From a4b7ed7a42c716ab9f05e351f003d589124fd55d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:58 +0200 Subject: Adding upstream version 1.68.2+dfsg1. Signed-off-by: Daniel Baumann --- src/librustdoc/html/format.rs | 31 +- src/librustdoc/html/highlight.rs | 46 +-- src/librustdoc/html/markdown.rs | 43 ++- src/librustdoc/html/markdown/tests.rs | 8 + src/librustdoc/html/render/context.rs | 33 ++- src/librustdoc/html/render/mod.rs | 35 ++- src/librustdoc/html/render/print_item.rs | 91 +++--- src/librustdoc/html/render/search_index.rs | 92 ++++-- src/librustdoc/html/render/write_shared.rs | 64 ++-- src/librustdoc/html/sources.rs | 62 ++-- src/librustdoc/html/static/css/rustdoc.css | 376 +++++++++--------------- src/librustdoc/html/static/css/settings.css | 37 +-- src/librustdoc/html/static/css/themes/ayu.css | 63 ++-- src/librustdoc/html/static/css/themes/dark.css | 49 +-- src/librustdoc/html/static/css/themes/light.css | 49 +-- src/librustdoc/html/static/js/main.js | 49 ++- src/librustdoc/html/static/js/search.js | 130 ++++---- src/librustdoc/html/static/js/settings.js | 6 +- src/librustdoc/html/static/js/source-script.js | 2 +- src/librustdoc/html/templates/page.html | 32 +- src/librustdoc/html/templates/print_item.html | 2 +- 21 files changed, 621 insertions(+), 679 deletions(-) (limited to 'src/librustdoc/html') diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 39e2a9022..d3dc4065d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -569,7 +569,7 @@ fn generate_macro_def_id_path( root_path: Option<&str>, ) -> Result<(String, ItemType, Vec), HrefError> { let tcx = cx.shared.tcx; - let crate_name = tcx.crate_name(def_id.krate).to_string(); + let crate_name = tcx.crate_name(def_id.krate); let cache = cx.cache(); let fqp: Vec = tcx @@ -584,7 +584,7 @@ fn generate_macro_def_id_path( } }) .collect(); - let mut relative = fqp.iter().map(|elem| elem.to_string()); + let mut relative = fqp.iter().copied(); let cstore = CStore::from_tcx(tcx); // We need this to prevent a `panic` when this function is used from intra doc links... if !cstore.has_crate_data(def_id.krate) { @@ -602,9 +602,9 @@ fn generate_macro_def_id_path( }; let mut path = if is_macro_2 { - once(crate_name.clone()).chain(relative).collect() + once(crate_name).chain(relative).collect() } else { - vec![crate_name.clone(), relative.next_back().unwrap()] + vec![crate_name, relative.next_back().unwrap()] }; if path.len() < 2 { // The minimum we can have is the crate name followed by the macro name. If shorter, then @@ -614,17 +614,22 @@ fn generate_macro_def_id_path( } if let Some(last) = path.last_mut() { - *last = format!("macro.{}.html", last); + *last = Symbol::intern(&format!("macro.{}.html", last.as_str())); } let url = match cache.extern_locations[&def_id.krate] { ExternalLocation::Remote(ref s) => { // `ExternalLocation::Remote` always end with a `/`. - format!("{}{}", s, path.join("/")) + format!("{}{}", s, path.iter().map(|p| p.as_str()).join("/")) } ExternalLocation::Local => { // `root_path` always end with a `/`. - format!("{}{}/{}", root_path.unwrap_or(""), crate_name, path.join("/")) + format!( + "{}{}/{}", + root_path.unwrap_or(""), + crate_name, + path.iter().map(|p| p.as_str()).join("/") + ) } ExternalLocation::Unknown => { debug!("crate {} not in cache when linkifying macros", crate_name); @@ -957,7 +962,7 @@ fn fmt_type<'cx>( clean::Tuple(ref typs) => { match &typs[..] { &[] => primitive_link(f, PrimitiveType::Unit, "()", cx), - &[ref one] => { + [one] => { if let clean::Generic(name) = one { primitive_link(f, PrimitiveType::Tuple, &format!("({name},)"), cx) } else { @@ -1050,7 +1055,7 @@ fn fmt_type<'cx>( _ => String::new(), }; let m = mutability.print_with_space(); - let amp = if f.alternate() { "&".to_string() } else { "&".to_string() }; + let amp = if f.alternate() { "&" } else { "&" }; match **ty { clean::DynTrait(ref bounds, ref trait_lt) if bounds.len() > 1 || trait_lt.is_some() => @@ -1655,10 +1660,10 @@ impl clean::types::Term { &'a self, cx: &'a Context<'tcx>, ) -> impl fmt::Display + 'a + Captures<'tcx> { - match self { - clean::types::Term::Type(ty) => ty.print(cx), - _ => todo!(), - } + display_fn(move |f| match self { + clean::types::Term::Type(ty) => fmt::Display::fmt(&ty.print(cx), f), + clean::types::Term::Constant(ct) => fmt::Display::fmt(&ct.print(cx.tcx()), f), + }) } } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index cd8c8c463..8a9e6caf6 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -21,15 +21,15 @@ use rustc_span::{BytePos, Span, DUMMY_SP}; use super::format::{self, Buffer}; /// This type is needed in case we want to render links on items to allow to go to their definition. -pub(crate) struct HrefContext<'a, 'b, 'c> { - pub(crate) context: &'a Context<'b>, +pub(crate) struct HrefContext<'a, 'tcx> { + pub(crate) context: &'a Context<'tcx>, /// This span contains the current file we're going through. pub(crate) file_span: Span, /// 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, + pub(crate) root_path: &'a str, /// This field is used to calculate precise local URLs. - pub(crate) current_href: &'c str, + pub(crate) current_href: String, } /// Decorations are represented as a map from CSS class to vector of character ranges. @@ -70,7 +70,7 @@ pub(crate) fn render_source_with_highlighting( src: &str, out: &mut Buffer, line_numbers: Buffer, - href_context: HrefContext<'_, '_, '_>, + href_context: HrefContext<'_, '_>, decoration_info: DecorationInfo, extra: Option<&str>, ) { @@ -137,7 +137,7 @@ fn can_merge(class1: Option, class2: Option, text: &str) -> bool { /// 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> { +struct TokenHandler<'a, 'tcx> { out: &'a mut Buffer, /// It contains the closing tag and the associated `Class`. closing_tags: Vec<(&'static str, Class)>, @@ -149,11 +149,11 @@ struct TokenHandler<'a, 'b, 'c, 'd, 'e> { current_class: Option, /// 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)>, - href_context: Option>, + pending_elems: Vec<(&'a str, Option)>, + href_context: Option>, } -impl<'a, 'b, 'c, 'd, 'e> TokenHandler<'a, 'b, 'c, 'd, 'e> { +impl<'a, 'tcx> TokenHandler<'a, 'tcx> { 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`. @@ -205,7 +205,7 @@ impl<'a, 'b, 'c, 'd, 'e> TokenHandler<'a, 'b, 'c, 'd, 'e> { } } -impl<'a, 'b, 'c, 'd, 'e> Drop for TokenHandler<'a, 'b, 'c, 'd, 'e> { +impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> { /// 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() { @@ -230,7 +230,7 @@ impl<'a, 'b, 'c, 'd, 'e> Drop for TokenHandler<'a, 'b, 'c, 'd, 'e> { fn write_code( out: &mut Buffer, src: &str, - href_context: Option>, + href_context: Option>, decoration_info: Option, ) { // This replace allows to fix how the code source with DOS backline characters is displayed. @@ -514,18 +514,18 @@ impl Decorations { /// Processes program tokens, classifying strings of text by highlighting /// category (`Class`). -struct Classifier<'a> { - tokens: PeekIter<'a>, +struct Classifier<'src> { + tokens: PeekIter<'src>, in_attribute: bool, in_macro: bool, in_macro_nonterminal: bool, byte_pos: u32, file_span: Span, - src: &'a str, + src: &'src str, decorations: Option, } -impl<'a> Classifier<'a> { +impl<'src> Classifier<'src> { /// 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, file_span: Span, decoration_info: Option) -> Classifier<'_> { @@ -603,7 +603,7 @@ impl<'a> Classifier<'a> { /// /// It returns the token's kind, the token as a string and its byte position in the source /// string. - fn next(&mut self) -> Option<(TokenKind, &'a str, u32)> { + fn next(&mut self) -> Option<(TokenKind, &'src str, u32)> { if let Some((kind, text)) = self.tokens.next() { let before = self.byte_pos; self.byte_pos += text.len() as u32; @@ -618,7 +618,7 @@ impl<'a> Classifier<'a> { /// The general structure for this method is to iterate over each token, /// possibly giving it an HTML span with a class specifying what flavor of /// token is used. - fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) { + fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'src>)) { loop { if let Some(decs) = self.decorations.as_mut() { let byte_pos = self.byte_pos; @@ -666,8 +666,8 @@ impl<'a> Classifier<'a> { fn advance( &mut self, token: TokenKind, - text: &'a str, - sink: &mut dyn FnMut(Highlight<'a>), + text: &'src str, + sink: &mut dyn FnMut(Highlight<'src>), before: u32, ) { let lookahead = self.peek(); @@ -881,7 +881,7 @@ impl<'a> Classifier<'a> { fn enter_span( out: &mut Buffer, klass: Class, - href_context: &Option>, + href_context: &Option>, ) -> &'static str { 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 \ @@ -914,7 +914,7 @@ fn string( out: &mut Buffer, text: T, klass: Option, - href_context: &Option>, + href_context: &Option>, open_tag: bool, ) { if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag) @@ -936,7 +936,7 @@ fn string_without_closing_tag( out: &mut Buffer, text: T, klass: Option, - href_context: &Option>, + href_context: &Option>, open_tag: bool, ) -> Option<&'static str> { let Some(klass) = klass @@ -985,7 +985,7 @@ fn string_without_closing_tag( // 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_relative(*span, href_context.current_href) + 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)) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 1e1c657b0..4ff67fe15 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -30,7 +30,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::HirId; use rustc_middle::ty::TyCtxt; use rustc_span::edition::Edition; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use once_cell::sync::Lazy; use std::borrow::Cow; @@ -198,7 +198,7 @@ fn slugify(c: char) -> Option { #[derive(Clone, Debug)] pub struct Playground { - pub crate_name: Option, + pub crate_name: Option, pub url: String, } @@ -236,12 +236,12 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { return event; }; - let mut origtext = String::new(); + let mut original_text = String::new(); for event in &mut self.inner { match event { Event::End(Tag::CodeBlock(..)) => break, Event::Text(ref s) => { - origtext.push_str(s); + original_text.push_str(s); } _ => {} } @@ -258,7 +258,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> {
{}
\ ", lang, - Escape(&origtext), + Escape(&original_text), ) .into(), )); @@ -268,7 +268,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { CodeBlockKind::Indented => Default::default(), }; - let lines = origtext.lines().filter_map(|l| map_line(l).for_html()); + let lines = original_text.lines().filter_map(|l| map_line(l).for_html()); let text = lines.intersperse("\n".into()).collect::(); compile_fail = parse_result.compile_fail; @@ -285,12 +285,12 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { if url.is_empty() { return None; } - let test = origtext + let test = original_text .lines() .map(|l| map_line(l).for_code()) .intersperse("\n".into()) .collect::(); - let krate = krate.as_ref().map(|s| &**s); + let krate = krate.as_ref().map(|s| s.as_str()); let (test, _, _) = doctest::make_test(&test, krate, false, &Default::default(), edition, None); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; @@ -567,11 +567,12 @@ struct SummaryLine<'a, I: Iterator>> { inner: I, started: bool, depth: u32, + skipped_tags: u32, } impl<'a, I: Iterator>> SummaryLine<'a, I> { fn new(iter: I) -> Self { - SummaryLine { inner: iter, started: false, depth: 0 } + SummaryLine { inner: iter, started: false, depth: 0, skipped_tags: 0 } } } @@ -601,6 +602,7 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { let is_allowed_tag = match event { Event::Start(ref c) => { if is_forbidden_tag(c) { + self.skipped_tags += 1; return None; } self.depth += 1; @@ -608,6 +610,7 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { } Event::End(ref c) => { if is_forbidden_tag(c) { + self.skipped_tags += 1; return None; } self.depth -= 1; @@ -616,6 +619,9 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { } _ => true, }; + if !is_allowed_tag { + self.skipped_tags += 1; + } return if !is_allowed_tag { if is_start { Some(Event::Start(Tag::Paragraph)) @@ -1096,11 +1102,11 @@ impl MarkdownItemInfo<'_> { } impl MarkdownSummaryLine<'_> { - pub(crate) fn into_string(self) -> String { + pub(crate) fn into_string_with_has_more_content(self) -> (String, bool) { let MarkdownSummaryLine(md, links) = self; // This is actually common enough to special-case if md.is_empty() { - return String::new(); + return (String::new(), false); } let mut replacer = |broken_link: BrokenLink<'_>| { @@ -1110,17 +1116,26 @@ impl MarkdownSummaryLine<'_> { .map(|link| (link.href.as_str().into(), link.new_text.as_str().into())) }; - let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer)); + let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer)) + .peekable(); + let mut summary = SummaryLine::new(p); let mut s = String::new(); - let without_paragraphs = LinkReplacer::new(SummaryLine::new(p), links).filter(|event| { + let without_paragraphs = LinkReplacer::new(&mut summary, links).filter(|event| { !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph)) }); html::push_html(&mut s, without_paragraphs); - s + let has_more_content = + matches!(summary.inner.peek(), Some(Event::Start(_))) || summary.skipped_tags > 0; + + (s, has_more_content) + } + + pub(crate) fn into_string(self) -> String { + self.into_string_with_has_more_content().0 } } diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 68b31a6ee..5878c5826 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -343,6 +343,14 @@ fn test_ascii_with_prepending_hashtag() { #..#.#....#....#....#..#. #..#.#....#....#....#..#. #..#.####.####.####..##.. +", + ); + t( + r#"```markdown +# hello +```"#, + "
\
+# hello
 
", ); } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 73690c86f..5cefe9475 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -309,7 +309,7 @@ impl<'tcx> Context<'tcx> { pub(crate) fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option { let mut root = self.root_path(); - let mut path = String::new(); + let mut path: String; let cnum = span.cnum(self.sess()); // We can safely ignore synthetic `SourceFile`s. @@ -340,10 +340,24 @@ impl<'tcx> Context<'tcx> { ExternalLocation::Unknown => return None, }; - sources::clean_path(&src_root, file, false, |component| { - path.push_str(&component.to_string_lossy()); + let href = RefCell::new(PathBuf::new()); + sources::clean_path( + &src_root, + file, + |component| { + href.borrow_mut().push(component); + }, + || { + href.borrow_mut().pop(); + }, + ); + + path = href.into_inner().to_string_lossy().to_string(); + + if let Some(c) = path.as_bytes().last() && *c != b'/' { path.push('/'); - }); + } + let mut fname = file.file_name().expect("source has no filename").to_os_string(); fname.push(".html"); path.push_str(&fname.to_string_lossy()); @@ -450,8 +464,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // If user passed in `--playground-url` arg, we fill in crate name here let mut playground = None; if let Some(url) = playground_url { - playground = - Some(markdown::Playground { crate_name: Some(krate.name(tcx).to_string()), url }); + playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url }); } let mut layout = layout::Layout { logo: String::new(), @@ -477,7 +490,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } (sym::html_playground_url, Some(s)) => { playground = Some(markdown::Playground { - crate_name: Some(krate.name(tcx).to_string()), + crate_name: Some(krate.name(tcx)), url: s.to_string(), }); } @@ -625,7 +638,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { write!( buf, "
\ -

Rustdoc settings

\ +

Rustdoc settings

\ \ \ Back\ @@ -637,7 +650,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { You need to enable Javascript be able to update your settings.\ \ \ - \ ", static_root_path = page.get_static_root_path(), @@ -663,7 +676,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { write!( buf, "
\ -

Rustdoc help

\ +

Rustdoc help

\ \
\ Back\ diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 36d15ec3b..4fa33e890 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -100,7 +100,7 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { #[derive(Debug)] pub(crate) struct IndexItem { pub(crate) ty: ItemType, - pub(crate) name: String, + pub(crate) name: Symbol, pub(crate) path: String, pub(crate) desc: String, pub(crate) parent: Option, @@ -364,7 +364,7 @@ impl AllTypes { } } - f.write_str("

List of all items

"); + f.write_str("

List of all items

"); // Note: print_entries does not escape the title, because we know the current set of titles // doesn't require escaping. print_entries(f, &self.structs, ItemSection::Structs); @@ -394,7 +394,7 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String { let mut ids = IdMap::default(); format!( "
\ -

About scraped examples

\ +

About scraped examples

\
\
{}
", Markdown { @@ -467,9 +467,10 @@ fn document_short( return; } if let Some(s) = item.doc_value() { - let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string(); + let (mut summary_html, has_more_content) = + MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content(); - if s.contains('\n') { + if has_more_content { let link = format!(r#" Read more
"#, assoc_href_attr(item, link, cx)); if let Some(idx) = summary_html.rfind("

") { @@ -512,7 +513,7 @@ fn document_full_inner( debug!("Doc block: =====\n{}\n=====", s); if is_collapsible { w.write_str( - "
\ + "
\ \ Expand description\ ", @@ -1342,7 +1343,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { write!( &mut out, "

Notable traits for {}

\ -
",
+                     
",
                         impl_.for_.print(cx)
                     );
                 }
@@ -1512,9 +1513,8 @@ fn render_impl(
 
         let toggled = !doc_buffer.is_empty();
         if toggled {
-            let method_toggle_class =
-                if item_type == ItemType::Method { " method-toggle" } else { "" };
-            write!(w, "
", method_toggle_class); + let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; + write!(w, "
", method_toggle_class); } match &*item.kind { clean::MethodItem(..) | clean::TyMethodItem(_) => { @@ -1730,7 +1730,7 @@ fn render_impl( close_tags.insert_str(0, "
"); write!( w, - "
", + "
", if rendering_params.toggle_open_by_default { " open" } else { "" } ); write!(w, "") @@ -2769,8 +2769,8 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { let mut work = VecDeque::new(); let mut process_path = |did: DefId| { - let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone()); - let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern); + let get_extern = || cache.external_paths.get(&did).map(|s| &s.0); + let fqp = cache.exact_paths.get(&did).or_else(get_extern); if let Some(path) = fqp { out.push(join_with_double_colon(&path)); @@ -2921,7 +2921,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite // Look for the example file in the source map if it exists, otherwise return a dummy span let file_span = (|| { let source_map = tcx.sess.source_map(); - let crate_src = tcx.sess.local_crate_source_file.as_ref()?; + let crate_src = tcx.sess.local_crate_source_file()?; let abs_crate_src = crate_src.canonicalize().ok()?; let crate_root = abs_crate_src.parent()?.parent()?; let rel_path = path.strip_prefix(crate_root).ok()?; @@ -2999,14 +2999,13 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite if it.peek().is_some() { write!( w, - "
\ + "
\ \ More examples\ \
Hide additional examples
\
\ -
\ -
" +
" ); // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could @@ -3030,7 +3029,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite write!(w, "
"); } - write!(w, "
"); + write!(w, "
"); } write!(w, ""); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index acbe3f228..f824c9e3a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -204,7 +204,7 @@ fn should_hide_fields(n_fields: usize) -> bool { fn toggle_open(w: &mut Buffer, text: impl fmt::Display) { write!( w, - "
\ + "
\ \ Show {}\ ", @@ -531,7 +531,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx)); wrap_into_item_decl(w, |w| { - wrap_item(w, "fn", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); w.reserve(header_len); write!( @@ -570,7 +570,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // Output the trait definition wrap_into_item_decl(w, |w| { - wrap_item(w, "trait", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); write!( w, @@ -732,7 +732,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: document(&mut content, cx, m, Some(t), HeadingOffset::H5); let toggled = !content.is_empty(); if toggled { - write!(w, "
"); + let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; + write!(w, "
"); } write!(w, "
", id); render_rightside(w, cx, m, t, RenderMode::Normal); @@ -1026,8 +1027,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: .chain(std::iter::once("implementors")) .collect(); if let Some(did) = it.item_id.as_def_id() && - let get_extern = { || cache.external_paths.get(&did).map(|s| s.0.clone()) } && - let Some(fqp) = cache.exact_paths.get(&did).cloned().or_else(get_extern) { + let get_extern = { || cache.external_paths.get(&did).map(|s| &s.0) } && + let Some(fqp) = cache.exact_paths.get(&did).or_else(get_extern) { js_src_path.extend(fqp[..fqp.len() - 1].iter().copied()); js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap())); } else { @@ -1050,7 +1051,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TraitAlias) { wrap_into_item_decl(w, |w| { - wrap_item(w, "trait-alias", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); write!( w, @@ -1074,7 +1075,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: & fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) { wrap_into_item_decl(w, |w| { - wrap_item(w, "opaque", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); write!( w, @@ -1098,7 +1099,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Typedef) { fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) { - wrap_item(w, "typedef", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); write!(w, "{}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx)); write!( @@ -1127,7 +1128,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) { wrap_into_item_decl(w, |w| { - wrap_item(w, "union", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); render_union(w, it, Some(&s.generics), &s.fields, "", cx); }); @@ -1192,7 +1193,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: let tcx = cx.tcx(); let count_variants = e.variants().count(); wrap_into_item_decl(w, |w| { - wrap_item(w, "enum", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); write!( w, @@ -1219,25 +1220,16 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: w.write_str(" "); let name = v.name.unwrap(); match *v.kind { - clean::VariantItem(ref var) => match var { - // FIXME(#101337): Show discriminant - clean::Variant::CLike(..) => write!(w, "{}", name), - clean::Variant::Tuple(ref s) => { + // FIXME(#101337): Show discriminant + clean::VariantItem(ref var) => match var.kind { + clean::VariantKind::CLike => write!(w, "{}", name), + clean::VariantKind::Tuple(ref s) => { write!(w, "{}(", name); print_tuple_struct_fields(w, cx, s); w.write_str(")"); } - clean::Variant::Struct(ref s) => { - render_struct( - w, - v, - None, - s.ctor_kind, - &s.fields, - " ", - false, - cx, - ); + clean::VariantKind::Struct(ref s) => { + render_struct(w, v, None, None, &s.fields, " ", false, cx); } }, _ => unreachable!(), @@ -1285,25 +1277,28 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: " rightside", ); write!(w, "

{name}", name = variant.name.unwrap()); - if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind { + + let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; + + if let clean::VariantKind::Tuple(ref s) = variant_data.kind { w.write_str("("); print_tuple_struct_fields(w, cx, s); w.write_str(")"); } w.write_str("

"); - use crate::clean::Variant; - - let heading_and_fields = match &*variant.kind { - clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)), - // Documentation on tuple variant fields is rare, so to reduce noise we only emit - // the section if at least one field is documented. - clean::VariantItem(Variant::Tuple(fields)) - if fields.iter().any(|f| f.doc_value().is_some()) => - { - Some(("Tuple Fields", fields)) + let heading_and_fields = match &variant_data.kind { + clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)), + clean::VariantKind::Tuple(fields) => { + // Documentation on tuple variant fields is rare, so to reduce noise we only emit + // the section if at least one field is documented. + if fields.iter().any(|f| f.doc_value().is_some()) { + Some(("Tuple Fields", fields)) + } else { + None + } } - _ => None, + clean::VariantKind::CLike => None, }; if let Some((heading, fields)) = heading_and_fields { @@ -1362,17 +1357,17 @@ fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &c let name = it.name.expect("proc-macros always have names"); match m.kind { MacroKind::Bang => { - wrap_item(w, "macro", |w| { + wrap_item(w, |w| { write!(w, "{}!() {{ /* proc-macro */ }}", name); }); } MacroKind::Attr => { - wrap_item(w, "attr", |w| { + wrap_item(w, |w| { write!(w, "#[{}]", name); }); } MacroKind::Derive => { - wrap_item(w, "derive", |w| { + wrap_item(w, |w| { write!(w, "#[derive({})]", name); if !m.helpers.is_empty() { w.push_str("\n{\n"); @@ -1406,7 +1401,7 @@ fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) { wrap_into_item_decl(w, |w| { - wrap_item(w, "const", |w| { + wrap_item(w, |w| { let tcx = cx.tcx(); render_attributes_in_code(w, it); @@ -1456,7 +1451,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) { wrap_into_item_decl(w, |w| { - wrap_item(w, "struct", |w| { + wrap_item(w, |w| { render_attributes_in_code(w, it); render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx); }); @@ -1509,7 +1504,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { wrap_into_item_decl(w, |w| { - wrap_item(w, "static", |w| { + wrap_item(w, |w| { render_attributes_in_code(w, it); write!( w, @@ -1526,7 +1521,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { wrap_into_item_decl(w, |w| { - wrap_item(w, "foreigntype", |w| { + wrap_item(w, |w| { w.write_str("extern {\n"); render_attributes_in_code(w, it); write!( @@ -1623,11 +1618,11 @@ where w.write_str("") } -fn wrap_item(w: &mut Buffer, item_name: &str, f: F) +fn wrap_item(w: &mut Buffer, f: F) where F: FnOnce(&mut Buffer), { - w.write_fmt(format_args!("
", item_name));
+    w.write_str(r#"
"#);
     f(w);
     w.write_str("
"); } @@ -1845,7 +1840,7 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { if item.is_non_exhaustive() { write!( w, - "
\ + "
\ {}\
", { diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 8eb9c07f8..5b0caac09 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -3,7 +3,6 @@ use std::collections::BTreeMap; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::Symbol; use serde::ser::{Serialize, SerializeStruct, Serializer}; @@ -24,18 +23,19 @@ pub(crate) fn build_index<'tcx>( tcx: TyCtxt<'tcx>, ) -> String { let mut itemid_to_pathid = FxHashMap::default(); + let mut primitives = FxHashMap::default(); let mut crate_paths = vec![]; // Attach all orphan items to the type's definition if the type // has since been learned. for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items { - if let Some(&(ref fqp, _)) = cache.paths.get(&parent) { + if let Some((fqp, _)) = cache.paths.get(&parent) { let desc = item .doc_value() .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache))); cache.search_index.push(IndexItem { ty: item.type_(), - name: item.name.unwrap().to_string(), + name: item.name.unwrap(), path: join_with_double_colon(&fqp[..fqp.len() - 1]), desc, parent: Some(parent), @@ -58,8 +58,8 @@ pub(crate) fn build_index<'tcx>( // Sort search index items. This improves the compressibility of the search index. cache.search_index.sort_unstable_by(|k1, k2| { // `sort_unstable_by_key` produces lifetime errors - let k1 = (&k1.path, &k1.name, &k1.ty, &k1.parent); - let k2 = (&k2.path, &k2.name, &k2.ty, &k2.parent); + let k1 = (&k1.path, k1.name.as_str(), &k1.ty, &k1.parent); + let k2 = (&k2.path, k2.name.as_str(), &k2.ty, &k2.parent); std::cmp::Ord::cmp(&k1, &k2) }); @@ -78,16 +78,45 @@ pub(crate) fn build_index<'tcx>( // First, on function signatures let mut search_index = std::mem::replace(&mut cache.search_index, Vec::new()); for item in search_index.iter_mut() { + fn insert_into_map( + ty: &mut RenderType, + map: &mut FxHashMap, + itemid: F, + lastpathid: &mut usize, + crate_paths: &mut Vec<(ItemType, Symbol)>, + item_type: ItemType, + path: Symbol, + ) { + match map.entry(itemid) { + Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())), + Entry::Vacant(entry) => { + let pathid = *lastpathid; + entry.insert(pathid); + *lastpathid += 1; + crate_paths.push((item_type, path)); + ty.id = Some(RenderTypeId::Index(pathid)); + } + } + } + fn convert_render_type( ty: &mut RenderType, cache: &mut Cache, itemid_to_pathid: &mut FxHashMap, + primitives: &mut FxHashMap, lastpathid: &mut usize, crate_paths: &mut Vec<(ItemType, Symbol)>, ) { if let Some(generics) = &mut ty.generics { for item in generics { - convert_render_type(item, cache, itemid_to_pathid, lastpathid, crate_paths); + convert_render_type( + item, + cache, + itemid_to_pathid, + primitives, + lastpathid, + crate_paths, + ); } } let Cache { ref paths, ref external_paths, .. } = *cache; @@ -95,33 +124,37 @@ pub(crate) fn build_index<'tcx>( assert!(ty.generics.is_some()); return; }; - let (itemid, path, item_type) = match id { + match id { RenderTypeId::DefId(defid) => { if let Some(&(ref fqp, item_type)) = paths.get(&defid).or_else(|| external_paths.get(&defid)) { - (ItemId::DefId(defid), *fqp.last().unwrap(), item_type) + insert_into_map( + ty, + itemid_to_pathid, + ItemId::DefId(defid), + lastpathid, + crate_paths, + item_type, + *fqp.last().unwrap(), + ); } else { ty.id = None; - return; } } - RenderTypeId::Primitive(primitive) => ( - ItemId::Primitive(primitive, LOCAL_CRATE), - primitive.as_sym(), - ItemType::Primitive, - ), - RenderTypeId::Index(_) => return, - }; - match itemid_to_pathid.entry(itemid) { - Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())), - Entry::Vacant(entry) => { - let pathid = *lastpathid; - entry.insert(pathid); - *lastpathid += 1; - crate_paths.push((item_type, path)); - ty.id = Some(RenderTypeId::Index(pathid)); + RenderTypeId::Primitive(primitive) => { + let sym = primitive.as_sym(); + insert_into_map( + ty, + primitives, + sym, + lastpathid, + crate_paths, + ItemType::Primitive, + sym, + ); } + RenderTypeId::Index(_) => {} } } if let Some(search_type) = &mut item.search_type { @@ -130,6 +163,7 @@ pub(crate) fn build_index<'tcx>( item, cache, &mut itemid_to_pathid, + &mut primitives, &mut lastpathid, &mut crate_paths, ); @@ -139,6 +173,7 @@ pub(crate) fn build_index<'tcx>( item, cache, &mut itemid_to_pathid, + &mut primitives, &mut lastpathid, &mut crate_paths, ); @@ -205,7 +240,7 @@ pub(crate) fn build_index<'tcx>( )?; crate_data.serialize_field( "n", - &self.items.iter().map(|item| &item.name).collect::>(), + &self.items.iter().map(|item| item.name.as_str()).collect::>(), )?; crate_data.serialize_field( "q", @@ -264,7 +299,7 @@ pub(crate) fn build_index<'tcx>( )?; crate_data.serialize_field( "p", - &self.paths.iter().map(|(it, s)| (it, s.to_string())).collect::>(), + &self.paths.iter().map(|(it, s)| (it, s.as_str())).collect::>(), )?; if has_aliases { crate_data.serialize_field("a", &self.aliases)?; @@ -322,8 +357,7 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option { match *clean_type { clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())), clean::DynTrait(ref bounds, _) => { - let path = &bounds[0].trait_; - Some(RenderTypeId::DefId(path.def_id())) + bounds.get(0).map(|b| RenderTypeId::DefId(b.trait_.def_id())) } clean::Primitive(p) => Some(RenderTypeId::Primitive(p)), clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => { @@ -539,7 +573,7 @@ fn get_fn_inputs_and_outputs<'tcx>( let decl = &func.decl; let combined_generics; - let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics { + let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_generics { match (impl_generics.is_empty(), func.generics.is_empty()) { (true, _) => (Some(impl_self), &func.generics), (_, true) => (Some(impl_self), impl_generics), diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 94d8a9fec..bc8badad3 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -1,8 +1,9 @@ +use std::cell::RefCell; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufReader}; use std::path::{Component, Path}; -use std::rc::Rc; +use std::rc::{Rc, Weak}; use itertools::Itertools; use rustc_data_structures::flock; @@ -184,23 +185,26 @@ pub(super) fn write_shared( use std::ffi::OsString; - #[derive(Debug)] + #[derive(Debug, Default)] struct Hierarchy { + parent: Weak, elem: OsString, - children: FxHashMap, - elems: FxHashSet, + children: RefCell>>, + elems: RefCell>, } impl Hierarchy { - fn new(elem: OsString) -> Hierarchy { - Hierarchy { elem, children: FxHashMap::default(), elems: FxHashSet::default() } + fn with_parent(elem: OsString, parent: &Rc) -> Self { + Self { elem, parent: Rc::downgrade(parent), ..Self::default() } } fn to_json_string(&self) -> String { - let mut subs: Vec<&Hierarchy> = self.children.values().collect(); + let borrow = self.children.borrow(); + let mut subs: Vec<_> = borrow.values().collect(); subs.sort_unstable_by(|a, b| a.elem.cmp(&b.elem)); let mut files = self .elems + .borrow() .iter() .map(|s| format!("\"{}\"", s.to_str().expect("invalid osstring conversion"))) .collect::>(); @@ -220,36 +224,52 @@ pub(super) fn write_shared( files = files ) } - } - if cx.include_sources { - let mut hierarchy = Hierarchy::new(OsString::new()); - for source in cx - .shared - .local_sources - .iter() - .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok()) - { - let mut h = &mut hierarchy; - let mut elems = source + fn add_path(self: &Rc, path: &Path) { + let mut h = Rc::clone(&self); + let mut elems = path .components() .filter_map(|s| match s { Component::Normal(s) => Some(s.to_owned()), + Component::ParentDir => Some(OsString::from("..")), _ => None, }) .peekable(); loop { let cur_elem = elems.next().expect("empty file path"); + if cur_elem == ".." { + if let Some(parent) = h.parent.upgrade() { + h = parent; + } + continue; + } if elems.peek().is_none() { - h.elems.insert(cur_elem); + h.elems.borrow_mut().insert(cur_elem); break; } else { - let e = cur_elem.clone(); - h = h.children.entry(cur_elem.clone()).or_insert_with(|| Hierarchy::new(e)); + let entry = Rc::clone( + h.children + .borrow_mut() + .entry(cur_elem.clone()) + .or_insert_with(|| Rc::new(Self::with_parent(cur_elem, &h))), + ); + h = entry; } } } + } + if cx.include_sources { + let hierarchy = Rc::new(Hierarchy::default()); + for source in cx + .shared + .local_sources + .iter() + .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok()) + { + hierarchy.add_path(source); + } + let hierarchy = Rc::try_unwrap(hierarchy).unwrap(); let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix)); let make_sources = || { let (mut all_sources, _krates) = @@ -325,7 +345,7 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; }; let content = format!( - "

List of all crates

    {}
", + "

List of all crates

    {}
", krates .iter() .map(|s| { diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 54e296959..799c497d1 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::source_map::FileName; +use std::cell::RefCell; use std::ffi::OsStr; use std::fs; use std::path::{Component, Path, PathBuf}; @@ -72,12 +73,22 @@ impl LocalSourcesCollector<'_, '_> { return; } - let mut href = String::new(); - clean_path(self.src_root, &p, false, |component| { - href.push_str(&component.to_string_lossy()); - href.push('/'); - }); + let href = RefCell::new(PathBuf::new()); + clean_path( + &self.src_root, + &p, + |component| { + href.borrow_mut().push(component); + }, + || { + href.borrow_mut().pop(); + }, + ); + let mut href = href.into_inner().to_string_lossy().to_string(); + if let Some(c) = href.as_bytes().last() && *c != b'/' { + href.push('/'); + } let mut src_fname = p.file_name().expect("source has no filename").to_os_string(); src_fname.push(".html"); href.push_str(&src_fname.to_string_lossy()); @@ -180,13 +191,28 @@ impl SourceCollector<'_, '_> { let shared = Rc::clone(&self.cx.shared); // Create the intermediate directories - let mut cur = self.dst.clone(); - let mut root_path = String::from("../../"); - clean_path(&shared.src_root, &p, false, |component| { - cur.push(component); - root_path.push_str("../"); - }); + let cur = RefCell::new(PathBuf::new()); + let root_path = RefCell::new(PathBuf::new()); + + clean_path( + &shared.src_root, + &p, + |component| { + cur.borrow_mut().push(component); + root_path.borrow_mut().push(".."); + }, + || { + cur.borrow_mut().pop(); + root_path.borrow_mut().pop(); + }, + ); + let root_path = PathBuf::from("../../").join(root_path.into_inner()); + let mut root_path = root_path.to_string_lossy(); + if let Some(c) = root_path.as_bytes().last() && *c != b'/' { + root_path += "/"; + } + let mut cur = self.dst.join(cur.into_inner()); shared.ensure_dir(&cur)?; let src_fname = p.file_name().expect("source has no filename").to_os_string(); @@ -232,11 +258,13 @@ impl SourceCollector<'_, '_> { /// Takes a path to a source file and cleans the path to it. This canonicalizes /// things like ".." to components which preserve the "top down" hierarchy of a /// static HTML tree. Each component in the cleaned path will be passed as an -/// argument to `f`. The very last component of the path (ie the file name) will -/// be passed to `f` if `keep_filename` is true, and ignored otherwise. -pub(crate) fn clean_path(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) +/// argument to `f`. The very last component of the path (ie the file name) is ignored. +/// If a `..` is encountered, the `parent` closure will be called to allow the callee to +/// handle it. +pub(crate) fn clean_path(src_root: &Path, p: &Path, mut f: F, mut parent: P) where F: FnMut(&OsStr), + P: FnMut(), { // make it relative, if possible let p = p.strip_prefix(src_root).unwrap_or(p); @@ -244,12 +272,12 @@ where let mut iter = p.components().peekable(); while let Some(c) = iter.next() { - if !keep_filename && iter.peek().is_none() { + if iter.peek().is_none() { break; } match c { - Component::ParentDir => f("up".as_ref()), + Component::ParentDir => parent(), Component::Normal(c) => f(c), _ => continue, } @@ -276,7 +304,7 @@ pub(crate) fn print_src( let mut line_numbers = Buffer::empty_from(buf); let extra; line_numbers.write_str("
");
-    let current_href = &context
+    let current_href = context
         .href_from_span(clean::Span::new(file_span), false)
         .expect("only local crates should have sources emitted");
     match source_context {
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index afcb40224..a93f60da2 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -76,8 +76,6 @@
 }
 
 * {
-	-webkit-box-sizing: border-box;
-	-moz-box-sizing: border-box;
 	box-sizing: border-box;
 }
 
@@ -110,11 +108,7 @@ body {
 	/* Then override it with `anywhere`, which is required to make non-Safari browsers break
 	   more aggressively when we want them to. */
 	overflow-wrap: anywhere;
-
-	-webkit-font-feature-settings: "kern", "liga";
-	-moz-font-feature-settings: "kern", "liga";
 	font-feature-settings: "kern", "liga";
-
 	background-color: var(--main-background-color);
 	color: var(--main-color);
 }
@@ -145,7 +139,7 @@ h1, h2, h3, h4 {
 .docblock > h6:first-child {
 	margin-top: 0;
 }
-h1.fqn {
+.main-heading h1 {
 	margin: 0;
 	padding: 0;
 	flex-grow: 1;
@@ -212,7 +206,7 @@ pre.rust a,
 .mobile-topbar h2 a,
 h1 a,
 .search-results a,
-.item-left .stab,
+.stab,
 .result-name .primitive > i, .result-name .keyword > i {
 	color: var(--main-color);
 }
@@ -259,6 +253,7 @@ h1 a,
 
 a {
 	color: var(--link-color);
+	text-decoration: none;
 }
 
 ol, ul {
@@ -322,11 +317,7 @@ main {
 	margin-right: auto;
 }
 
-.source .width-limiter {
-	max-width: unset;
-}
-
-details:not(.rustdoc-toggle) summary {
+details:not(.toggle) summary {
 	margin-bottom: .6em;
 }
 
@@ -342,26 +333,35 @@ code, pre, a.test-arrow, .code-header {
 }
 pre {
 	padding: 14px;
+	line-height: 1.5; /* https://github.com/rust-lang/rust/issues/105906 */
 }
 .item-decl pre {
 	overflow-x: auto;
 }
+/* This rule allows to have scrolling on the X axis. */
+.item-decl .type-contents-toggle {
+	contain: initial;
+}
 
 .source .content pre {
 	padding: 20px;
 }
+.rustdoc.source .example-wrap > pre.src-line-numbers  {
+	padding: 20px 0 20px 4px;
+}
 
 img {
 	max-width: 100%;
 }
 
-.source .content {
-	overflow: visible;
-}
-
 .sub-logo-container, .logo-container {
 	/* zero text boxes so that computed line height = image height exactly */
 	line-height: 0;
+	display: block;
+}
+
+.sub-logo-container {
+	margin-right: 32px;
 }
 
 .sub-logo-container > img {
@@ -374,10 +374,6 @@ img {
 	filter: var(--rust-logo-filter);
 }
 
-.sidebar, .mobile-topbar, .sidebar-menu-toggle {
-	background-color: var(--sidebar-background-color);
-}
-
 .sidebar {
 	font-size: 0.875rem;
 	flex: 0 0 200px;
@@ -396,15 +392,16 @@ img {
 	overflow-y: hidden;
 }
 
-.source .sidebar, #sidebar-toggle, #source-sidebar {
+.sidebar, .mobile-topbar, .sidebar-menu-toggle,
+#src-sidebar-toggle, #source-sidebar {
 	background-color: var(--sidebar-background-color);
 }
 
-#sidebar-toggle > button:hover, #sidebar-toggle > button:focus {
+#src-sidebar-toggle > button:hover, #src-sidebar-toggle > button:focus {
 	background-color: var(--sidebar-background-color-hover);
 }
 
-.source .sidebar > *:not(#sidebar-toggle) {
+.source .sidebar > *:not(#src-sidebar-toggle) {
 	visibility: hidden;
 }
 
@@ -413,7 +410,7 @@ img {
 	flex-basis: 300px;
 }
 
-.source-sidebar-expanded .source .sidebar > *:not(#sidebar-toggle) {
+.source-sidebar-expanded .source .sidebar > *:not(#src-sidebar-toggle) {
 	visibility: visible;
 }
 
@@ -500,11 +497,11 @@ ul.block, .block li {
 	padding-left: 24px;
 }
 
-.sidebar a, .sidebar .current {
+.sidebar a {
 	color: var(--sidebar-link-color);
 }
 .sidebar .current,
-.sidebar a:hover {
+.sidebar a:hover:not(.logo-container) {
 	background-color: var(--sidebar-current-link-background-color);
 }
 
@@ -522,11 +519,6 @@ ul.block, .block li {
 	display: none;
 }
 
-.source .content pre.rust {
-	overflow: auto;
-	padding-left: 0;
-}
-
 .rustdoc .example-wrap {
 	display: flex;
 	position: relative;
@@ -547,29 +539,26 @@ ul.block, .block li {
 .rustdoc .example-wrap > pre.example-line-numbers,
 .rustdoc .example-wrap > pre.src-line-numbers {
 	flex-grow: 0;
+	min-width: fit-content; /* prevent collapsing into nothing in truncated scraped examples */
 	overflow: initial;
 	text-align: right;
 	-webkit-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
 	user-select: none;
+	padding: 14px 8px;
+	color: var(--src-line-numbers-span-color);
 }
 
-.example-line-numbers {
-	border: 1px solid;
-	padding: 13px 8px;
-	border-top-left-radius: 5px;
-	border-bottom-left-radius: 5px;
-	border-color: var(--example-line-numbers-border-color);
+.rustdoc .example-wrap > pre.src-line-numbers {
+	padding: 14px 0;
 }
-
 .src-line-numbers a, .src-line-numbers span {
 	color: var(--src-line-numbers-span-color);
+	padding: 0 8px;
 }
 .src-line-numbers :target {
 	background-color: transparent;
 	border-right: none;
-	padding-right: 0;
+	padding: 0 8px;
 }
 .src-line-numbers .line-highlighted {
 	background-color: var(--src-line-number-highlighted-background-color);
@@ -582,12 +571,10 @@ ul.block, .block li {
 .docblock-short {
 	overflow-wrap: break-word;
 	overflow-wrap: anywhere;
-	overflow: hidden;
-	text-overflow: ellipsis;
 }
 /* Wrap non-pre code blocks (`text`) but not (```text```). */
-.docblock > :not(pre) > code,
-.docblock-short > code {
+.docblock :not(pre) > code,
+.docblock-short code {
 	white-space: pre-wrap;
 }
 
@@ -679,13 +666,6 @@ nav.sub {
 .source nav.sub {
 	margin: 0 0 15px 0;
 }
-.source .search-form {
-	margin-left: 32px;
-}
-
-a {
-	text-decoration: none;
-}
 
 .small-section-header {
 	/* fields use  tags, but should get their own lines */
@@ -693,14 +673,10 @@ a {
 	position: relative;
 }
 
-.small-section-header:hover > .anchor {
+.small-section-header:hover > .anchor, .impl:hover > .anchor,
+.trait-impl:hover > .anchor, .variant:hover > .anchor {
 	display: initial;
 }
-
-.impl:hover > .anchor, .trait-impl:hover > .anchor, .variant:hover > .anchor {
-	display: inline-block;
-	position: absolute;
-}
 .anchor {
 	display: none;
 	position: absolute;
@@ -731,7 +707,7 @@ h2.small-section-header > .anchor {
 
 /*  In most contexts we use `overflow-wrap: anywhere` to ensure that we can wrap
 	as much as needed on mobile (see
-	src/test/rustdoc-gui/type-declaration-overflow.goml for an example of why
+	tests/rustdoc-gui/type-declaration-overflow.goml for an example of why
 	this matters). The `anywhere` value means:
 
 	"Soft wrap opportunities introduced by the word break are considered when
@@ -903,10 +879,11 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	top: 100%;
 	right: 0;
 	z-index: 2;
-	display: block;
 	margin-top: 7px;
 	border-radius: 3px;
 	border: 1px solid var(--border-color);
+	background-color: var(--main-background-color);
+	color: var(--main-color);
 	--popover-arrow-offset: 11px;
 }
 
@@ -917,16 +894,12 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	right: var(--popover-arrow-offset);
 	border: solid var(--border-color);
 	border-width: 1px 1px 0 0;
+	background-color: var(--main-background-color);
 	padding: 4px;
 	transform: rotate(-45deg);
 	top: -5px;
 }
 
-.popover, .popover::before {
-	background-color: var(--main-background-color);
-	color: var(--main-color);
-}
-
 /* use larger max-width for help popover, but not for help.html */
 #help.popover {
 	max-width: 600px;
@@ -960,22 +933,29 @@ so that we can apply CSS-filters to change the arrow color in themes */
 }
 
 .item-info .stab {
-	width: fit-content;
 	/* This min-height is needed to unify the height of the stab elements because some of them
 	   have emojis.
 	*/
 	min-height: 36px;
 	display: flex;
-	align-items: center;
-	white-space: pre-wrap;
-}
-.stab {
 	padding: 3px;
 	margin-bottom: 5px;
+}
+.item-left .stab {
+	margin-left: 0.3125em;
+}
+.stab {
+	padding: 0 2px;
 	font-size: 0.875rem;
 	font-weight: normal;
 	color: var(--main-color);
 	background-color: var(--stab-background-color);
+	width: fit-content;
+	align-items: center;
+	white-space: pre-wrap;
+	border-radius: 3px;
+	display: inline-flex;
+	vertical-align: text-bottom;
 }
 
 .stab.portability > code {
@@ -988,12 +968,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	margin-right: 0.3rem;
 }
 
-/* This is to prevent the `.stab` elements to overflow the .docblock elements. */
-.docblock .stab {
-	padding: 0 0.125em;
-	margin-bottom: 0;
-}
-
 /* Black one-pixel outline around emoji shapes */
 .emoji {
 	text-shadow:
@@ -1003,16 +977,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
 		0 -1px 0 black;
 }
 
-.item-left .stab {
-	border-radius: 3px;
-	display: inline-block;
-	line-height: 1.2;
-	margin-bottom: 0;
-	margin-left: 0.3125em;
-	padding: 2px;
-	vertical-align: text-bottom;
-}
-
 .module-item.unstable,
 .import-item.unstable {
 	opacity: 0.65;
@@ -1084,6 +1048,10 @@ pre.rust .doccomment {
 	color: var(--code-highlight-doc-comment-color);
 }
 
+.rustdoc.source .example-wrap pre.rust a {
+	background: var(--codeblock-link-background);
+}
+
 .example-wrap.compile_fail,
 .example-wrap.should_panic {
 	border-left: 2px solid var(--codeblock-error-color);
@@ -1127,9 +1095,7 @@ pre.rust .doccomment {
 	top: 5px;
 }
 
-.example-wrap .tooltip::after {
-	display: none;
-	text-align: center;
+.example-wrap .tooltip:hover::after {
 	padding: 5px 3px 3px 3px;
 	border-radius: 6px;
 	margin-left: 5px;
@@ -1143,35 +1109,30 @@ pre.rust .doccomment {
 	color: var(--tooltip-color);
 }
 
-.example-wrap .tooltip::before {
+.example-wrap .tooltip:hover::before {
 	content: " ";
 	position: absolute;
 	top: 50%;
 	left: 16px;
 	margin-top: -5px;
-	display: none;
 	z-index: 1;
 	border: 5px solid transparent;
 	border-right-color: var(--tooltip-background-color);
 }
 
-.example-wrap.ignore .tooltip::after {
+.example-wrap.ignore .tooltip:hover::after {
 	content: "This example is not tested";
 }
-.example-wrap.compile_fail .tooltip::after {
+.example-wrap.compile_fail .tooltip:hover::after {
 	content: "This example deliberately fails to compile";
 }
-.example-wrap.should_panic .tooltip::after {
+.example-wrap.should_panic .tooltip:hover::after {
 	content: "This example panics";
 }
-.example-wrap.edition .tooltip::after {
+.example-wrap.edition .tooltip:hover::after {
 	content: "This code runs with edition " attr(data-edition);
 }
 
-.example-wrap .tooltip:hover::before, .example-wrap .tooltip:hover::after {
-	display: inline;
-}
-
 .example-wrap.compile_fail .tooltip,
 .example-wrap.should_panic .tooltip,
 .example-wrap.ignore .tooltip {
@@ -1253,11 +1214,11 @@ a.test-arrow:hover {
 	content: "\00a0";
 }
 
-.notable .docblock {
+.notable .content {
 	margin: 0.25em 0.5em;
 }
 
-.notable .docblock pre, .notable .docblock code {
+.notable .content pre, .notable .content code {
 	background: transparent;
 	margin: 0;
 	padding: 0;
@@ -1265,6 +1226,10 @@ a.test-arrow:hover {
 	white-space: pre-wrap;
 }
 
+.notable .content > h3:first-child {
+	margin: 0 0 5px 0;
+}
+
 .search-failed {
 	text-align: center;
 	margin-top: 20px;
@@ -1282,14 +1247,14 @@ a.test-arrow:hover {
 	margin-right: auto;
 }
 
-#titles {
+#search-tabs {
 	display: flex;
 	flex-direction: row;
 	gap: 1px;
 	margin-bottom: 4px;
 }
 
-#titles > button {
+#search-tabs button {
 	text-align: center;
 	font-size: 1.125rem;
 	border: 0;
@@ -1299,12 +1264,12 @@ a.test-arrow:hover {
 	color: inherit;
 }
 
-#titles > button > div.count {
-	display: inline-block;
+#search-tabs .count {
 	font-size: 1rem;
+	color: var(--search-tab-title-count-color);
 }
 
-#sidebar-toggle {
+#src-sidebar-toggle {
 	position: sticky;
 	top: 0;
 	left: 0;
@@ -1333,7 +1298,7 @@ a.test-arrow:hover {
 #source-sidebar div.files > a.selected {
 	background-color: var(--source-sidebar-background-selected);
 }
-#sidebar-toggle > button {
+#src-sidebar-toggle > button {
 	font-size: inherit;
 	font-weight: bold;
 	background: none;
@@ -1346,15 +1311,11 @@ a.test-arrow:hover {
 	-webkit-appearance: none;
 	opacity: 1;
 }
+
 #settings-menu, #help-button {
 	margin-left: 4px;
 	display: flex;
 }
-
-#settings-menu > a, #help-button > a, #copy-path {
-	width: 33px;
-}
-
 #settings-menu > a, #help-button > a {
 	display: flex;
 	align-items: center;
@@ -1366,6 +1327,7 @@ a.test-arrow:hover {
 	/* Rare exception to specifying font sizes in rem. Since this is acting
 	   as an icon, it's okay to specify their sizes in pixels. */
 	font-size: 20px;
+	width: 33px;
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
@@ -1381,6 +1343,7 @@ a.test-arrow:hover {
 	padding: 0;
 	padding-left: 2px;
 	border: 0;
+	width: 33px;
 }
 #copy-path > img {
 	filter: var(--copy-path-img-filter);
@@ -1409,8 +1372,7 @@ kbd {
 	vertical-align: middle;
 	border: solid 1px var(--border-color);
 	border-radius: 3px;
-	cursor: default;
-	color: var(--kbd--color);
+	color: var(--kbd-color);
 	background-color: var(--kbd-background);
 	box-shadow: inset 0 -1px 0 var(--kbd-box-shadow-color);
 }
@@ -1423,31 +1385,10 @@ details.dir-entry {
 	padding-left: 4px;
 }
 
-details.dir-entry > summary::after {
-	content: " ►";
-	position: absolute;
-	left: -15px;
-	top: 0px;
-	font-size: 80%;
-	padding: 2px 0px;
-	/* set width to cover gap between arrow and text */
-	width: 25px;
-}
-
-details[open].dir-entry > summary::after {
-	content: " ▼";
-}
-
-details.dir-entry > summary::-webkit-details-marker,
-details.dir-entry > summary::marker {
-	display: none;
-}
-
 details.dir-entry > summary {
-	margin: 0 0 0 13px;
-	list-style: none;
+	margin: 0 0 0 -4px;
+	padding: 0 0 0 4px;
 	cursor: pointer;
-	position: relative;
 }
 
 details.dir-entry div.folders, details.dir-entry div.files {
@@ -1464,7 +1405,7 @@ details.dir-entry a {
 	Unfortunately we can't yet specify contain: content or contain: strict
 	because the [-]/[+] toggles extend past the boundaries of the 
https://developer.mozilla.org/en-US/docs/Web/CSS/contain */ -details.rustdoc-toggle { +details.toggle { contain: layout; position: relative; } @@ -1472,26 +1413,26 @@ details.rustdoc-toggle { /* The hideme class is used on summary tags that contain a span with placeholder text shown only when the toggle is closed. For instance, "Expand description" or "Show methods". */ -details.rustdoc-toggle > summary.hideme { +details.toggle > summary.hideme { cursor: pointer; font-size: 1rem; } -details.rustdoc-toggle > summary { +details.toggle > summary { list-style: none; /* focus outline is shown on `::before` instead of this */ outline: none; } -details.rustdoc-toggle > summary::-webkit-details-marker, -details.rustdoc-toggle > summary::marker { +details.toggle > summary::-webkit-details-marker, +details.toggle > summary::marker { display: none; } -details.rustdoc-toggle > summary.hideme > span { +details.toggle > summary.hideme > span { margin-left: 9px; } -details.rustdoc-toggle > summary::before { +details.toggle > summary::before { background: url("toggle-plus-1092eb4930d581b0.svg") no-repeat top left; content: ""; cursor: pointer; @@ -1503,14 +1444,14 @@ details.rustdoc-toggle > summary::before { filter: var(--toggle-filter); } -details.rustdoc-toggle > summary.hideme > span, +details.toggle > summary.hideme > span, .more-examples-toggle summary, .more-examples-toggle .hide-more { color: var(--toggles-color); } /* Screen readers see the text version at the end the line. Visual readers see the icon at the start of the line, but small and transparent. */ -details.rustdoc-toggle > summary::after { +details.toggle > summary::after { content: "Expand"; overflow: hidden; width: 0; @@ -1518,17 +1459,17 @@ details.rustdoc-toggle > summary::after { position: absolute; } -details.rustdoc-toggle > summary.hideme::after { +details.toggle > summary.hideme::after { /* "hideme" toggles already have a description when they're contracted */ content: ""; } -details.rustdoc-toggle > summary:focus::before, -details.rustdoc-toggle > summary:hover::before { +details.toggle > summary:focus::before, +details.toggle > summary:hover::before { opacity: 1; } -details.rustdoc-toggle > summary:focus-visible::before { +details.toggle > summary:focus-visible::before { /* The SVG is black, and gets turned white using a filter in the dark themes. Do the same with the outline. The dotted 1px style is copied from Firefox's focus ring style. @@ -1541,17 +1482,17 @@ details.non-exhaustive { margin-bottom: 8px; } -details.rustdoc-toggle > summary.hideme::before { +details.toggle > summary.hideme::before { position: relative; } -details.rustdoc-toggle > summary:not(.hideme)::before { +details.toggle > summary:not(.hideme)::before { position: absolute; left: -24px; top: 4px; } -.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before { +.impl-items > details.toggle > summary:not(.hideme)::before { position: absolute; left: -24px; } @@ -1561,19 +1502,19 @@ details.rustdoc-toggle > summary:not(.hideme)::before { affect the layout of the items to its right. To do that, we use absolute positioning. Note that we also set position: relative on the parent
to make this work properly. */ -details.rustdoc-toggle[open] > summary.hideme { +details.toggle[open] > summary.hideme { position: absolute; } -details.rustdoc-toggle[open] > summary.hideme > span { +details.toggle[open] > summary.hideme > span { display: none; } -details.rustdoc-toggle[open] > summary::before { +details.toggle[open] > summary::before { background: url("toggle-minus-31bbd6e4c77f5c96.svg") no-repeat top left; } -details.rustdoc-toggle[open] > summary::after { +details.toggle[open] > summary::after { content: "Collapse"; } @@ -1633,7 +1574,7 @@ in storage.js /* Hide the logo and item name from the sidebar. Those are displayed in the mobile-topbar instead. */ - .sidebar .sidebar-logo, + .sidebar .logo-container, .sidebar .location { display: none; } @@ -1662,14 +1603,10 @@ in storage.js .sidebar.shown, .source-sidebar-expanded .source .sidebar, - .sidebar:focus-within { + .rustdoc:not(.source) .sidebar:focus-within { left: 0; } - .rustdoc.source > .sidebar { - width: 0; - } - .mobile-topbar h2 { padding-bottom: 0; margin: auto 0.5em auto auto; @@ -1719,30 +1656,25 @@ in storage.js margin-top: 1em; } - .content { - margin-left: 0px; - } - .anchor { display: none !important; } - #titles > button > div.count { + #search-tabs .count { display: block; } - #main-content > details.rustdoc-toggle > summary::before, - #main-content > div > details.rustdoc-toggle > summary::before { + #main-content > details.toggle > summary::before, + #main-content > div > details.toggle > summary::before { left: -11px; } - #sidebar-toggle { + #src-sidebar-toggle { position: fixed; left: 1px; top: 100px; width: 30px; font-size: 1.5rem; - text-align: center; padding: 0; z-index: 10; border-top-right-radius: 3px; @@ -1751,7 +1683,7 @@ in storage.js border-left: 0; } - .source-sidebar-expanded #sidebar-toggle { + .source-sidebar-expanded #src-sidebar-toggle { left: unset; top: unset; width: unset; @@ -1787,12 +1719,12 @@ in storage.js } /* Position of the "[-]" element. */ - details.rustdoc-toggle:not(.top-doc) > summary { + details.toggle:not(.top-doc) > summary { margin-left: 10px; } - .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before, - #main-content > details.rustdoc-toggle:not(.top-doc) > summary::before, - #main-content > div > details.rustdoc-toggle > summary::before { + .impl-items > details.toggle > summary:not(.hideme)::before, + #main-content > details.toggle:not(.top-doc) > summary::before, + #main-content > div > details.toggle > summary::before { left: -11px; } @@ -1825,8 +1757,8 @@ in storage.js @media print { nav.sidebar, nav.sub, .out-of-band, a.srclink, #copy-path, - details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before, - details.rustdoc-toggle.top-doc > summary { + details.toggle[open] > summary::before, details.toggle > summary::before, + details.toggle.top-doc > summary { display: none; } @@ -1861,13 +1793,6 @@ in storage.js height: 35px; width: 35px; } - - #sidebar-toggle { - top: 10px; - } - .source-sidebar-expanded #sidebar-toggle { - top: unset; - } } .variant, @@ -1875,23 +1800,24 @@ in storage.js .impl, #implementors-list > .docblock, .impl-items > section, -.impl-items > .rustdoc-toggle > summary, +.impl-items > .toggle > summary, .methods > section, -.methods > .rustdoc-toggle > summary +.methods > .toggle > summary { margin-bottom: 0.75em; } .variants > .docblock, -.impl-items > .rustdoc-toggle[open]:not(:last-child), -.methods > .rustdoc-toggle[open]:not(:last-child), +.implementors-toggle > .docblock, +.impl-items > .toggle[open]:not(:last-child), +.methods > .toggle[open]:not(:last-child), .implementors-toggle[open]:not(:last-child) { margin-bottom: 2em; } -#trait-implementations-list .impl-items > .rustdoc-toggle:not(:last-child), -#synthetic-implementations-list .impl-items > .rustdoc-toggle:not(:last-child), -#blanket-implementations-list .impl-items > .rustdoc-toggle:not(:last-child) { +#trait-implementations-list .impl-items > .toggle:not(:last-child), +#synthetic-implementations-list .impl-items > .toggle:not(:last-child), +#blanket-implementations-list .impl-items > .toggle:not(:last-child) { margin-bottom: 1em; } @@ -1904,9 +1830,13 @@ in storage.js font-size: 12px; position: relative; bottom: 1px; - border-width: 1px; - border-style: solid; + border: 1px solid var(--scrape-example-help-border-color); border-radius: 50px; + color: var(--scrape-example-help-color); +} +.scraped-example-list .scrape-help:hover { + border-color: var(--scrape-example-help-hover-border-color); + color: var(--scrape-example-help-hover-color); } .scraped-example { @@ -1982,21 +1912,8 @@ in storage.js bottom: 0; } -.scraped-example .code-wrapper .src-line-numbers { - margin: 0; - padding: 14px 0; -} - -.scraped-example .code-wrapper .src-line-numbers a, -.scraped-example .code-wrapper .src-line-numbers span { - padding: 0 14px; -} - .scraped-example .code-wrapper .example-wrap { - display: grid; - grid-template-columns: max-content auto; width: 100%; - overflow-x: auto; overflow-y: hidden; margin-bottom: 0; } @@ -2005,12 +1922,12 @@ in storage.js overflow-x: hidden; } -.scraped-example .code-wrapper .example-wrap pre.rust { - overflow-x: inherit; - width: inherit; - overflow-y: hidden; +.scraped-example .example-wrap .rust span.highlight { + background: var(--scrape-example-code-line-highlight); +} +.scraped-example .example-wrap .rust span.highlight.focus { + background: var(--scrape-example-code-line-highlight-focus); } - .more-examples-toggle { max-width: calc(100% + 25px); @@ -2020,25 +1937,19 @@ in storage.js .more-examples-toggle .hide-more { margin-left: 25px; - margin-bottom: 5px; cursor: pointer; } .more-scraped-examples { - margin-left: 5px; - display: flex; - flex-direction: row; -} - -.more-scraped-examples-inner { - /* 20px is width of toggle-line + toggle-line-inner */ - width: calc(100% - 20px); + margin-left: 25px; + position: relative; } .toggle-line { - align-self: stretch; - margin-right: 10px; - margin-top: 5px; + position: absolute; + top: 5px; + bottom: 0; + right: calc(100% + 10px); padding: 0 4px; cursor: pointer; } @@ -2046,18 +1957,19 @@ in storage.js .toggle-line-inner { min-width: 2px; height: 100%; + background: var(--scrape-example-toggle-line-background); } -.more-scraped-examples .scraped-example { - margin-bottom: 20px; +.toggle-line:hover .toggle-line-inner { + background: var(--scrape-example-toggle-line-hover-background); } -.more-scraped-examples .scraped-example:last-child { - margin-bottom: 0; +.more-scraped-examples .scraped-example, .example-links { + margin-top: 20px; } -.example-links a { - margin-top: 20px; +.more-scraped-examples .scraped-example:first-child { + margin-top: 5px; } .example-links ul { diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 1f6fb961e..4e9803fe2 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -1,15 +1,10 @@ .setting-line { - margin: 0.6em 0 0.6em 0.3em; + margin: 1.2em 0.6em; position: relative; } -.setting-line .choices { - display: flex; - flex-wrap: wrap; -} - .setting-line .radio-line input, -.setting-line .toggle input { +.setting-line .settings-toggle input { margin-right: 0.3em; height: 1.2rem; width: 1.2rem; @@ -22,27 +17,23 @@ .setting-line .radio-line input { border-radius: 50%; } -.setting-line .toggle input:checked { +.setting-line .settings-toggle input:checked { content: url('data:image/svg+xml,\ \ '); } .setting-line .radio-line input + span, -.setting-line .toggle span { +.setting-line .settings-toggle span { padding-bottom: 1px; } -.radio-line .setting-name { - width: 100%; -} - .radio-line .choice { margin-top: 0.1em; margin-bottom: 0.1em; min-width: 3.8em; padding: 0.3em; - display: flex; + display: inline-flex; align-items: center; cursor: pointer; } @@ -50,7 +41,7 @@ margin-left: 0.5em; } -.toggle { +.settings-toggle { position: relative; width: 100%; margin-right: 20px; @@ -59,25 +50,15 @@ cursor: pointer; } -.setting-line > .sub-settings { - padding-left: 42px; - width: 100%; - display: block; -} - -#settings .setting-line { - margin: 1.2em 0.6em; -} - .setting-line .radio-line input:checked { box-shadow: inset 0 0 0 3px var(--main-background-color); background-color: var(--settings-input-color); } -.setting-line .toggle input:checked { +.setting-line .settings-toggle input:checked { background-color: var(--settings-input-color); } .setting-line .radio-line input:focus, -.setting-line .toggle input:focus { +.setting-line .settings-toggle input:focus { box-shadow: 0 0 1px 1px var(--settings-input-color); } /* In here we combine both `:focus` and `:checked` properties. */ @@ -86,6 +67,6 @@ 0 0 2px 2px var(--settings-input-color); } .setting-line .radio-line input:hover, -.setting-line .toggle input:hover { +.setting-line .settings-toggle input:hover { border-color: var(--settings-input-color) !important; } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 0436fe013..979e7e0f9 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -45,6 +45,7 @@ Original by Dempfi (https://github.com/dempfi/ayu) --search-color: #fff; --search-results-alias-color: #c5c5c5; --search-results-grey-color: #999; + --search-tab-title-count-color: #888; --stab-background-color: #314559; --stab-code-color: #e6e1cf; --code-highlight-kw-color: #ff7733; @@ -61,7 +62,6 @@ Original by Dempfi (https://github.com/dempfi/ayu) --code-highlight-question-mark-color: #ff9011; --code-highlight-comment-color: #788797; --code-highlight-doc-comment-color: #a1ac88; - --example-line-numbers-border-color: none; --src-line-numbers-span-color: #5c6773; --src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06); --test-arrow-color: #788797; @@ -88,6 +88,15 @@ Original by Dempfi (https://github.com/dempfi/ayu) --source-sidebar-background-selected: #14191f; --source-sidebar-background-hover: #14191f; --table-alt-row-background-color: #191f26; + --codeblock-link-background: #333; + --scrape-example-toggle-line-background: #999; + --scrape-example-toggle-line-hover-background: #c5c5c5; + --scrape-example-code-line-highlight: rgb(91, 59, 1); + --scrape-example-code-line-highlight-focus: rgb(124, 75, 15); + --scrape-example-help-border-color: #aaa; + --scrape-example-help-color: #eee; + --scrape-example-help-hover-border-color: #fff; + --scrape-example-help-hover-color: #fff; } h1, h2, h3, h4 { @@ -130,7 +139,7 @@ pre, .rustdoc.source .example-wrap { .src-line-numbers .line-highlighted { color: #708090; - padding-right: 4px; + padding-right: 7px; border-right: 1px solid #ffb44c; } @@ -150,55 +159,37 @@ pre, .rustdoc.source .example-wrap { color: #c5c5c5; } -.content .item-info::before { color: #ccc; } - .sidebar h2 a, .sidebar h3 a { color: white; } -body.source .example-wrap pre.rust a { - background: #333; -} - -.module-item .stab, -.import-item .stab { - color: #000; -} .result-name .primitive > i, .result-name .keyword > i { color: #788797; } -#titles > button.selected { +#search-tabs > button.selected { background-color: #141920 !important; border-bottom: 1px solid #ffb44c !important; border-top: none; } -#titles > button:not(.selected) { +#search-tabs > button:not(.selected) { background-color: transparent !important; border: none; } -#titles > button:hover { +#search-tabs > button:hover { border-bottom: 1px solid rgba(242, 151, 24, 0.3); } -#titles > button > div.count { - color: #888; -} - /* rules that this theme does not need to set, here to satisfy the rule checker */ /* note that a lot of these are partially set in some way (meaning they are set individually rather than as a group) */ /* FIXME: these rules should be at the bottom of the file but currently must be above the `@media (max-width: 700px)` rules due to a bug in the css checker */ /* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */ -pre.rust .lifetime {} -pre.rust .kw {} -#titles > button:hover, #titles > button.selected {} -pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, pre.rust .attribute {} -pre.rust .kw-2, pre.rust .prelude-ty {} +#search-tabs > button:hover, #search-tabs > button.selected {} #settings-menu > a img { filter: invert(100); @@ -213,29 +204,9 @@ pre.rust .kw-2, pre.rust .prelude-ty {} color: #ffb44c; } -.scraped-example-list .scrape-help { - border-color: #aaa; - color: #eee; -} -.scraped-example-list .scrape-help:hover { - border-color: white; - color: white; -} -.scraped-example .example-wrap .rust span.highlight { - background: rgb(91, 59, 1); -} -.scraped-example .example-wrap .rust span.highlight.focus { - background: rgb(124, 75, 15); -} -.scraped-example:not(.expanded) .code-wrapper:before { +.scraped-example:not(.expanded) .code-wrapper::before { background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0)); } -.scraped-example:not(.expanded) .code-wrapper:after { +.scraped-example:not(.expanded) .code-wrapper::after { background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0)); } -.toggle-line-inner { - background: #999; -} -.toggle-line:hover .toggle-line-inner { - background: #c5c5c5; -} diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index d945e956c..fb15863b0 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -40,6 +40,7 @@ --search-color: #111; --search-results-alias-color: #fff; --search-results-grey-color: #ccc; + --search-tab-title-count-color: #888; --stab-background-color: #314559; --stab-code-color: #e6e1cf; --code-highlight-kw-color: #ab8ac1; @@ -56,7 +57,6 @@ --code-highlight-question-mark-color: #ff9011; --code-highlight-comment-color: #8d8d8b; --code-highlight-doc-comment-color: #8ca375; - --example-line-numbers-border-color: #4a4949; --src-line-numbers-span-color: #3b91e2; --src-line-number-highlighted-background-color: #0a042f; --test-arrow-color: #dedede; @@ -83,51 +83,30 @@ --source-sidebar-background-selected: #333; --source-sidebar-background-hover: #444; --table-alt-row-background-color: #2A2A2A; + --codeblock-link-background: #333; + --scrape-example-toggle-line-background: #999; + --scrape-example-toggle-line-hover-background: #c5c5c5; + --scrape-example-code-line-highlight: rgb(91, 59, 1); + --scrape-example-code-line-highlight-focus: rgb(124, 75, 15); + --scrape-example-help-border-color: #aaa; + --scrape-example-help-color: #eee; + --scrape-example-help-hover-border-color: #fff; + --scrape-example-help-hover-color: #fff; } -.content .item-info::before { color: #ccc; } - -body.source .example-wrap pre.rust a { - background: #333; -} - -#titles > button:not(.selected) { +#search-tabs > button:not(.selected) { background-color: #252525; border-top-color: #252525; } -#titles > button:hover, #titles > button.selected { +#search-tabs > button:hover, #search-tabs > button.selected { border-top-color: #0089ff; background-color: #353535; } -#titles > button > div.count { - color: #888; -} - -.scraped-example-list .scrape-help { - border-color: #aaa; - color: #eee; -} -.scraped-example-list .scrape-help:hover { - border-color: white; - color: white; -} -.scraped-example .example-wrap .rust span.highlight { - background: rgb(91, 59, 1); -} -.scraped-example .example-wrap .rust span.highlight.focus { - background: rgb(124, 75, 15); -} -.scraped-example:not(.expanded) .code-wrapper:before { +.scraped-example:not(.expanded) .code-wrapper::before { background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0)); } -.scraped-example:not(.expanded) .code-wrapper:after { +.scraped-example:not(.expanded) .code-wrapper::after { background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0)); } -.toggle-line-inner { - background: #999; -} -.toggle-line:hover .toggle-line-inner { - background: #c5c5c5; -} diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 58955a793..053fa78d1 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -40,6 +40,7 @@ --search-color: #000; --search-results-alias-color: #000; --search-results-grey-color: #999; + --search-tab-title-count-color: #888; --stab-background-color: #fff5d6; --stab-code-color: #000; --code-highlight-kw-color: #8959a8; @@ -56,7 +57,6 @@ --code-highlight-question-mark-color: #ff9011; --code-highlight-comment-color: #8e908c; --code-highlight-doc-comment-color: #4d4d4c; - --example-line-numbers-border-color: #c7c7c7; --src-line-numbers-span-color: #c67e2d; --src-line-number-highlighted-background-color: #fdffd3; --test-arrow-color: #f5f5f5; @@ -80,51 +80,30 @@ --source-sidebar-background-selected: #fff; --source-sidebar-background-hover: #e0e0e0; --table-alt-row-background-color: #F5F5F5; + --codeblock-link-background: #eee; + --scrape-example-toggle-line-background: #ccc; + --scrape-example-toggle-line-hover-background: #999; + --scrape-example-code-line-highlight: #fcffd6; + --scrape-example-code-line-highlight-focus: #f6fdb0; + --scrape-example-help-border-color: #555; + --scrape-example-help-color: #333; + --scrape-example-help-hover-border-color: #000; + --scrape-example-help-hover-color: #000; } -.content .item-info::before { color: #ccc; } - -body.source .example-wrap pre.rust a { - background: #eee; -} - -#titles > button:not(.selected) { +#search-tabs > button:not(.selected) { background-color: #e6e6e6; border-top-color: #e6e6e6; } -#titles > button:hover, #titles > button.selected { +#search-tabs > button:hover, #search-tabs > button.selected { background-color: #ffffff; border-top-color: #0089ff; } -#titles > button > div.count { - color: #888; -} - -.scraped-example-list .scrape-help { - border-color: #555; - color: #333; -} -.scraped-example-list .scrape-help:hover { - border-color: black; - color: black; -} -.scraped-example .example-wrap .rust span.highlight { - background: #fcffd6; -} -.scraped-example .example-wrap .rust span.highlight.focus { - background: #f6fdb0; -} -.scraped-example:not(.expanded) .code-wrapper:before { +.scraped-example:not(.expanded) .code-wrapper::before { background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)); } -.scraped-example:not(.expanded) .code-wrapper:after { +.scraped-example:not(.expanded) .code-wrapper::after { background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)); } -.toggle-line-inner { - background: #ccc; -} -.toggle-line:hover .toggle-line-inner { - background: #999; -} diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 152116089..604ab147f 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -184,7 +184,6 @@ function browserSupportsHistoryApi() { function loadCss(cssUrl) { const link = document.createElement("link"); link.href = cssUrl; - link.type = "text/css"; link.rel = "stylesheet"; document.getElementsByTagName("head")[0].appendChild(link); } @@ -391,7 +390,8 @@ function loadCss(cssUrl) { } if (document.activeElement.tagName === "INPUT" && - document.activeElement.type !== "checkbox") { + document.activeElement.type !== "checkbox" && + document.activeElement.type !== "radio") { switch (getVirtualKey(ev)) { case "Escape": handleEscape(ev); @@ -527,7 +527,7 @@ function loadCss(cssUrl) { } let currentNbImpls = implementors.getElementsByClassName("impl").length; - const traitName = document.querySelector("h1.fqn > .trait").textContent; + const traitName = document.querySelector(".main-heading h1 > .trait").textContent; const baseIdName = "impl-" + traitName + "-"; const libs = Object.getOwnPropertyNames(imp); // We don't want to include impls from this JS file, when the HTML already has them. @@ -564,7 +564,7 @@ function loadCss(cssUrl) { onEachLazy(code.getElementsByTagName("a"), elem => { const href = elem.getAttribute("href"); - if (href && href.indexOf("http") !== 0) { + if (href && !/^(?:[a-z+]+:)?\/\//.test(href)) { elem.setAttribute("href", window.rootPath + href); } }); @@ -621,7 +621,7 @@ function loadCss(cssUrl) { function expandAllDocs() { const innerToggle = document.getElementById(toggleAllDocsId); removeClass(innerToggle, "will-expand"); - onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { + onEachLazy(document.getElementsByClassName("toggle"), e => { if (!hasClass(e, "type-contents-toggle") && !hasClass(e, "more-examples-toggle")) { e.open = true; } @@ -633,7 +633,7 @@ function loadCss(cssUrl) { function collapseAllDocs() { const innerToggle = document.getElementById(toggleAllDocsId); addClass(innerToggle, "will-expand"); - onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { + onEachLazy(document.getElementsByClassName("toggle"), e => { if (e.parentNode.id !== "implementations-list" || (!hasClass(e, "implementors-toggle") && !hasClass(e, "type-contents-toggle")) @@ -681,7 +681,7 @@ function loadCss(cssUrl) { setImplementorsTogglesOpen("blanket-implementations-list", false); } - onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { + onEachLazy(document.getElementsByClassName("toggle"), e => { if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) { e.open = true; } @@ -804,29 +804,22 @@ function loadCss(cssUrl) { } }); - function handleClick(id, f) { - const elem = document.getElementById(id); - if (elem) { - elem.addEventListener("click", f); - } + const mainElem = document.getElementById(MAIN_ID); + if (mainElem) { + mainElem.addEventListener("click", hideSidebar); } - handleClick(MAIN_ID, () => { - hideSidebar(); - }); - onEachLazy(document.getElementsByTagName("a"), el => { + onEachLazy(document.querySelectorAll("a[href^='#']"), el => { // For clicks on internal links ( tags with a hash property), we expand the section we're // jumping to *before* jumping there. We can't do this in onHashChange, because it changes // the height of the document so we wind up scrolled to the wrong place. - if (el.hash) { - el.addEventListener("click", () => { - expandSection(el.hash.slice(1)); - hideSidebar(); - }); - } + el.addEventListener("click", () => { + expandSection(el.hash.slice(1)); + hideSidebar(); + }); }); - onEachLazy(document.querySelectorAll(".rustdoc-toggle > summary:not(.hideme)"), el => { + onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => { el.addEventListener("click", e => { if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") { e.preventDefault(); @@ -850,7 +843,7 @@ function loadCss(cssUrl) { window.hideAllModals(false); const ty = e.getAttribute("data-ty"); const wrapper = document.createElement("div"); - wrapper.innerHTML = "
" + window.NOTABLE_TRAITS[ty] + "
"; + wrapper.innerHTML = "
" + window.NOTABLE_TRAITS[ty] + "
"; wrapper.className = "notable popover"; const focusCatcher = document.createElement("div"); focusCatcher.setAttribute("tabindex", "0"); @@ -948,7 +941,7 @@ function loadCss(cssUrl) { return; } if (!this.NOTABLE_FORCE_VISIBLE && - !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) { + !elemIsInParent(ev.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) { hideNotable(true); } }; @@ -1043,9 +1036,6 @@ function loadCss(cssUrl) { help_button.appendChild(container); container.onblur = helpBlurHandler; - container.onclick = event => { - event.preventDefault(); - }; help_button.onblur = helpBlurHandler; help_button.children[0].onblur = helpBlurHandler; } @@ -1093,6 +1083,9 @@ function loadCss(cssUrl) { * Show the help popup menu. */ function showHelp() { + // Prevent `blur` events from being dispatched as a result of closing + // other modals. + getHelpButton().querySelector("a").focus(); const menu = getHelpMenu(true); if (menu.style.display === "none") { window.hideAllModals(); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 23ae4e970..88592fa0c 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -49,7 +49,7 @@ function printTab(nb) { let iter = 0; let foundCurrentTab = false; let foundCurrentResultSet = false; - onEachLazy(document.getElementById("titles").childNodes, elem => { + onEachLazy(document.getElementById("search-tabs").childNodes, elem => { if (nb === iter) { addClass(elem, "selected"); foundCurrentTab = true; @@ -781,7 +781,29 @@ function initSearch(rawSearchIndex) { return a - b; } - // Sort by non levenshtein results and then levenshtein results by the distance + // sort by index of keyword in item name (no literal occurrence goes later) + a = (aaa.index < 0); + b = (bbb.index < 0); + if (a !== b) { + return a - b; + } + + // Sort by distance in the path part, if specified + // (less changes required to match means higher rankings) + a = aaa.path_lev; + b = bbb.path_lev; + if (a !== b) { + return a - b; + } + + // (later literal occurrence, if any, goes later) + a = aaa.index; + b = bbb.index; + if (a !== b) { + return a - b; + } + + // Sort by distance in the name part, the last part of the path // (less changes required to match means higher rankings) a = (aaa.lev); b = (bbb.lev); @@ -810,19 +832,6 @@ function initSearch(rawSearchIndex) { return (a > b ? +1 : -1); } - // sort by index of keyword in item name (no literal occurrence goes later) - a = (aaa.index < 0); - b = (bbb.index < 0); - if (a !== b) { - return a - b; - } - // (later literal occurrence, if any, goes later) - a = aaa.index; - b = bbb.index; - if (a !== b) { - return a - b; - } - // special precedence for primitive and keyword pages if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) || (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) { @@ -1230,15 +1239,19 @@ function initSearch(rawSearchIndex) { * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element. * * `index` is an `integer`` used to sort by the position of the word in the item's name. * * `lev` is the main metric used to sort the search results. + * * `path_lev` is zero if a single-component search query is used, otherwise it's the + * distance computed for everything other than the last path component. * * @param {Results} results * @param {string} fullId * @param {integer} id * @param {integer} index * @param {integer} lev + * @param {integer} path_lev */ - function addIntoResults(results, fullId, id, index, lev) { - if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) { + function addIntoResults(results, fullId, id, index, lev, path_lev) { + const inBounds = lev <= MAX_LEV_DISTANCE || index !== -1; + if (lev === 0 || (!parsedQuery.literalSearch && inBounds)) { if (results[fullId] !== undefined) { const result = results[fullId]; if (result.dontValidate || result.lev <= lev) { @@ -1250,6 +1263,7 @@ function initSearch(rawSearchIndex) { index: index, dontValidate: parsedQuery.literalSearch, lev: lev, + path_lev: path_lev, }; } } @@ -1280,68 +1294,68 @@ function initSearch(rawSearchIndex) { if (!row || (filterCrates !== null && row.crate !== filterCrates)) { return; } - let lev, lev_add = 0, index = -1; + let lev, index = -1, path_lev = 0; const fullId = row.id; + const searchWord = searchWords[pos]; const in_args = findArg(row, elem, parsedQuery.typeFilter); const returned = checkReturned(row, elem, parsedQuery.typeFilter); - addIntoResults(results_in_args, fullId, pos, index, in_args); - addIntoResults(results_returned, fullId, pos, index, returned); + // path_lev is 0 because no parent path information is currently stored + // in the search index + addIntoResults(results_in_args, fullId, pos, -1, in_args, 0); + addIntoResults(results_returned, fullId, pos, -1, returned, 0); if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) { return; } - const searchWord = searchWords[pos]; - if (parsedQuery.literalSearch) { - if (searchWord === elem.name) { - addIntoResults(results_others, fullId, pos, -1, 0); - } - return; + const row_index = row.normalizedName.indexOf(elem.pathLast); + const word_index = searchWord.indexOf(elem.pathLast); + + // lower indexes are "better" matches + // rank based on the "best" match + if (row_index === -1) { + index = word_index; + } else if (word_index === -1) { + index = row_index; + } else if (word_index < row_index) { + index = word_index; + } else { + index = row_index; } // No need to check anything else if it's a "pure" generics search. if (elem.name.length === 0) { if (row.type !== null) { lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1); - addIntoResults(results_others, fullId, pos, index, lev); + // path_lev is 0 because we know it's empty + addIntoResults(results_others, fullId, pos, index, lev, 0); } return; } if (elem.fullPath.length > 1) { - lev = checkPath(elem.pathWithoutLast, row); - if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) { + path_lev = checkPath(elem.pathWithoutLast, row); + if (path_lev > MAX_LEV_DISTANCE) { return; - } else if (lev > 0) { - lev_add = lev / 10; } } - if (searchWord.indexOf(elem.pathLast) > -1 || - row.normalizedName.indexOf(elem.pathLast) > -1 - ) { - index = row.normalizedName.indexOf(elem.pathLast); - } - lev = levenshtein(searchWord, elem.pathLast); - if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) { - if (elem.pathLast.length < 6) { - lev = 1; - } else { - lev = 0; + if (parsedQuery.literalSearch) { + if (searchWord === elem.name) { + addIntoResults(results_others, fullId, pos, index, 0, path_lev); } - } - lev += lev_add; - if (lev > MAX_LEV_DISTANCE) { return; - } else if (index !== -1 && elem.fullPath.length < 2) { - lev -= 1; } - if (lev < 0) { - lev = 0; + + lev = levenshtein(searchWord, elem.pathLast); + + if (index === -1 && lev + path_lev > MAX_LEV_DISTANCE) { + return; } - addIntoResults(results_others, fullId, pos, index, lev); + + addIntoResults(results_others, fullId, pos, index, lev, path_lev); } /** @@ -1386,7 +1400,7 @@ function initSearch(rawSearchIndex) { return; } const lev = Math.round(totalLev / nbLev); - addIntoResults(results, row.id, pos, 0, lev); + addIntoResults(results, row.id, pos, 0, lev, 0); } function innerRunQuery() { @@ -1490,7 +1504,7 @@ function initSearch(rawSearchIndex) { function focusSearchResult() { const target = searchState.focusedByTab[searchState.currentTab] || document.querySelectorAll(".search-results.active a").item(0) || - document.querySelectorAll("#titles > button").item(searchState.currentTab); + document.querySelectorAll("#search-tabs button").item(searchState.currentTab); searchState.focusedByTab[searchState.currentTab] = null; if (target) { target.focus(); @@ -1645,9 +1659,9 @@ function initSearch(rawSearchIndex) { function makeTabHeader(tabNb, text, nbElems) { if (searchState.currentTab === tabNb) { return ""; + " (" + nbElems + ")"; } - return ""; + return ""; } /** @@ -1712,12 +1726,12 @@ function initSearch(rawSearchIndex) { let output = `

Results${crates}

`; if (results.query.error !== null) { output += `

Query parser error: "${results.query.error}".

`; - output += "
" + + output += "
" + makeTabHeader(0, "In Names", ret_others[1]) + "
"; currentTab = 0; } else if (results.query.foundElems <= 1 && results.query.returned.length === 0) { - output += "
" + + output += "
" + makeTabHeader(0, "In Names", ret_others[1]) + makeTabHeader(1, "In Parameters", ret_in_args[1]) + makeTabHeader(2, "In Return Types", ret_returned[1]) + @@ -1727,7 +1741,7 @@ function initSearch(rawSearchIndex) { results.query.elems.length === 0 ? "In Function Return Types" : results.query.returned.length === 0 ? "In Function Parameters" : "In Function Signatures"; - output += "
" + + output += "
" + makeTabHeader(0, signatureTabTitle, ret_others[1]) + "
"; currentTab = 0; @@ -1747,7 +1761,7 @@ function initSearch(rawSearchIndex) { search.appendChild(resultsElem); // Reset focused elements. searchState.showResults(search); - const elems = document.getElementById("titles").childNodes; + const elems = document.getElementById("search-tabs").childNodes; searchState.focusedByTab = []; let i = 0; for (const elem of elems) { diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 589bfc793..84df1b7d3 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -135,7 +135,7 @@ // This is a select setting. output += `\
- ${setting_name} +
${setting_name}
`; onEach(setting["options"], option => { const checked = option === setting["default"] ? " checked" : ""; @@ -150,10 +150,10 @@ }); output += "
"; } else { - // This is a toggle. + // This is a checkbox toggle. const checked = setting["default"] === true ? " checked" : ""; output += `\ -
{#- -#} {%- endif -%} {#- -#}
{#- -#} -
{#- -#} + {%- if page.css_class != "source" -%}
{%- endif -%} {#- -#}
{{- content|safe -}}
{#- -#} -
{#- -#} + {%- if page.css_class != "source" -%}
{%- endif -%}
{#- -#} {{- layout.external_html.after_content|safe -}}
{#- -#} -

{#- -#} +

{#- -#} {{-typ-}} {#- The breadcrumbs of the item path, like std::string -#} {%- for component in path_components -%} -- cgit v1.2.3