Skip to content

Commit afaa406

Browse files
committed
Auto merge of #51803 - lucasem:rustdoc-code-hash-escape, r=GuillaumeGomez
rustdoc codeblock hash escape So that docstring text such as the following (in a code block) can be created ergonomically: ```rust let s = " foo # bar baz "; ``` Such code in a docstring hide the <code>&nbsp;&nbsp;&nbsp;&nbsp;# bar</code> line. Previously, using two consecutive hashes <code>&nbsp;&nbsp;&nbsp;&nbsp;## bar</code> would turn the line into _shown_ `# bar`, losing the leading whitespace. A line of code like <code>&nbsp;&nbsp;&nbsp;&nbsp;# bar</code> (such as in the example above) **could not be represented** in the docstring text. This commit makes the two consecutive hashes not also trim the leading whitespace — the two hashes simply **escape** into a single hash and do not hide the line, leaving the rest of that line unaffected. The new docstring text to achieve the above code block is: ```rust /// ``` /// let s = " /// foo /// ## bar /// baz /// "; /// ``` ```
2 parents 4af9132 + ff2ff2b commit afaa406

File tree

2 files changed

+27
-10
lines changed

2 files changed

+27
-10
lines changed

src/doc/rustdoc/src/documentation-tests.md

+17
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,23 @@ By repeating all parts of the example, you can ensure that your example still
170170
compiles, while only showing the parts that are relevant to that part of your
171171
explanation.
172172
173+
The `#`-hiding of lines can be prevented by using two consecutive hashes
174+
`##`. This only needs to be done with with the first `#` which would've
175+
otherwise caused hiding. If we have a string literal like the following,
176+
which has a line that starts with a `#`:
177+
178+
```rust
179+
let s = "foo
180+
## bar # baz";
181+
```
182+
183+
We can document it by escaping the initial `#`:
184+
185+
```text
186+
/// let s = "foo
187+
/// ## bar # baz";
188+
```
189+
173190

174191
## Using `?` in doc tests
175192

src/librustdoc/html/markdown.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,21 @@ pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]);
6464
/// All lines are used in documentation tests.
6565
enum Line<'a> {
6666
Hidden(&'a str),
67-
Shown(&'a str),
67+
Shown(Cow<'a, str>),
6868
}
6969

7070
impl<'a> Line<'a> {
71-
fn for_html(self) -> Option<&'a str> {
71+
fn for_html(self) -> Option<Cow<'a, str>> {
7272
match self {
7373
Line::Shown(l) => Some(l),
7474
Line::Hidden(_) => None,
7575
}
7676
}
7777

78-
fn for_code(self) -> &'a str {
78+
fn for_code(self) -> Cow<'a, str> {
7979
match self {
80-
Line::Shown(l) |
81-
Line::Hidden(l) => l,
80+
Line::Shown(l) => l,
81+
Line::Hidden(l) => Cow::Borrowed(l),
8282
}
8383
}
8484
}
@@ -91,15 +91,15 @@ impl<'a> Line<'a> {
9191
fn map_line(s: &str) -> Line {
9292
let trimmed = s.trim();
9393
if trimmed.starts_with("##") {
94-
Line::Shown(&trimmed[1..])
94+
Line::Shown(Cow::Owned(s.replacen("##", "#", 1)))
9595
} else if trimmed.starts_with("# ") {
9696
// # text
9797
Line::Hidden(&trimmed[2..])
9898
} else if trimmed == "#" {
9999
// We cannot handle '#text' because it could be #[attr].
100100
Line::Hidden("")
101101
} else {
102-
Line::Shown(s)
102+
Line::Shown(Cow::Borrowed(s))
103103
}
104104
}
105105

@@ -168,7 +168,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
168168
}
169169
}
170170
let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
171-
let text = lines.collect::<Vec<&str>>().join("\n");
171+
let text = lines.collect::<Vec<Cow<str>>>().join("\n");
172172
PLAYGROUND.with(|play| {
173173
// insert newline to clearly separate it from the
174174
// previous block so we can shorten the html output
@@ -179,7 +179,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
179179
}
180180
let test = origtext.lines()
181181
.map(|l| map_line(l).for_code())
182-
.collect::<Vec<&str>>().join("\n");
182+
.collect::<Vec<Cow<str>>>().join("\n");
183183
let krate = krate.as_ref().map(|s| &**s);
184184
let (test, _) = test::make_test(&test, krate, false,
185185
&Default::default());
@@ -477,7 +477,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Sp
477477
}
478478
if let Some(offset) = offset {
479479
let lines = test_s.lines().map(|l| map_line(l).for_code());
480-
let text = lines.collect::<Vec<&str>>().join("\n");
480+
let text = lines.collect::<Vec<Cow<str>>>().join("\n");
481481
nb_lines += doc[prev_offset..offset].lines().count();
482482
let line = tests.get_line() + (nb_lines - 1);
483483
let filename = tests.get_filename();

0 commit comments

Comments
 (0)