From 58c7505d868515eb55971cf1ad8744c81d5ea7d2 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 23 Sep 2025 00:34:05 +0300 Subject: [PATCH 1/3] Make `render_example_with_highlighting` return an `impl fmt::Display` --- src/librustdoc/html/highlight.rs | 116 ++++++++++++++----------------- src/librustdoc/html/markdown.rs | 17 +++-- 2 files changed, 62 insertions(+), 71 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 0e06361024b9f..3ddfb3470f2f1 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -8,6 +8,7 @@ use std::borrow::Cow; use std::collections::VecDeque; use std::fmt::{self, Display, Write}; +use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind}; @@ -15,8 +16,9 @@ use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, DUMMY_SP, Span}; -use super::format::{self, write_str}; +use super::format; use crate::clean::PrimitiveType; +use crate::display::Joined as _; use crate::html::escape::EscapeBodyText; use crate::html::macro_expansion::ExpandedCode; use crate::html::render::{Context, LinkFromSrc}; @@ -51,26 +53,26 @@ pub(crate) enum Tooltip { /// Highlights `src` as an inline example, returning the HTML output. pub(crate) fn render_example_with_highlighting( src: &str, - out: &mut String, - tooltip: Tooltip, + tooltip: &Tooltip, playground_button: Option<&str>, extra_classes: &[String], -) { - write_header(out, "rust-example-rendered", None, tooltip, extra_classes); - write_code(out, src, None, None, None); - write_footer(out, playground_button); +) -> impl Display { + fmt::from_fn(move |f| { + write_header("rust-example-rendered", None, tooltip, extra_classes).fmt(f)?; + write_code(f, src, None, None, None); + write_footer(playground_button).fmt(f) + }) } fn write_header( - out: &mut String, class: &str, extra_content: Option<&str>, - tooltip: Tooltip, + tooltip: &Tooltip, extra_classes: &[String], -) { - write_str( - out, - format_args!( +) -> impl Display { + fmt::from_fn(move |f| { + write!( + f, "
", match tooltip { Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore", @@ -79,58 +81,48 @@ fn write_header( Tooltip::Edition(_) => " edition", Tooltip::None => "", } - ), - ); - - if tooltip != Tooltip::None { - let tooltip = fmt::from_fn(|f| match &tooltip { - Tooltip::IgnoreAll => f.write_str("This example is not tested"), - Tooltip::IgnoreSome(platforms) => { - f.write_str("This example is not tested on ")?; - match &platforms[..] { - [] => unreachable!(), - [platform] => f.write_str(platform)?, - [first, second] => write!(f, "{first} or {second}")?, - [platforms @ .., last] => { - for platform in platforms { - write!(f, "{platform}, ")?; + )?; + + if *tooltip != Tooltip::None { + let tooltip = fmt::from_fn(|f| match tooltip { + Tooltip::IgnoreAll => f.write_str("This example is not tested"), + Tooltip::IgnoreSome(platforms) => { + f.write_str("This example is not tested on ")?; + match &platforms[..] { + [] => unreachable!(), + [platform] => f.write_str(platform)?, + [first, second] => write!(f, "{first} or {second}")?, + [platforms @ .., last] => { + for platform in platforms { + write!(f, "{platform}, ")?; + } + write!(f, "or {last}")?; } - write!(f, "or {last}")?; } + Ok(()) } - Ok(()) - } - Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"), - Tooltip::ShouldPanic => f.write_str("This example panics"), - Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"), - Tooltip::None => unreachable!(), + Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"), + Tooltip::ShouldPanic => f.write_str("This example panics"), + Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"), + Tooltip::None => unreachable!(), + }); + + write!(f, "")?; + } + + if let Some(extra) = extra_content { + f.write_str(extra)?; + } + + let classes = fmt::from_fn(|f| { + iter::once("rust") + .chain(Some(class).filter(|class| !class.is_empty())) + .chain(extra_classes.iter().map(String::as_str)) + .joined(" ", f) }); - write_str(out, format_args!("")); - } - if let Some(extra) = extra_content { - out.push_str(extra); - } - if class.is_empty() { - write_str( - out, - format_args!( - "
",
-                if extra_classes.is_empty() { "" } else { " " },
-                extra_classes.join(" ")
-            ),
-        );
-    } else {
-        write_str(
-            out,
-            format_args!(
-                "
",
-                if extra_classes.is_empty() { "" } else { " " },
-                extra_classes.join(" ")
-            ),
-        );
-    }
-    write_str(out, format_args!(""));
+        write!(f, "
")
+    })
 }
 
 /// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
@@ -577,8 +569,8 @@ pub(super) fn write_code(
     });
 }
 
-fn write_footer(out: &mut String, playground_button: Option<&str>) {
-    write_str(out, format_args!("
{}
", playground_button.unwrap_or_default())); +fn write_footer(playground_button: Option<&str>) -> impl Display { + fmt::from_fn(move |f| write!(f, "{}", playground_button.unwrap_or_default())) } /// How a span of text is classified. Mostly corresponds to token kinds. diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4addf2c3c9644..46923d1f69826 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -337,15 +337,14 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { // insert newline to clearly separate it from the // previous block so we can shorten the html output - let mut s = String::new(); - s.push('\n'); - - highlight::render_example_with_highlighting( - &text, - &mut s, - tooltip, - playground_button.as_deref(), - &added_classes, + let s = format!( + "\n{}", + highlight::render_example_with_highlighting( + &text, + &tooltip, + playground_button.as_deref(), + &added_classes, + ) ); Some(Event::Html(s.into())) } From aaff372f4b45f88dc3b28fe3c1c8ec22cb3b3411 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 23 Sep 2025 01:04:04 +0300 Subject: [PATCH 2/3] Remove `Tooltip::None` variant, use `Option::None` --- src/librustdoc/html/highlight.rs | 23 +++++++++++------------ src/librustdoc/html/markdown.rs | 30 +++++++++++++++++------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 3ddfb3470f2f1..b1257999c070c 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -47,13 +47,12 @@ pub(crate) enum Tooltip { CompileFail, ShouldPanic, Edition(Edition), - None, } /// Highlights `src` as an inline example, returning the HTML output. pub(crate) fn render_example_with_highlighting( src: &str, - tooltip: &Tooltip, + tooltip: Option<&Tooltip>, playground_button: Option<&str>, extra_classes: &[String], ) -> impl Display { @@ -67,23 +66,24 @@ pub(crate) fn render_example_with_highlighting( fn write_header( class: &str, extra_content: Option<&str>, - tooltip: &Tooltip, + tooltip: Option<&Tooltip>, extra_classes: &[String], ) -> impl Display { fmt::from_fn(move |f| { write!( f, "
", - match tooltip { - Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore", - Tooltip::CompileFail => " compile_fail", - Tooltip::ShouldPanic => " should_panic", - Tooltip::Edition(_) => " edition", - Tooltip::None => "", - } + tooltip + .map(|tooltip| match tooltip { + Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore", + Tooltip::CompileFail => " compile_fail", + Tooltip::ShouldPanic => " should_panic", + Tooltip::Edition(_) => " edition", + }) + .unwrap_or_default() )?; - if *tooltip != Tooltip::None { + if let Some(tooltip) = tooltip { let tooltip = fmt::from_fn(|f| match tooltip { Tooltip::IgnoreAll => f.write_str("This example is not tested"), Tooltip::IgnoreSome(platforms) => { @@ -104,7 +104,6 @@ fn write_header( Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"), Tooltip::ShouldPanic => f.write_str("This example panics"), Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"), - Tooltip::None => unreachable!(), }); write!(f, "")?; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 46923d1f69826..7065de14c8ea7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -321,18 +321,22 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { )) }); - let tooltip = if ignore == Ignore::All { - highlight::Tooltip::IgnoreAll - } else if let Ignore::Some(platforms) = ignore { - highlight::Tooltip::IgnoreSome(platforms) - } else if compile_fail { - highlight::Tooltip::CompileFail - } else if should_panic { - highlight::Tooltip::ShouldPanic - } else if explicit_edition { - highlight::Tooltip::Edition(edition) - } else { - highlight::Tooltip::None + let tooltip = { + use highlight::Tooltip::*; + + if ignore == Ignore::All { + Some(IgnoreAll) + } else if let Ignore::Some(platforms) = ignore { + Some(IgnoreSome(platforms)) + } else if compile_fail { + Some(CompileFail) + } else if should_panic { + Some(ShouldPanic) + } else if explicit_edition { + Some(Edition(edition)) + } else { + None + } }; // insert newline to clearly separate it from the @@ -341,7 +345,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { "\n{}", highlight::render_example_with_highlighting( &text, - &tooltip, + tooltip.as_ref(), playground_button.as_deref(), &added_classes, ) From e697f206fe4eba49f8984ef2d436bc0cd19ff8fc Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 23 Sep 2025 01:04:14 +0300 Subject: [PATCH 3/3] Remove unused param from `write_header` --- src/librustdoc/html/highlight.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index b1257999c070c..fe2b2fc603120 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -57,18 +57,13 @@ pub(crate) fn render_example_with_highlighting( extra_classes: &[String], ) -> impl Display { fmt::from_fn(move |f| { - write_header("rust-example-rendered", None, tooltip, extra_classes).fmt(f)?; + write_header("rust-example-rendered", tooltip, extra_classes).fmt(f)?; write_code(f, src, None, None, None); write_footer(playground_button).fmt(f) }) } -fn write_header( - class: &str, - extra_content: Option<&str>, - tooltip: Option<&Tooltip>, - extra_classes: &[String], -) -> impl Display { +fn write_header(class: &str, tooltip: Option<&Tooltip>, extra_classes: &[String]) -> impl Display { fmt::from_fn(move |f| { write!( f, @@ -109,10 +104,6 @@ fn write_header( write!(f, "")?; } - if let Some(extra) = extra_content { - f.write_str(extra)?; - } - let classes = fmt::from_fn(|f| { iter::once("rust") .chain(Some(class).filter(|class| !class.is_empty()))