|
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