|
1 | 1 | use std::cmp;
|
2 |
| -use std::string::String; |
3 | 2 |
|
4 |
| -use crate::clean::{self, DocFragment, Item}; |
| 3 | +use crate::clean::{self, DocFragment, DocFragmentKind, Item}; |
5 | 4 | use crate::core::DocContext;
|
6 | 5 | use crate::fold::{self, DocFolder};
|
7 | 6 | use crate::passes::Pass;
|
@@ -35,65 +34,85 @@ impl clean::Attributes {
|
35 | 34 | }
|
36 | 35 |
|
37 | 36 | fn unindent_fragments(docs: &mut Vec<DocFragment>) {
|
38 |
| - for fragment in docs { |
39 |
| - fragment.doc = unindent(&fragment.doc); |
40 |
| - } |
41 |
| -} |
42 |
| - |
43 |
| -fn unindent(s: &str) -> String { |
44 |
| - let lines = s.lines().collect::<Vec<&str>>(); |
45 | 37 | let mut saw_first_line = false;
|
46 | 38 | let mut saw_second_line = false;
|
47 |
| - let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| { |
48 |
| - // After we see the first non-whitespace line, look at |
49 |
| - // the line we have. If it is not whitespace, and therefore |
50 |
| - // part of the first paragraph, then ignore the indentation |
51 |
| - // level of the first line |
52 |
| - let ignore_previous_indents = |
53 |
| - saw_first_line && !saw_second_line && !line.chars().all(|c| c.is_whitespace()); |
54 |
| - |
55 |
| - let min_indent = if ignore_previous_indents { usize::MAX } else { min_indent }; |
56 |
| - |
57 |
| - if saw_first_line { |
58 |
| - saw_second_line = true; |
59 |
| - } |
60 | 39 |
|
61 |
| - if line.chars().all(|c| c.is_whitespace()) { |
62 |
| - min_indent |
63 |
| - } else { |
64 |
| - saw_first_line = true; |
65 |
| - let mut whitespace = 0; |
66 |
| - line.chars().all(|char| { |
67 |
| - // Compare against either space or tab, ignoring whether they |
68 |
| - // are mixed or not |
69 |
| - if char == ' ' || char == '\t' { |
70 |
| - whitespace += 1; |
71 |
| - true |
| 40 | + let add = if !docs.windows(2).all(|arr| arr[0].kind == arr[1].kind) |
| 41 | + && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc) |
| 42 | + { |
| 43 | + // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to |
| 44 | + // "decide" how much the minimum indent will be. |
| 45 | + 1 |
| 46 | + } else { |
| 47 | + 0 |
| 48 | + }; |
| 49 | + |
| 50 | + let min_indent = match docs |
| 51 | + .iter() |
| 52 | + .map(|fragment| { |
| 53 | + fragment.doc.lines().fold(usize::MAX, |min_indent, line| { |
| 54 | + // After we see the first non-whitespace line, look at |
| 55 | + // the line we have. If it is not whitespace, and therefore |
| 56 | + // part of the first paragraph, then ignore the indentation |
| 57 | + // level of the first line |
| 58 | + let ignore_previous_indents = |
| 59 | + saw_first_line && !saw_second_line && !line.chars().all(|c| c.is_whitespace()); |
| 60 | + |
| 61 | + let min_indent = if ignore_previous_indents { usize::MAX } else { min_indent }; |
| 62 | + |
| 63 | + if saw_first_line { |
| 64 | + saw_second_line = true; |
| 65 | + } |
| 66 | + |
| 67 | + if line.chars().all(|c| c.is_whitespace()) { |
| 68 | + min_indent |
72 | 69 | } else {
|
73 |
| - false |
| 70 | + saw_first_line = true; |
| 71 | + // Compare against either space or tab, ignoring whether they are |
| 72 | + // mixed or not. |
| 73 | + let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count(); |
| 74 | + cmp::min(min_indent, whitespace) |
| 75 | + + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add } |
74 | 76 | }
|
75 |
| - }); |
76 |
| - cmp::min(min_indent, whitespace) |
| 77 | + }) |
| 78 | + }) |
| 79 | + .min() |
| 80 | + { |
| 81 | + Some(x) => x, |
| 82 | + None => return, |
| 83 | + }; |
| 84 | + |
| 85 | + let mut first_ignored = false; |
| 86 | + for fragment in docs { |
| 87 | + let lines: Vec<_> = fragment.doc.lines().collect(); |
| 88 | + |
| 89 | + if !lines.is_empty() { |
| 90 | + let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 { |
| 91 | + min_indent - add |
| 92 | + } else { |
| 93 | + min_indent |
| 94 | + }; |
| 95 | + |
| 96 | + let mut iter = lines.iter(); |
| 97 | + let mut result = if !first_ignored { |
| 98 | + first_ignored = true; |
| 99 | + vec![iter.next().unwrap().trim_start().to_string()] |
| 100 | + } else { |
| 101 | + Vec::new() |
| 102 | + }; |
| 103 | + result.extend_from_slice( |
| 104 | + &iter |
| 105 | + .map(|&line| { |
| 106 | + if line.chars().all(|c| c.is_whitespace()) { |
| 107 | + line.to_string() |
| 108 | + } else { |
| 109 | + assert!(line.len() >= min_indent); |
| 110 | + line[min_indent..].to_string() |
| 111 | + } |
| 112 | + }) |
| 113 | + .collect::<Vec<_>>(), |
| 114 | + ); |
| 115 | + fragment.doc = result.join("\n"); |
77 | 116 | }
|
78 |
| - }); |
79 |
| - |
80 |
| - if !lines.is_empty() { |
81 |
| - let mut unindented = vec![lines[0].trim_start().to_string()]; |
82 |
| - unindented.extend_from_slice( |
83 |
| - &lines[1..] |
84 |
| - .iter() |
85 |
| - .map(|&line| { |
86 |
| - if line.chars().all(|c| c.is_whitespace()) { |
87 |
| - line.to_string() |
88 |
| - } else { |
89 |
| - assert!(line.len() >= min_indent); |
90 |
| - line[min_indent..].to_string() |
91 |
| - } |
92 |
| - }) |
93 |
| - .collect::<Vec<_>>(), |
94 |
| - ); |
95 |
| - unindented.join("\n") |
96 |
| - } else { |
97 |
| - s.to_string() |
98 | 117 | }
|
99 | 118 | }
|
0 commit comments