Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 87147f6

Browse files
committedMay 25, 2024·
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

Lines changed: 19 additions & 58 deletions
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

Lines changed: 14 additions & 14 deletions
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

Lines changed: 1 addition & 1 deletion
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)
Please sign in to comment.