diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index ece3ee640e2a6..15a4f4b10ad6f 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -9,8 +9,9 @@ use crate::clean::PrimitiveType;
use crate::html::escape::Escape;
use crate::html::render::Context;
-use std::fmt::{Display, Write};
-use std::iter::Peekable;
+use std::borrow::Cow;
+use std::fmt::{Debug, Display, Write};
+use std::iter::{once, Peekable};
use rustc_lexer::{LiteralKind, TokenKind};
use rustc_span::edition::Edition;
@@ -18,6 +19,7 @@ use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, Span, DUMMY_SP};
use super::format::{self, Buffer};
+use super::markdown::Line;
use super::render::LinkFromSrc;
/// This type is needed in case we want to render links on items to allow to go to their definition.
@@ -31,7 +33,7 @@ crate struct ContextInfo<'a, 'b, 'c> {
}
/// Highlights `src`, returning the HTML output.
-crate fn render_with_highlighting(
+crate fn render_source_with_highlighting(
src: &str,
out: &mut Buffer,
class: Option<&str>,
@@ -41,7 +43,31 @@ crate fn render_with_highlighting(
extra_content: Option,
context_info: Option>,
) {
- debug!("highlighting: ================\n{}\n==============", src);
+ render_with_highlighting(
+ once(Line::Shown(Cow::Borrowed(src))),
+ out,
+ class,
+ playground_button,
+ tooltip,
+ edition,
+ extra_content,
+ context_info,
+ )
+}
+
+/// Highlights `src` containing potential hidden lines, returning the HTML output. If you don't have
+/// hidden lines, use [`render_source_with_highlighting`] instead.
+crate fn render_with_highlighting<'a>(
+ src: impl Iterator- > + Debug,
+ out: &mut Buffer,
+ class: Option<&str>,
+ playground_button: Option<&str>,
+ tooltip: Option<(Option, &str)>,
+ edition: Edition,
+ extra_content: Option,
+ context_info: Option>,
+) {
+ debug!("highlighting: ================\n{:?}\n==============", src);
if let Some((edition_info, class)) = tooltip {
write!(
out,
@@ -56,8 +82,8 @@ crate fn render_with_highlighting(
}
write_header(out, class, extra_content);
- write_code(out, &src, edition, context_info);
- write_footer(out, playground_button);
+ let expand = write_code(out, src, edition, context_info);
+ write_footer(out, playground_button, expand);
}
fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option) {
@@ -86,13 +112,31 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option>,
edition: Edition,
context_info: Option>,
-) {
- // This replace allows to fix how the code source with DOS backline characters is displayed.
- let src = src.replace("\r\n", "\n");
- Classifier::new(&src, edition, context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP))
+) -> bool {
+ let mut iter = src.peekable();
+ let mut expand = false;
+
+ // For each `Line`, we replace DOS backlines with '\n'. This replace allows to fix how the code
+ // source with DOS backline characters is displayed.
+ while let Some(line) = iter.next() {
+ let (before, text, after) = match line {
+ Line::Hidden(text) => {
+ expand = true;
+ ("", text.replace("\r\n", "\n"), "")
+ }
+ Line::Shown(text) => ("", text.replace("\r\n", "\n"), ""),
+ };
+ if !before.is_empty() {
+ out.push_str(before);
+ }
+ Classifier::new(
+ &text.replace("\r\n", "\n"),
+ edition,
+ context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
+ )
.highlight(&mut |highlight| {
match highlight {
Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
@@ -100,10 +144,27 @@ fn write_code(
Highlight::ExitSpan => exit_span(out),
};
});
+ if iter.peek().is_some() && !text.ends_with('\n') {
+ out.push_str("\n");
+ }
+ if !after.is_empty() {
+ out.push_str(after);
+ }
+ }
+ expand
}
-fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
- writeln!(out, "{}", playground_button.unwrap_or_default());
+fn write_footer(out: &mut Buffer, playground_button: Option<&str>, expand: bool) {
+ writeln!(
+ out,
+ "\
+
\
+ {}{}\
+
\
+ ",
+ playground_button.unwrap_or_default(),
+ if expand { "" } else { "" },
+ );
}
/// How a span of text is classified. Mostly corresponds to token kinds.
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 68592ae96c187..7e09a60083e7b 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -1,9 +1,13 @@
use super::write_code;
use crate::html::format::Buffer;
+use crate::html::markdown::Line;
use expect_test::expect_file;
use rustc_span::create_default_session_globals_then;
use rustc_span::edition::Edition;
+use std::borrow::Cow;
+use std::iter::once;
+
const STYLE: &str = r#"