Skip to content

Commit b779277

Browse files
committed
rustdoc: Add a pass to normalize indentation levels in doc comments
1 parent e869458 commit b779277

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

src/rustdoc/rustdoc.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ mod prune_undoc_pass;
2525
mod prune_unexported_pass;
2626
mod desc_to_brief_pass;
2727
mod desc_pass;
28+
mod unindent_pass;
2829
mod trim_pass;
2930
mod astsrv;
3031
mod demo;

src/rustdoc/rustdoc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ fn run(source_file: str) {
102102
prune_undoc_pass::mk_pass(),
103103
desc_to_brief_pass::mk_pass(),
104104
trim_pass::mk_pass(),
105+
unindent_pass::mk_pass(),
105106
markdown_pass::mk_pass {|| std::io:: stdout()}
106107
]);
107108
}

src/rustdoc/unindent_pass.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#[doc = "
2+
3+
Removes the common level of indention from description strings. For
4+
instance, if an entire doc comment is indented 8 spaces we want to
5+
remove those 8 spaces from every line.
6+
7+
The first line of a string is allowed to be intend less than
8+
subsequent lines in the same paragraph in order to account for
9+
instances where the string containing the doc comment is opened in the
10+
middle of a line, and each of the following lines is indented.
11+
12+
"];
13+
14+
export mk_pass;
15+
16+
fn mk_pass() -> pass {
17+
desc_pass::mk_pass(unindent)
18+
}
19+
20+
fn unindent(s: str) -> str {
21+
let lines = str::lines_any(s);
22+
let saw_first_line = false;
23+
let saw_second_line = false;
24+
let min_indent = vec::foldl(uint::max_value, lines) {|min_indent, line|
25+
26+
// After we see the first non-whitespace line, look at
27+
// the line we have. If it is not whitespace, and therefore
28+
// part of the first paragraph, then ignore the indentation
29+
// level of the first line
30+
let ignore_previous_indents =
31+
saw_first_line &&
32+
!saw_second_line &&
33+
!str::is_whitespace(line);
34+
35+
let min_indent = if ignore_previous_indents {
36+
uint::max_value
37+
} else {
38+
min_indent
39+
};
40+
41+
if saw_first_line {
42+
saw_second_line = true;
43+
}
44+
45+
if str::is_whitespace(line) {
46+
min_indent
47+
} else {
48+
saw_first_line = true;
49+
let spaces = 0u;
50+
str::loop_chars(line) {|char|
51+
// Only comparing against space because I wouldn't
52+
// know what to do with mixed whitespace chars
53+
if char == ' ' {
54+
spaces += 1u;
55+
true
56+
} else {
57+
false
58+
}
59+
};
60+
math::min(min_indent, spaces)
61+
}
62+
};
63+
64+
if check vec::is_not_empty(lines) {
65+
let unindented = [str::trim(vec::head(lines))]
66+
+ vec::map(vec::tail(lines)) {|line|
67+
if str::is_whitespace(line) {
68+
line
69+
} else {
70+
assert str::byte_len(line) >= min_indent;
71+
str::char_slice(line, min_indent, str::char_len(line))
72+
}
73+
};
74+
str::connect(unindented, "\n")
75+
} else {
76+
s
77+
}
78+
}
79+
80+
#[test]
81+
fn should_unindent() {
82+
let s = " line1\n line2";
83+
let r = unindent(s);
84+
assert r == "line1\nline2";
85+
}
86+
87+
#[test]
88+
fn should_unindent_multiple_paragraphs() {
89+
let s = " line1\n\n line2";
90+
let r = unindent(s);
91+
assert r == "line1\n\nline2";
92+
}
93+
94+
#[test]
95+
fn should_leave_multiple_indent_levels() {
96+
// Line 2 is indented another level beyond the
97+
// base indentation and should be preserved
98+
let s = " line1\n\n line2";
99+
let r = unindent(s);
100+
assert r == "line1\n\n line2";
101+
}
102+
103+
#[test]
104+
fn should_ignore_first_line_indent() {
105+
// Thi first line of the first paragraph may not be indented as
106+
// far due to the way the doc string was written:
107+
//
108+
// #[doc = "Start way over here
109+
// and continue here"]
110+
let s = "line1\n line2";
111+
let r = unindent(s);
112+
assert r == "line1\nline2";
113+
}
114+
115+
#[test]
116+
fn should_not_ignore_first_line_indent_in_a_single_line_para() {
117+
let s = "line1\n\n line2";
118+
let r = unindent(s);
119+
assert r == "line1\n\n line2";
120+
}

0 commit comments

Comments
 (0)