diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:03:36 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:03:36 +0000 |
commit | 17d40c6057c88f4c432b0d7bac88e1b84cb7e67f (patch) | |
tree | 3f66c4a5918660bb8a758ab6cda5ff8ee4f6cdcd /src/librustdoc/html/highlight | |
parent | Adding upstream version 1.64.0+dfsg1. (diff) | |
download | rustc-upstream/1.65.0+dfsg1.tar.xz rustc-upstream/1.65.0+dfsg1.zip |
Adding upstream version 1.65.0+dfsg1.upstream/1.65.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/librustdoc/html/highlight.rs | 355 | ||||
-rw-r--r-- | src/librustdoc/html/highlight/fixtures/decorations.html | 6 | ||||
-rw-r--r-- | src/librustdoc/html/highlight/fixtures/dos_line.html | 2 | ||||
-rw-r--r-- | src/librustdoc/html/highlight/fixtures/highlight.html | 8 | ||||
-rw-r--r-- | src/librustdoc/html/highlight/fixtures/sample.html | 39 | ||||
-rw-r--r-- | src/librustdoc/html/highlight/fixtures/sample.rs | 1 | ||||
-rw-r--r-- | src/librustdoc/html/highlight/fixtures/union.html | 10 | ||||
-rw-r--r-- | src/librustdoc/html/highlight/tests.rs | 18 |
8 files changed, 335 insertions, 104 deletions
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 05547ea15..8922bf377 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -29,31 +29,74 @@ pub(crate) struct HrefContext<'a, 'b, 'c> { /// This field is used to know "how far" from the top of the directory we are to link to either /// documentation pages or other source pages. pub(crate) root_path: &'c str, + /// This field is used to calculate precise local URLs. + pub(crate) current_href: &'c str, } /// Decorations are represented as a map from CSS class to vector of character ranges. /// Each range will be wrapped in a span with that class. +#[derive(Default)] pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>); -/// Highlights `src`, returning the HTML output. -pub(crate) fn render_with_highlighting( +#[derive(Eq, PartialEq, Clone, Copy)] +pub(crate) enum Tooltip { + Ignore, + 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 Buffer, - class: Option<&str>, + tooltip: Tooltip, playground_button: Option<&str>, - tooltip: Option<(Option<Edition>, &str)>, - edition: Edition, - extra_content: Option<Buffer>, - href_context: Option<HrefContext<'_, '_, '_>>, - decoration_info: Option<DecorationInfo>, ) { - debug!("highlighting: ================\n{}\n==============", src); - if let Some((edition_info, class)) = tooltip { + write_header(out, "rust-example-rendered", None, tooltip); + write_code(out, src, None, None); + write_footer(out, playground_button); +} + +/// Highlights `src` as a macro, returning the HTML output. +pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) { + write_header(out, "macro", None, Tooltip::None); + write_code(out, src, None, None); + write_footer(out, None); +} + +/// Highlights `src` as a source code page, returning the HTML output. +pub(crate) fn render_source_with_highlighting( + src: &str, + out: &mut Buffer, + line_numbers: Buffer, + href_context: HrefContext<'_, '_, '_>, + decoration_info: DecorationInfo, +) { + write_header(out, "", Some(line_numbers), Tooltip::None); + write_code(out, src, Some(href_context), Some(decoration_info)); + write_footer(out, None); +} + +fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, tooltip: Tooltip) { + write!( + out, + "<div class=\"example-wrap{}\">", + match tooltip { + Tooltip::Ignore => " ignore", + Tooltip::CompileFail => " compile_fail", + Tooltip::ShouldPanic => " should_panic", + Tooltip::Edition(_) => " edition", + Tooltip::None => "", + }, + ); + + if tooltip != Tooltip::None { write!( out, - "<div class='information'><div class='tooltip {}'{}>ⓘ</div></div>", - class, - if let Some(edition_info) = edition_info { + "<div class='tooltip'{}>ⓘ</div>", + if let Tooltip::Edition(edition_info) = tooltip { format!(" data-edition=\"{}\"", edition_info) } else { String::new() @@ -61,24 +104,115 @@ pub(crate) fn render_with_highlighting( ); } - write_header(out, class, extra_content); - write_code(out, src, edition, href_context, decoration_info); - write_footer(out, playground_button); -} - -fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buffer>) { - write!(out, "<div class=\"example-wrap\">"); if let Some(extra) = extra_content { out.push_buffer(extra); } - if let Some(class) = class { - write!(out, "<pre class=\"rust {}\">", class); - } else { + if class.is_empty() { write!(out, "<pre class=\"rust\">"); + } else { + write!(out, "<pre class=\"rust {class}\">"); } write!(out, "<code>"); } +/// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None` +/// basically (since it's `Option<Class>`). The following rules apply: +/// +/// * If two `Class` have the same variant, then they can be merged. +/// * If the other `Class` is unclassified and only contains white characters (backline, +/// whitespace, etc), it can be merged. +/// * `Class::Ident` is considered the same as unclassified (because it doesn't have an associated +/// CSS class). +fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool { + match (class1, class2) { + (Some(c1), Some(c2)) => c1.is_equal_to(c2), + (Some(Class::Ident(_)), None) | (None, Some(Class::Ident(_))) => true, + (Some(_), None) | (None, Some(_)) => text.trim().is_empty(), + (None, None) => true, + } +} + +/// This type is used as a conveniency to prevent having to pass all its fields as arguments into +/// the various functions (which became its methods). +struct TokenHandler<'a, 'b, 'c, 'd, 'e> { + out: &'a mut Buffer, + /// It contains the closing tag and the associated `Class`. + closing_tags: Vec<(&'static str, Class)>, + /// This is used because we don't automatically generate the closing tag on `ExitSpan` in + /// case an `EnterSpan` event with the same class follows. + pending_exit_span: Option<Class>, + /// `current_class` and `pending_elems` are used to group HTML elements with same `class` + /// attributes to reduce the DOM size. + current_class: Option<Class>, + /// We need to keep the `Class` for each element because it could contain a `Span` which is + /// used to generate links. + pending_elems: Vec<(&'b str, Option<Class>)>, + href_context: Option<HrefContext<'c, 'd, 'e>>, +} + +impl<'a, 'b, 'c, 'd, 'e> TokenHandler<'a, 'b, 'c, 'd, 'e> { + fn handle_exit_span(&mut self) { + // We can't get the last `closing_tags` element using `pop()` because `closing_tags` is + // being used in `write_pending_elems`. + let class = self.closing_tags.last().expect("ExitSpan without EnterSpan").1; + // We flush everything just in case... + self.write_pending_elems(Some(class)); + + exit_span(self.out, self.closing_tags.pop().expect("ExitSpan without EnterSpan").0); + self.pending_exit_span = None; + } + + /// Write all the pending elements sharing a same (or at mergeable) `Class`. + /// + /// If there is a "parent" (if a `EnterSpan` event was encountered) and the parent can be merged + /// with the elements' class, then we simply write the elements since the `ExitSpan` event will + /// close the tag. + /// + /// Otherwise, if there is only one pending element, we let the `string` function handle both + /// opening and closing the tag, otherwise we do it into this function. + /// + /// It returns `true` if `current_class` must be set to `None` afterwards. + fn write_pending_elems(&mut self, current_class: Option<Class>) -> bool { + if self.pending_elems.is_empty() { + return false; + } + if let Some((_, parent_class)) = self.closing_tags.last() && + can_merge(current_class, Some(*parent_class), "") + { + for (text, class) in self.pending_elems.iter() { + string(self.out, Escape(text), *class, &self.href_context, false); + } + } else { + // We only want to "open" the tag ourselves if we have more than one pending and if the + // current parent tag is not the same as our pending content. + let close_tag = if self.pending_elems.len() > 1 && current_class.is_some() { + Some(enter_span(self.out, current_class.unwrap(), &self.href_context)) + } else { + None + }; + for (text, class) in self.pending_elems.iter() { + string(self.out, Escape(text), *class, &self.href_context, close_tag.is_none()); + } + if let Some(close_tag) = close_tag { + exit_span(self.out, close_tag); + } + } + self.pending_elems.clear(); + true + } +} + +impl<'a, 'b, 'c, 'd, 'e> Drop for TokenHandler<'a, 'b, 'c, 'd, 'e> { + /// When leaving, we need to flush all pending data to not have missing content. + fn drop(&mut self) { + if self.pending_exit_span.is_some() { + self.handle_exit_span(); + } else { + self.write_pending_elems(self.current_class); + } + } +} + /// Convert the given `src` source code into HTML by adding classes for highlighting. /// /// This code is used to render code blocks (in the documentation) as well as the source code pages. @@ -93,27 +227,74 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf fn write_code( out: &mut Buffer, src: &str, - edition: Edition, href_context: Option<HrefContext<'_, '_, '_>>, decoration_info: Option<DecorationInfo>, ) { // This replace allows to fix how the code source with DOS backline characters is displayed. let src = src.replace("\r\n", "\n"); - let mut closing_tags: Vec<&'static str> = Vec::new(); + let mut token_handler = TokenHandler { + out, + closing_tags: Vec::new(), + pending_exit_span: None, + current_class: None, + pending_elems: Vec::new(), + href_context, + }; + Classifier::new( &src, - edition, - href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP), + token_handler.href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP), decoration_info, ) .highlight(&mut |highlight| { match highlight { - Highlight::Token { text, class } => string(out, Escape(text), class, &href_context), + Highlight::Token { text, class } => { + // If we received a `ExitSpan` event and then have a non-compatible `Class`, we + // need to close the `<span>`. + let need_current_class_update = if let Some(pending) = token_handler.pending_exit_span && + !can_merge(Some(pending), class, text) { + token_handler.handle_exit_span(); + true + // If the two `Class` are different, time to flush the current content and start + // a new one. + } else if !can_merge(token_handler.current_class, class, text) { + token_handler.write_pending_elems(token_handler.current_class); + true + } else { + token_handler.current_class.is_none() + }; + + if need_current_class_update { + token_handler.current_class = class.map(Class::dummy); + } + token_handler.pending_elems.push((text, class)); + } Highlight::EnterSpan { class } => { - closing_tags.push(enter_span(out, class, &href_context)) + let mut should_add = true; + if let Some(pending_exit_span) = token_handler.pending_exit_span { + if class.is_equal_to(pending_exit_span) { + should_add = false; + } else { + token_handler.handle_exit_span(); + } + } else { + // We flush everything just in case... + if token_handler.write_pending_elems(token_handler.current_class) { + token_handler.current_class = None; + } + } + if should_add { + let closing_tag = enter_span(token_handler.out, class, &token_handler.href_context); + token_handler.closing_tags.push((closing_tag, class)); + } + + token_handler.current_class = None; + token_handler.pending_exit_span = None; } Highlight::ExitSpan => { - exit_span(out, closing_tags.pop().expect("ExitSpan without EnterSpan")) + token_handler.current_class = None; + token_handler.pending_exit_span = + Some(token_handler.closing_tags.last().as_ref().expect("ExitSpan without EnterSpan").1); } }; }); @@ -130,15 +311,15 @@ enum Class { DocComment, Attribute, KeyWord, - // Keywords that do pointer/reference stuff. + /// Keywords that do pointer/reference stuff. RefKeyWord, Self_(Span), - Op, Macro(Span), MacroNonTerminal, String, Number, Bool, + /// `Ident` isn't rendered in the HTML but we still need it for the `Span` it contains. Ident(Span), Lifetime, PreludeTy, @@ -148,6 +329,31 @@ enum Class { } impl Class { + /// It is only looking at the variant, not the variant content. + /// + /// It is used mostly to group multiple similar HTML elements into one `<span>` instead of + /// multiple ones. + fn is_equal_to(self, other: Self) -> bool { + match (self, other) { + (Self::Self_(_), Self::Self_(_)) + | (Self::Macro(_), Self::Macro(_)) + | (Self::Ident(_), Self::Ident(_)) => true, + (Self::Decoration(c1), Self::Decoration(c2)) => c1 == c2, + (x, y) => x == y, + } + } + + /// If `self` contains a `Span`, it'll be replaced with `DUMMY_SP` to prevent creating links + /// on "empty content" (because of the attributes merge). + fn dummy(self) -> Self { + match self { + Self::Self_(_) => Self::Self_(DUMMY_SP), + Self::Macro(_) => Self::Macro(DUMMY_SP), + Self::Ident(_) => Self::Ident(DUMMY_SP), + s => s, + } + } + /// Returns the css class expected by rustdoc for each `Class`. fn as_html(self) -> &'static str { match self { @@ -157,13 +363,12 @@ impl Class { Class::KeyWord => "kw", Class::RefKeyWord => "kw-2", Class::Self_(_) => "self", - Class::Op => "op", Class::Macro(_) => "macro", Class::MacroNonTerminal => "macro-nonterminal", Class::String => "string", Class::Number => "number", Class::Bool => "bool-val", - Class::Ident(_) => "ident", + Class::Ident(_) => "", Class::Lifetime => "lifetime", Class::PreludeTy => "prelude-ty", Class::PreludeVal => "prelude-val", @@ -182,7 +387,6 @@ impl Class { | Self::Attribute | Self::KeyWord | Self::RefKeyWord - | Self::Op | Self::MacroNonTerminal | Self::String | Self::Number @@ -220,7 +424,7 @@ impl<'a> Iterator for TokenIter<'a> { } /// Classifies into identifier class; returns `None` if this is a non-keyword identifier. -fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option<Class> { +fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option<Class> { let ignore: &[&str] = if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] }; if ignore.iter().any(|k| *k == text) { @@ -229,7 +433,7 @@ fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) Some(match text { "ref" | "mut" => Class::RefKeyWord, "false" | "true" => Class::Bool, - _ if Symbol::intern(text).is_reserved(|| edition) => Class::KeyWord, + _ if Symbol::intern(text).is_reserved(|| Edition::Edition2021) => Class::KeyWord, _ => return None, }) } @@ -250,7 +454,7 @@ impl<'a> PeekIter<'a> { fn new(iter: TokenIter<'a>) -> Self { Self { stored: VecDeque::new(), peek_pos: 0, iter } } - /// Returns the next item after the current one. It doesn't interfer with `peek_next` output. + /// Returns the next item after the current one. It doesn't interfere with `peek_next` output. fn peek(&mut self) -> Option<&(TokenKind, &'a str)> { if self.stored.is_empty() { if let Some(next) = self.iter.next() { @@ -259,7 +463,7 @@ impl<'a> PeekIter<'a> { } self.stored.front() } - /// Returns the next item after the last one peeked. It doesn't interfer with `peek` output. + /// Returns the next item after the last one peeked. It doesn't interfere with `peek` output. fn peek_next(&mut self) -> Option<&(TokenKind, &'a str)> { self.peek_pos += 1; if self.peek_pos - 1 < self.stored.len() { @@ -311,7 +515,6 @@ struct Classifier<'a> { in_attribute: bool, in_macro: bool, in_macro_nonterminal: bool, - edition: Edition, byte_pos: u32, file_span: Span, src: &'a str, @@ -321,12 +524,7 @@ struct Classifier<'a> { impl<'a> Classifier<'a> { /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code /// file span which will be used later on by the `span_correspondance_map`. - fn new( - src: &str, - edition: Edition, - file_span: Span, - decoration_info: Option<DecorationInfo>, - ) -> Classifier<'_> { + fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> { let tokens = PeekIter::new(TokenIter { src }); let decorations = decoration_info.map(Decorations::new); Classifier { @@ -334,7 +532,6 @@ impl<'a> Classifier<'a> { in_attribute: false, in_macro: false, in_macro_nonterminal: false, - edition, byte_pos: 0, file_span, src, @@ -354,7 +551,6 @@ impl<'a> Classifier<'a> { let start = self.byte_pos as usize; let mut pos = start; let mut has_ident = false; - let edition = self.edition; loop { let mut nb = 0; @@ -376,7 +572,7 @@ impl<'a> Classifier<'a> { if let Some((None, text)) = self.tokens.peek().map(|(token, text)| { if *token == TokenKind::Ident { - let class = get_real_ident_class(text, edition, true); + let class = get_real_ident_class(text, true); (class, text) } else { // Doesn't matter which Class we put in here... @@ -494,7 +690,7 @@ impl<'a> Classifier<'a> { // or a reference or pointer type. Unless, of course, it looks like // a logical and or a multiplication operator: `&&` or `* `. TokenKind::Star => match self.tokens.peek() { - Some((TokenKind::Whitespace, _)) => Class::Op, + Some((TokenKind::Whitespace, _)) => return no_highlight(sink), Some((TokenKind::Ident, "mut")) => { self.next(); sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) }); @@ -510,15 +706,15 @@ impl<'a> Classifier<'a> { TokenKind::And => match self.tokens.peek() { Some((TokenKind::And, _)) => { self.next(); - sink(Highlight::Token { text: "&&", class: Some(Class::Op) }); + sink(Highlight::Token { text: "&&", class: None }); return; } Some((TokenKind::Eq, _)) => { self.next(); - sink(Highlight::Token { text: "&=", class: Some(Class::Op) }); + sink(Highlight::Token { text: "&=", class: None }); return; } - Some((TokenKind::Whitespace, _)) => Class::Op, + Some((TokenKind::Whitespace, _)) => return no_highlight(sink), Some((TokenKind::Ident, "mut")) => { self.next(); sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) }); @@ -531,7 +727,7 @@ impl<'a> Classifier<'a> { TokenKind::Eq => match lookahead { Some(TokenKind::Eq) => { self.next(); - sink(Highlight::Token { text: "==", class: Some(Class::Op) }); + sink(Highlight::Token { text: "==", class: None }); return; } Some(TokenKind::Gt) => { @@ -539,7 +735,7 @@ impl<'a> Classifier<'a> { sink(Highlight::Token { text: "=>", class: None }); return; } - _ => Class::Op, + _ => return no_highlight(sink), }, TokenKind::Minus if lookahead == Some(TokenKind::Gt) => { self.next(); @@ -556,7 +752,7 @@ impl<'a> Classifier<'a> { | TokenKind::Percent | TokenKind::Bang | TokenKind::Lt - | TokenKind::Gt => Class::Op, + | TokenKind::Gt => return no_highlight(sink), // Miscellaneous, no highlighting. TokenKind::Dot @@ -634,7 +830,7 @@ impl<'a> Classifier<'a> { sink(Highlight::Token { text, class: None }); return; } - TokenKind::Ident => match get_real_ident_class(text, self.edition, false) { + TokenKind::Ident => match get_real_ident_class(text, false) { None => match text { "Option" | "Result" => Class::PreludeTy, "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, @@ -682,7 +878,7 @@ fn enter_span( klass: Class, href_context: &Option<HrefContext<'_, '_, '_>>, ) -> &'static str { - string_without_closing_tag(out, "", Some(klass), href_context).expect( + string_without_closing_tag(out, "", Some(klass), href_context, true).expect( "internal error: enter_span was called with Some(klass) but did not return a \ closing HTML tag", ) @@ -714,8 +910,10 @@ fn string<T: Display>( text: T, klass: Option<Class>, href_context: &Option<HrefContext<'_, '_, '_>>, + open_tag: bool, ) { - if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context) { + if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag) + { out.write_str(closing_tag); } } @@ -734,6 +932,7 @@ fn string_without_closing_tag<T: Display>( text: T, klass: Option<Class>, href_context: &Option<HrefContext<'_, '_, '_>>, + open_tag: bool, ) -> Option<&'static str> { let Some(klass) = klass else { @@ -742,6 +941,10 @@ fn string_without_closing_tag<T: Display>( }; let Some(def_span) = klass.get_span() else { + if !open_tag { + write!(out, "{}", text); + return None; + } write!(out, "<span class=\"{}\">{}", klass.as_html(), text); return Some("</span>"); }; @@ -765,6 +968,7 @@ fn string_without_closing_tag<T: Display>( path }); } + if let Some(href_context) = href_context { if let Some(href) = href_context.context.shared.span_correspondance_map.get(&def_span).and_then(|href| { @@ -775,9 +979,9 @@ fn string_without_closing_tag<T: Display>( // a link to their definition can be generated using this: // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338 match href { - LinkFromSrc::Local(span) => context - .href_from_span(*span, true) - .map(|s| format!("{}{}", href_context.root_path, s)), + LinkFromSrc::Local(span) => { + context.href_from_span_relative(*span, href_context.current_href) + } LinkFromSrc::External(def_id) => { format::href_with_root_path(*def_id, context, Some(href_context.root_path)) .ok() @@ -793,12 +997,33 @@ fn string_without_closing_tag<T: Display>( } }) { - write!(out, "<a class=\"{}\" href=\"{}\">{}", klass.as_html(), href, text_s); + if !open_tag { + // We're already inside an element which has the same klass, no need to give it + // again. + write!(out, "<a href=\"{}\">{}", href, text_s); + } else { + let klass_s = klass.as_html(); + if klass_s.is_empty() { + write!(out, "<a href=\"{}\">{}", href, text_s); + } else { + write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s); + } + } return Some("</a>"); } } - write!(out, "<span class=\"{}\">{}", klass.as_html(), text_s); - Some("</span>") + if !open_tag { + write!(out, "{}", text_s); + return None; + } + let klass_s = klass.as_html(); + if klass_s.is_empty() { + write!(out, "{}", text_s); + Some("") + } else { + write!(out, "<span class=\"{}\">{}", klass_s, text_s); + Some("</span>") + } } #[cfg(test)] diff --git a/src/librustdoc/html/highlight/fixtures/decorations.html b/src/librustdoc/html/highlight/fixtures/decorations.html index 45f567880..ebf29f9cb 100644 --- a/src/librustdoc/html/highlight/fixtures/decorations.html +++ b/src/librustdoc/html/highlight/fixtures/decorations.html @@ -1,2 +1,4 @@ -<span class="example"><span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="number">1</span>;</span> -<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="number">2</span>;
\ No newline at end of file +<span class="example"><span class="kw">let </span>x = <span class="number">1</span>; +<span class="kw">let </span>y = <span class="number">2</span>; +</span><span class="example2"><span class="kw">let </span>z = <span class="number">3</span>; +</span><span class="kw">let </span>a = <span class="number">4</span>;
\ No newline at end of file diff --git a/src/librustdoc/html/highlight/fixtures/dos_line.html b/src/librustdoc/html/highlight/fixtures/dos_line.html index 1c8dbffe7..30b50ca7c 100644 --- a/src/librustdoc/html/highlight/fixtures/dos_line.html +++ b/src/librustdoc/html/highlight/fixtures/dos_line.html @@ -1,3 +1,3 @@ -<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">foo</span>() { +<span class="kw">pub fn </span>foo() { <span class="macro">println!</span>(<span class="string">"foo"</span>); } diff --git a/src/librustdoc/html/highlight/fixtures/highlight.html b/src/librustdoc/html/highlight/fixtures/highlight.html index abc2db179..9f73e03f9 100644 --- a/src/librustdoc/html/highlight/fixtures/highlight.html +++ b/src/librustdoc/html/highlight/fixtures/highlight.html @@ -1,4 +1,4 @@ -<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::a::foo</span>; -<span class="kw">use</span> <span class="ident"><span class="self">self</span>::whatever</span>; -<span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="ident"><span class="kw">super</span>::b::foo</span>; -<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="ident"><span class="self">Self</span>::whatever</span>;
\ No newline at end of file +<span class="kw">use </span><span class="kw">crate</span>::a::foo; +<span class="kw">use </span><span class="self">self</span>::whatever; +<span class="kw">let </span>x = <span class="kw">super</span>::b::foo; +<span class="kw">let </span>y = <span class="self">Self</span>::whatever;
\ No newline at end of file diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html index b117a12e3..4a5a3cf60 100644 --- a/src/librustdoc/html/highlight/fixtures/sample.html +++ b/src/librustdoc/html/highlight/fixtures/sample.html @@ -8,30 +8,31 @@ .lifetime { color: #B76514; } .question-mark { color: #ff9011; } </style> -<pre><code><span class="attribute">#![<span class="ident">crate_type</span> <span class="op">=</span> <span class="string">"lib"</span>]</span> +<pre><code><span class="attribute">#![crate_type = <span class="string">"lib"</span>] -<span class="kw">use</span> <span class="ident">std::path</span>::{<span class="ident">Path</span>, <span class="ident">PathBuf</span>}; +</span><span class="kw">use </span>std::path::{Path, PathBuf}; -<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> <span class="op">=</span> <span class="string">"linux"</span>)]</span> -<span class="kw">fn</span> <span class="ident">main</span>() -> () { - <span class="kw">let</span> <span class="ident">foo</span> <span class="op">=</span> <span class="bool-val">true</span> <span class="op">&&</span> <span class="bool-val">false</span> <span class="op">|</span><span class="op">|</span> <span class="bool-val">true</span>; - <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*const</span> () <span class="op">=</span> <span class="number">0</span>; - <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">&</span><span class="ident">foo</span>; - <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="op">&&</span><span class="ident">foo</span>; - <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">*</span><span class="ident">foo</span>; - <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&mut</span> <span class="ident">bar</span>); - <span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op"><</span> <span class="ident">N</span> <span class="op">&&</span> <span class="ident">index</span> <span class="op"><</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>); - <span class="ident">::std::env::var</span>(<span class="string">"gateau"</span>).<span class="ident">is_ok</span>(); - <span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span> - <span class="kw">let</span> <span class="ident">s</span>:<span class="ident">std::path::PathBuf</span> <span class="op">=</span> <span class="ident">std::path::PathBuf::new</span>(); - <span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">s</span> <span class="op">=</span> <span class="ident">String::new</span>(); +<span class="attribute">#[cfg(target_os = <span class="string">"linux"</span>)] +#[cfg(target_os = <span class="string">"windows"</span>)] +</span><span class="kw">fn </span>main() -> () { + <span class="kw">let </span>foo = <span class="bool-val">true </span>&& <span class="bool-val">false </span>|| <span class="bool-val">true</span>; + <span class="kw">let _</span>: <span class="kw-2">*const </span>() = <span class="number">0</span>; + <span class="kw">let _ </span>= <span class="kw-2">&</span>foo; + <span class="kw">let _ </span>= &&foo; + <span class="kw">let _ </span>= <span class="kw-2">*</span>foo; + <span class="macro">mac!</span>(foo, <span class="kw-2">&mut </span>bar); + <span class="macro">assert!</span>(<span class="self">self</span>.length < N && index <= <span class="self">self</span>.length); + ::std::env::var(<span class="string">"gateau"</span>).is_ok(); + <span class="attribute">#[rustfmt::skip] + </span><span class="kw">let </span>s:std::path::PathBuf = std::path::PathBuf::new(); + <span class="kw">let </span><span class="kw-2">mut </span>s = String::new(); - <span class="kw">match</span> <span class="kw-2">&</span><span class="ident">s</span> { - <span class="kw-2">ref</span> <span class="kw-2">mut</span> <span class="ident">x</span> => {} + <span class="kw">match </span><span class="kw-2">&</span>s { + <span class="kw-2">ref mut </span>x => {} } } -<span class="macro">macro_rules!</span> <span class="ident">bar</span> { - (<span class="macro-nonterminal">$</span><span class="macro-nonterminal">foo</span>:<span class="ident">tt</span>) => {}; +<span class="macro">macro_rules! </span>bar { + (<span class="macro-nonterminal">$foo</span>:tt) => {}; } </code></pre> diff --git a/src/librustdoc/html/highlight/fixtures/sample.rs b/src/librustdoc/html/highlight/fixtures/sample.rs index fbfdc6767..ef85b566c 100644 --- a/src/librustdoc/html/highlight/fixtures/sample.rs +++ b/src/librustdoc/html/highlight/fixtures/sample.rs @@ -3,6 +3,7 @@ use std::path::{Path, PathBuf}; #[cfg(target_os = "linux")] +#[cfg(target_os = "windows")] fn main() -> () { let foo = true && false || true; let _: *const () = 0; diff --git a/src/librustdoc/html/highlight/fixtures/union.html b/src/librustdoc/html/highlight/fixtures/union.html index c0acf31a0..9f8915282 100644 --- a/src/librustdoc/html/highlight/fixtures/union.html +++ b/src/librustdoc/html/highlight/fixtures/union.html @@ -1,8 +1,8 @@ -<span class="kw">union</span> <span class="ident">Foo</span> { - <span class="ident">i</span>: <span class="ident">i8</span>, - <span class="ident">u</span>: <span class="ident">i8</span>, +<span class="kw">union </span>Foo { + i: i8, + u: i8, } -<span class="kw">fn</span> <span class="ident">main</span>() { - <span class="kw">let</span> <span class="ident">union</span> <span class="op">=</span> <span class="number">0</span>; +<span class="kw">fn </span>main() { + <span class="kw">let </span>union = <span class="number">0</span>; } diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 1fea7e983..a5e633df4 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -3,7 +3,6 @@ use crate::html::format::Buffer; use expect_test::expect_file; use rustc_data_structures::fx::FxHashMap; use rustc_span::create_default_session_globals_then; -use rustc_span::edition::Edition; const STYLE: &str = r#" <style> @@ -23,7 +22,7 @@ fn test_html_highlighting() { let src = include_str!("fixtures/sample.rs"); let html = { let mut out = Buffer::new(); - write_code(&mut out, src, Edition::Edition2018, None, None); + write_code(&mut out, src, None, None); format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner()) }; expect_file!["fixtures/sample.html"].assert_eq(&html); @@ -37,7 +36,7 @@ fn test_dos_backline() { println!(\"foo\");\r\n\ }\r\n"; let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None, None); + write_code(&mut html, src, None, None); expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner()); }); } @@ -51,7 +50,7 @@ let x = super::b::foo; let y = Self::whatever;"; let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None, None); + write_code(&mut html, src, None, None); expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner()); }); } @@ -61,7 +60,7 @@ fn test_union_highlighting() { create_default_session_globals_then(|| { let src = include_str!("fixtures/union.rs"); let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None, None); + write_code(&mut html, src, None, None); expect_file!["fixtures/union.html"].assert_eq(&html.into_inner()); }); } @@ -70,12 +69,15 @@ fn test_union_highlighting() { fn test_decorations() { create_default_session_globals_then(|| { let src = "let x = 1; -let y = 2;"; +let y = 2; +let z = 3; +let a = 4;"; let mut decorations = FxHashMap::default(); - decorations.insert("example", vec![(0, 10)]); + decorations.insert("example", vec![(0, 10), (11, 21)]); + decorations.insert("example2", vec![(22, 32)]); let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations))); + write_code(&mut html, src, None, Some(DecorationInfo(decorations))); expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner()); }); } |