Skip to content

Commit

Permalink
Fix unindent behavior between different doc comments
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez committed Oct 26, 2020
1 parent 07a63e6 commit 06fe278
Showing 1 changed file with 75 additions and 56 deletions.
131 changes: 75 additions & 56 deletions src/librustdoc/passes/unindent_comments.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::cmp;
use std::string::String;

use crate::clean::{self, DocFragment, Item};
use crate::clean::{self, DocFragment, DocFragmentKind, Item};
use crate::core::DocContext;
use crate::fold::{self, DocFolder};
use crate::passes::Pass;
Expand Down Expand Up @@ -35,65 +34,85 @@ impl clean::Attributes {
}

fn unindent_fragments(docs: &mut Vec<DocFragment>) {
for fragment in docs {
fragment.doc = unindent(&fragment.doc);
}
}

fn unindent(s: &str) -> String {
let lines = s.lines().collect::<Vec<&str>>();
let mut saw_first_line = false;
let mut saw_second_line = false;
let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| {
// After we see the first non-whitespace line, look at
// the line we have. If it is not whitespace, and therefore
// part of the first paragraph, then ignore the indentation
// level of the first line
let ignore_previous_indents =
saw_first_line && !saw_second_line && !line.chars().all(|c| c.is_whitespace());

let min_indent = if ignore_previous_indents { usize::MAX } else { min_indent };

if saw_first_line {
saw_second_line = true;
}

if line.chars().all(|c| c.is_whitespace()) {
min_indent
} else {
saw_first_line = true;
let mut whitespace = 0;
line.chars().all(|char| {
// Compare against either space or tab, ignoring whether they
// are mixed or not
if char == ' ' || char == '\t' {
whitespace += 1;
true
let add = if !docs.windows(2).all(|arr| arr[0].kind == arr[1].kind)
&& docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
{
// In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
// "decide" how much the minimum indent will be.
1
} else {
0
};

let min_indent = match docs
.iter()
.map(|fragment| {
fragment.doc.lines().fold(usize::MAX, |min_indent, line| {
// After we see the first non-whitespace line, look at
// the line we have. If it is not whitespace, and therefore
// part of the first paragraph, then ignore the indentation
// level of the first line
let ignore_previous_indents =
saw_first_line && !saw_second_line && !line.chars().all(|c| c.is_whitespace());

let min_indent = if ignore_previous_indents { usize::MAX } else { min_indent };

if saw_first_line {
saw_second_line = true;
}

if line.chars().all(|c| c.is_whitespace()) {
min_indent
} else {
false
saw_first_line = true;
// Compare against either space or tab, ignoring whether they are
// mixed or not.
let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
cmp::min(min_indent, whitespace)
+ if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
}
});
cmp::min(min_indent, whitespace)
})
})
.min()
{
Some(x) => x,
None => return,
};

let mut first_ignored = false;
for fragment in docs {
let lines: Vec<_> = fragment.doc.lines().collect();

if !lines.is_empty() {
let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
min_indent - add
} else {
min_indent
};

let mut iter = lines.iter();
let mut result = if !first_ignored {
first_ignored = true;
vec![iter.next().unwrap().trim_start().to_string()]
} else {
Vec::new()
};
result.extend_from_slice(
&iter
.map(|&line| {
if line.chars().all(|c| c.is_whitespace()) {
line.to_string()
} else {
assert!(line.len() >= min_indent);
line[min_indent..].to_string()
}
})
.collect::<Vec<_>>(),
);
fragment.doc = result.join("\n");
}
});

if !lines.is_empty() {
let mut unindented = vec![lines[0].trim_start().to_string()];
unindented.extend_from_slice(
&lines[1..]
.iter()
.map(|&line| {
if line.chars().all(|c| c.is_whitespace()) {
line.to_string()
} else {
assert!(line.len() >= min_indent);
line[min_indent..].to_string()
}
})
.collect::<Vec<_>>(),
);
unindented.join("\n")
} else {
s.to_string()
}
}

0 comments on commit 06fe278

Please sign in to comment.