Skip to content

Commit 87147f6

Browse files
committed
Simplify logic for unindenting doc comments
This has almost the same behavior, except that it completely ignores raw doc comments (i.e., `#[doc = "..."]`) for the purposes of computing indentation.
1 parent 72d8d8d commit 87147f6

File tree

3 files changed

+34
-73
lines changed

3 files changed

+34
-73
lines changed

compiler/rustc_resolve/src/rustdoc.rs

+19-58
Original file line numberDiff line numberDiff line change
@@ -84,84 +84,44 @@ pub enum MalformedGenerics {
8484

8585
/// Removes excess indentation on comments in order for the Markdown
8686
/// to be parsed correctly. This is necessary because the convention for
87-
/// writing documentation is to provide a space between the /// or //! marker
87+
/// writing documentation is to provide a space between the `///` or `//!` marker
8888
/// and the doc text, but Markdown is whitespace-sensitive. For example,
8989
/// a block of text with four-space indentation is parsed as a code block,
9090
/// so if we didn't unindent comments, these list items
9191
///
92+
/// ```
9293
/// /// A list:
9394
/// ///
9495
/// /// - Foo
9596
/// /// - Bar
97+
/// # fn foo() {}
98+
/// ```
9699
///
97100
/// would be parsed as if they were in a code block, which is likely not what the user intended.
98101
pub fn unindent_doc_fragments(docs: &mut [DocFragment]) {
99-
// `add` is used in case the most common sugared doc syntax is used ("/// "). The other
100-
// fragments kind's lines are never starting with a whitespace unless they are using some
101-
// markdown formatting requiring it. Therefore, if the doc block have a mix between the two,
102-
// we need to take into account the fact that the minimum indent minus one (to take this
103-
// whitespace into account).
104-
//
105-
// For example:
106-
//
107-
// /// hello!
108-
// #[doc = "another"]
109-
//
110-
// In this case, you want "hello! another" and not "hello! another".
111-
let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind)
112-
&& docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
113-
{
114-
// In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
115-
// "decide" how much the minimum indent will be.
116-
1
117-
} else {
118-
0
119-
};
120-
121-
// `min_indent` is used to know how much whitespaces from the start of each lines must be
122-
// removed. Example:
123-
//
124-
// /// hello!
125-
// #[doc = "another"]
126-
//
127-
// In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
128-
// 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
129-
// (5 - 1) whitespaces.
130-
let Some(min_indent) = docs
102+
// Only sugared docs have the concept of indentation.
103+
// We assume the docs overall are indented by the amount that the least-indented line is indented.
104+
// Raw docs are taken literally.
105+
let min_indent = docs
131106
.iter()
132-
.map(|fragment| {
133-
fragment
134-
.doc
135-
.as_str()
136-
.lines()
137-
.filter(|line| line.chars().any(|c| !c.is_whitespace()))
138-
.map(|line| {
139-
// Compare against either space or tab, ignoring whether they are
140-
// mixed or not.
141-
let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
142-
whitespace
143-
+ (if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add })
144-
})
145-
.min()
146-
.unwrap_or(usize::MAX)
147-
})
107+
.filter(|frag| frag.kind == DocFragmentKind::SugaredDoc)
108+
.flat_map(|frag| frag.doc.as_str().lines())
109+
.filter(|line| line.chars().any(|c| !c.is_whitespace()))
110+
// FIXME: we should be more careful when spaces and tabs are mixed
111+
.map(|line| line.chars().take_while(|c| *c == ' ' || *c == '\t').count())
148112
.min()
149-
else {
150-
return;
151-
};
113+
.unwrap_or(0);
152114

153115
for fragment in docs {
154116
if fragment.doc == kw::Empty {
155117
continue;
156118
}
157119

158-
let indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
159-
min_indent - add
160-
} else {
161-
min_indent
120+
fragment.indent = match fragment.kind {
121+
// Raw docs are taken literally.
122+
DocFragmentKind::RawDoc => 0,
123+
DocFragmentKind::SugaredDoc => min_indent,
162124
};
163-
164-
fragment.indent = indent;
165125
}
166126
}
167127

@@ -171,6 +131,7 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) {
171131
///
172132
/// Note: remove the trailing newline where appropriate
173133
pub fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
134+
debug!("add_doc_fragment: {:?}", frag);
174135
if frag.doc == kw::Empty {
175136
out.push('\n');
176137
return;

tests/rustdoc-ui/unescaped_backticks.stderr

+14-14
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,11 @@ LL | | /// level changes.
280280
| |______________________^
281281
|
282282
= help: the opening backtick of a previous inline code may be missing
283-
change: The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
284-
to this: The `Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
283+
change: The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
284+
to this: The `Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
285285
= help: if you meant to use a literal backtick, escape it
286-
change: `None`. Otherwise, it will return `Some(Dispatch)`.
287-
to this: `None`. Otherwise, it will return `Some(Dispatch)\`.
286+
change: `None`. Otherwise, it will return `Some(Dispatch)`.
287+
to this: `None`. Otherwise, it will return `Some(Dispatch)\`.
288288

289289
error: unescaped backtick
290290
--> $DIR/unescaped_backticks.rs:323:5
@@ -300,8 +300,8 @@ LL | | /// level changes.
300300
|
301301
= help: the opening or closing backtick of an inline code may be missing
302302
= help: if you meant to use a literal backtick, escape it
303-
change: or `None` if it isn't.
304-
to this: or `None\` if it isn't.
303+
change: or `None` if it isn't.
304+
to this: or `None\` if it isn't.
305305

306306
error: unescaped backtick
307307
--> $DIR/unescaped_backticks.rs:323:5
@@ -316,11 +316,11 @@ LL | | /// level changes.
316316
| |______________________^
317317
|
318318
= help: a previous inline code might be longer than expected
319-
change: Called before the filtered [`Layer]'s [`on_event`], to determine if
320-
to this: Called before the filtered [`Layer`]'s [`on_event`], to determine if
319+
change: Called before the filtered [`Layer]'s [`on_event`], to determine if
320+
to this: Called before the filtered [`Layer`]'s [`on_event`], to determine if
321321
= help: if you meant to use a literal backtick, escape it
322-
change: `on_event` should be called.
323-
to this: `on_event\` should be called.
322+
change: `on_event` should be called.
323+
to this: `on_event\` should be called.
324324

325325
error: unescaped backtick
326326
--> $DIR/unescaped_backticks.rs:323:5
@@ -335,11 +335,11 @@ LL | | /// level changes.
335335
| |______________________^
336336
|
337337
= help: a previous inline code might be longer than expected
338-
change: Therefore, if the `Filter will change the value returned by this
339-
to this: Therefore, if the `Filter` will change the value returned by this
338+
change: Therefore, if the `Filter will change the value returned by this
339+
to this: Therefore, if the `Filter` will change the value returned by this
340340
= help: if you meant to use a literal backtick, escape it
341-
change: [`rebuild_interest_cache`][rebuild] is called after the value of the max
342-
to this: [`rebuild_interest_cache\`][rebuild] is called after the value of the max
341+
change: [`rebuild_interest_cache`][rebuild] is called after the value of the max
342+
to this: [`rebuild_interest_cache\`][rebuild] is called after the value of the max
343343

344344
error: unescaped backtick
345345
--> $DIR/unescaped_backticks.rs:349:56

tests/rustdoc/unindent.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub struct G;
4040
pub struct H;
4141

4242
// @has foo/struct.I.html
43-
// @matches - '//pre[@class="rust rust-example-rendered"]' '(?m)4 whitespaces!\Z'
43+
// @has - '//div[@class="docblock"]/p' '4 whitespaces! something'
4444
/// 4 whitespaces!
4545
#[doc = "something"]
4646
pub struct I;

0 commit comments

Comments
 (0)