Skip to content

Commit 32de303

Browse files
Auto merge of #146933 - yotamofek:pr/rustdoc/highlight_no_write_str, r=<try>
Make `render_example_with_highlighting` return an `impl fmt::Display`
2 parents bbcbc78 + e697f20 commit 32de303

File tree

2 files changed

+80
-95
lines changed

2 files changed

+80
-95
lines changed

src/librustdoc/html/highlight.rs

Lines changed: 56 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@
88
use std::borrow::Cow;
99
use std::collections::VecDeque;
1010
use std::fmt::{self, Display, Write};
11+
use std::iter;
1112

1213
use rustc_data_structures::fx::FxIndexMap;
1314
use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
1415
use rustc_span::edition::Edition;
1516
use rustc_span::symbol::Symbol;
1617
use rustc_span::{BytePos, DUMMY_SP, Span};
1718

18-
use super::format::{self, write_str};
19+
use super::format;
1920
use crate::clean::PrimitiveType;
21+
use crate::display::Joined as _;
2022
use crate::html::escape::EscapeBodyText;
2123
use crate::html::macro_expansion::ExpandedCode;
2224
use crate::html::render::{Context, LinkFromSrc};
@@ -45,92 +47,72 @@ pub(crate) enum Tooltip {
4547
CompileFail,
4648
ShouldPanic,
4749
Edition(Edition),
48-
None,
4950
}
5051

5152
/// Highlights `src` as an inline example, returning the HTML output.
5253
pub(crate) fn render_example_with_highlighting(
5354
src: &str,
54-
out: &mut String,
55-
tooltip: Tooltip,
55+
tooltip: Option<&Tooltip>,
5656
playground_button: Option<&str>,
5757
extra_classes: &[String],
58-
) {
59-
write_header(out, "rust-example-rendered", None, tooltip, extra_classes);
60-
write_code(out, src, None, None, None);
61-
write_footer(out, playground_button);
58+
) -> impl Display {
59+
fmt::from_fn(move |f| {
60+
write_header("rust-example-rendered", tooltip, extra_classes).fmt(f)?;
61+
write_code(f, src, None, None, None);
62+
write_footer(playground_button).fmt(f)
63+
})
6264
}
6365

64-
fn write_header(
65-
out: &mut String,
66-
class: &str,
67-
extra_content: Option<&str>,
68-
tooltip: Tooltip,
69-
extra_classes: &[String],
70-
) {
71-
write_str(
72-
out,
73-
format_args!(
66+
fn write_header(class: &str, tooltip: Option<&Tooltip>, extra_classes: &[String]) -> impl Display {
67+
fmt::from_fn(move |f| {
68+
write!(
69+
f,
7470
"<div class=\"example-wrap{}\">",
75-
match tooltip {
76-
Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore",
77-
Tooltip::CompileFail => " compile_fail",
78-
Tooltip::ShouldPanic => " should_panic",
79-
Tooltip::Edition(_) => " edition",
80-
Tooltip::None => "",
81-
}
82-
),
83-
);
84-
85-
if tooltip != Tooltip::None {
86-
let tooltip = fmt::from_fn(|f| match &tooltip {
87-
Tooltip::IgnoreAll => f.write_str("This example is not tested"),
88-
Tooltip::IgnoreSome(platforms) => {
89-
f.write_str("This example is not tested on ")?;
90-
match &platforms[..] {
91-
[] => unreachable!(),
92-
[platform] => f.write_str(platform)?,
93-
[first, second] => write!(f, "{first} or {second}")?,
94-
[platforms @ .., last] => {
95-
for platform in platforms {
96-
write!(f, "{platform}, ")?;
71+
tooltip
72+
.map(|tooltip| match tooltip {
73+
Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore",
74+
Tooltip::CompileFail => " compile_fail",
75+
Tooltip::ShouldPanic => " should_panic",
76+
Tooltip::Edition(_) => " edition",
77+
})
78+
.unwrap_or_default()
79+
)?;
80+
81+
if let Some(tooltip) = tooltip {
82+
let tooltip = fmt::from_fn(|f| match tooltip {
83+
Tooltip::IgnoreAll => f.write_str("This example is not tested"),
84+
Tooltip::IgnoreSome(platforms) => {
85+
f.write_str("This example is not tested on ")?;
86+
match &platforms[..] {
87+
[] => unreachable!(),
88+
[platform] => f.write_str(platform)?,
89+
[first, second] => write!(f, "{first} or {second}")?,
90+
[platforms @ .., last] => {
91+
for platform in platforms {
92+
write!(f, "{platform}, ")?;
93+
}
94+
write!(f, "or {last}")?;
9795
}
98-
write!(f, "or {last}")?;
9996
}
97+
Ok(())
10098
}
101-
Ok(())
102-
}
103-
Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"),
104-
Tooltip::ShouldPanic => f.write_str("This example panics"),
105-
Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"),
106-
Tooltip::None => unreachable!(),
99+
Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"),
100+
Tooltip::ShouldPanic => f.write_str("This example panics"),
101+
Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"),
102+
});
103+
104+
write!(f, "<a href=\"#\" class=\"tooltip\" title=\"{tooltip}\">ⓘ</a>")?;
105+
}
106+
107+
let classes = fmt::from_fn(|f| {
108+
iter::once("rust")
109+
.chain(Some(class).filter(|class| !class.is_empty()))
110+
.chain(extra_classes.iter().map(String::as_str))
111+
.joined(" ", f)
107112
});
108-
write_str(out, format_args!("<a href=\"#\" class=\"tooltip\" title=\"{tooltip}\">ⓘ</a>"));
109-
}
110113

111-
if let Some(extra) = extra_content {
112-
out.push_str(extra);
113-
}
114-
if class.is_empty() {
115-
write_str(
116-
out,
117-
format_args!(
118-
"<pre class=\"rust{}{}\">",
119-
if extra_classes.is_empty() { "" } else { " " },
120-
extra_classes.join(" ")
121-
),
122-
);
123-
} else {
124-
write_str(
125-
out,
126-
format_args!(
127-
"<pre class=\"rust {class}{}{}\">",
128-
if extra_classes.is_empty() { "" } else { " " },
129-
extra_classes.join(" ")
130-
),
131-
);
132-
}
133-
write_str(out, format_args!("<code>"));
114+
write!(f, "<pre class=\"{classes}\"><code>")
115+
})
134116
}
135117

136118
/// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
@@ -577,8 +559,8 @@ pub(super) fn write_code(
577559
});
578560
}
579561

580-
fn write_footer(out: &mut String, playground_button: Option<&str>) {
581-
write_str(out, format_args!("</code></pre>{}</div>", playground_button.unwrap_or_default()));
562+
fn write_footer(playground_button: Option<&str>) -> impl Display {
563+
fmt::from_fn(move |f| write!(f, "</code></pre>{}</div>", playground_button.unwrap_or_default()))
582564
}
583565

584566
/// How a span of text is classified. Mostly corresponds to token kinds.

src/librustdoc/html/markdown.rs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -321,31 +321,34 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
321321
))
322322
});
323323

324-
let tooltip = if ignore == Ignore::All {
325-
highlight::Tooltip::IgnoreAll
326-
} else if let Ignore::Some(platforms) = ignore {
327-
highlight::Tooltip::IgnoreSome(platforms)
328-
} else if compile_fail {
329-
highlight::Tooltip::CompileFail
330-
} else if should_panic {
331-
highlight::Tooltip::ShouldPanic
332-
} else if explicit_edition {
333-
highlight::Tooltip::Edition(edition)
334-
} else {
335-
highlight::Tooltip::None
324+
let tooltip = {
325+
use highlight::Tooltip::*;
326+
327+
if ignore == Ignore::All {
328+
Some(IgnoreAll)
329+
} else if let Ignore::Some(platforms) = ignore {
330+
Some(IgnoreSome(platforms))
331+
} else if compile_fail {
332+
Some(CompileFail)
333+
} else if should_panic {
334+
Some(ShouldPanic)
335+
} else if explicit_edition {
336+
Some(Edition(edition))
337+
} else {
338+
None
339+
}
336340
};
337341

338342
// insert newline to clearly separate it from the
339343
// previous block so we can shorten the html output
340-
let mut s = String::new();
341-
s.push('\n');
342-
343-
highlight::render_example_with_highlighting(
344-
&text,
345-
&mut s,
346-
tooltip,
347-
playground_button.as_deref(),
348-
&added_classes,
344+
let s = format!(
345+
"\n{}",
346+
highlight::render_example_with_highlighting(
347+
&text,
348+
tooltip.as_ref(),
349+
playground_button.as_deref(),
350+
&added_classes,
351+
)
349352
);
350353
Some(Event::Html(s.into()))
351354
}

0 commit comments

Comments
 (0)