diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 0e06361024b9f..fe2b2fc603120 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}; @@ -45,92 +47,72 @@ 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, - out: &mut String, - tooltip: Tooltip, + tooltip: Option<&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", 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, - extra_classes: &[String], -) { - write_str( - out, - format_args!( +fn write_header(class: &str, 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 => "", - } - ), - ); - - 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}, ")?; + 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 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) => { + 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}"), + }); + + write!(f, "")?; + } + + 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 +559,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..7065de14c8ea7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -321,31 +321,34 @@ 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 // 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.as_ref(), + playground_button.as_deref(), + &added_classes, + ) ); Some(Event::Html(s.into())) }