diff options
Diffstat (limited to 'src/librustdoc/html')
22 files changed, 907 insertions, 999 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index b499e186c..92e7f2739 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -331,7 +331,8 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( bounds_display.truncate(bounds_display.len() - " + ".len()); write!(f, "{}: {bounds_display}", lifetime.print()) } - clean::WherePredicate::EqPredicate { lhs, rhs } => { + // FIXME(fmease): Render bound params. + clean::WherePredicate::EqPredicate { lhs, rhs, bound_params: _ } => { if f.alternate() { write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx)) } else { @@ -611,7 +612,7 @@ fn generate_macro_def_id_path( }; if path.len() < 2 { // The minimum we can have is the crate name followed by the macro name. If shorter, then - // it means that that `relative` was empty, which is an error. + // it means that `relative` was empty, which is an error. debug!("macro path cannot be empty!"); return Err(HrefError::NotInExternalCache); } @@ -658,7 +659,7 @@ pub(crate) fn href_with_root_path( } if !did.is_local() - && !cache.access_levels.is_public(did) + && !cache.effective_visibilities.is_directly_public(did) && !cache.document_private && !cache.primitive_locations.values().any(|&id| id == did) { @@ -1010,15 +1011,25 @@ fn fmt_type<'cx>( write!(f, "]") } }, - clean::Array(ref t, ref n) => { - primitive_link(f, PrimitiveType::Array, "[", cx)?; - fmt::Display::fmt(&t.print(cx), f)?; - if f.alternate() { - primitive_link(f, PrimitiveType::Array, &format!("; {}]", n), cx) - } else { - primitive_link(f, PrimitiveType::Array, &format!("; {}]", Escape(n)), cx) + clean::Array(ref t, ref n) => match **t { + clean::Generic(name) if !f.alternate() => primitive_link( + f, + PrimitiveType::Array, + &format!("[{name}; {n}]", n = Escape(n)), + cx, + ), + _ => { + write!(f, "[")?; + fmt::Display::fmt(&t.print(cx), f)?; + if f.alternate() { + write!(f, "; {n}")?; + } else { + write!(f, "; ")?; + primitive_link(f, PrimitiveType::Array, &format!("{n}", n = Escape(n)), cx)?; + } + write!(f, "]") } - } + }, clean::RawPointer(m, ref t) => { let m = match m { hir::Mutability::Mut => "mut", diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 8922bf377..5e28204b2 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -7,19 +7,18 @@ use crate::clean::PrimitiveType; use crate::html::escape::Escape; -use crate::html::render::Context; +use crate::html::render::{Context, LinkFromSrc}; use std::collections::VecDeque; use std::fmt::{Display, Write}; use rustc_data_structures::fx::FxHashMap; -use rustc_lexer::{LiteralKind, TokenKind}; +use rustc_lexer::{Cursor, LiteralKind, TokenKind}; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Span, DUMMY_SP}; use super::format::{self, Buffer}; -use super::render::LinkFromSrc; /// 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> { @@ -408,15 +407,16 @@ enum Highlight<'a> { struct TokenIter<'a> { src: &'a str, + cursor: Cursor<'a>, } impl<'a> Iterator for TokenIter<'a> { type Item = (TokenKind, &'a str); fn next(&mut self) -> Option<(TokenKind, &'a str)> { - if self.src.is_empty() { + let token = self.cursor.advance_token(); + if token.kind == TokenKind::Eof { return None; } - let token = rustc_lexer::first_token(self.src); let (text, rest) = self.src.split_at(token.len as usize); self.src = rest; Some((token.kind, text)) @@ -525,7 +525,7 @@ impl<'a> Classifier<'a> { /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code /// file span which will be used later on by the `span_correspondance_map`. fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> { - let tokens = PeekIter::new(TokenIter { src }); + let tokens = PeekIter::new(TokenIter { src, cursor: Cursor::new(src) }); let decorations = decoration_info.map(Decorations::new); Classifier { tokens, @@ -850,6 +850,7 @@ impl<'a> Classifier<'a> { Class::Ident(self.new_span(before, text)) } TokenKind::Lifetime { .. } => Class::Lifetime, + TokenKind::Eof => panic!("Eof in advance"), }; // Anything that didn't return above is the simple case where we the // class just spans a single token, so we can use the `string` method. diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 43d07d4a5..1e1c657b0 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -111,14 +111,9 @@ pub(crate) struct MarkdownWithToc<'a>( pub(crate) Edition, pub(crate) &'a Option<Playground>, ); -/// A tuple struct like `Markdown` that renders the markdown escaping HTML tags. -pub(crate) struct MarkdownHtml<'a>( - pub(crate) &'a str, - pub(crate) &'a mut IdMap, - pub(crate) ErrorCodes, - pub(crate) Edition, - pub(crate) &'a Option<Playground>, -); +/// A tuple struct like `Markdown` that renders the markdown escaping HTML tags +/// and includes no paragraph tags. +pub(crate) struct MarkdownItemInfo<'a>(pub(crate) &'a str, pub(crate) &'a mut IdMap); /// A tuple struct like `Markdown` that renders only the first paragraph. pub(crate) struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [RenderedLink]); @@ -251,8 +246,6 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { _ => {} } } - let lines = origtext.lines().filter_map(|l| map_line(l).for_html()); - let text = lines.intersperse("\n".into()).collect::<String>(); let parse_result = match kind { CodeBlockKind::Fenced(ref lang) => { @@ -265,7 +258,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { <pre class=\"language-{}\"><code>{}</code></pre>\ </div>", lang, - Escape(&text), + Escape(&origtext), ) .into(), )); @@ -275,6 +268,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { CodeBlockKind::Indented => Default::default(), }; + let lines = origtext.lines().filter_map(|l| map_line(l).for_html()); + let text = lines.intersperse("\n".into()).collect::<String>(); + compile_fail = parse_result.compile_fail; should_panic = parse_result.should_panic; ignore = parse_result.ignore; @@ -818,11 +814,8 @@ impl<'tcx> ExtraInfo<'tcx> { crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, hir_id, self.sp, - |lint| { - let mut diag = lint.build(msg); - diag.help(help); - diag.emit(); - }, + msg, + |lint| lint.help(help), ); } } @@ -1072,9 +1065,9 @@ impl MarkdownWithToc<'_> { } } -impl MarkdownHtml<'_> { +impl MarkdownItemInfo<'_> { pub(crate) fn into_string(self) -> String { - let MarkdownHtml(md, ids, codes, edition, playground) = self; + let MarkdownItemInfo(md, ids) = self; // This is actually common enough to special-case if md.is_empty() { @@ -1093,7 +1086,9 @@ impl MarkdownHtml<'_> { let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1); let p = Footnotes::new(p); let p = TableWrapper::new(p.map(|(ev, _)| ev)); - let p = CodeBlocks::new(p, codes, edition, playground); + let p = p.filter(|event| { + !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph)) + }); html::push_html(&mut s, p); s @@ -1439,6 +1434,7 @@ static DEFAULT_ID_MAP: Lazy<FxHashMap<Cow<'static, str>, usize>> = Lazy::new(|| fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { let mut map = FxHashMap::default(); // This is the list of IDs used in Javascript. + map.insert("help".into(), 1); map.insert("settings".into(), 1); map.insert("not-displayed".into(), 1); map.insert("alternative-display".into(), 1); diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 5c0bf0ed9..68b31a6ee 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -1,5 +1,5 @@ use super::{find_testable_code, plain_text_summary, short_markdown_summary}; -use super::{ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, Markdown, MarkdownHtml}; +use super::{ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, Markdown, MarkdownItemInfo}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; #[test] @@ -279,14 +279,13 @@ fn test_plain_text_summary() { fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let mut idmap = IdMap::new(); - let output = - MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); + let output = MarkdownItemInfo(input, &mut idmap).into_string(); assert_eq!(output, expect, "original: {}", input); } - t("`Struct<'a, T>`", "<p><code>Struct<'a, T></code></p>\n"); - t("Struct<'a, T>", "<p>Struct<’a, T></p>\n"); - t("Struct<br>", "<p>Struct<br></p>\n"); + t("`Struct<'a, T>`", "<code>Struct<'a, T></code>"); + t("Struct<'a, T>", "Struct<’a, T>"); + t("Struct<br>", "Struct<br>"); } #[test] @@ -310,3 +309,40 @@ fn test_find_testable_code_line() { t("```rust\n```\n```rust\n```", &[1, 3]); t("```rust\n```\n ```rust\n```", &[1, 3]); } + +#[test] +fn test_ascii_with_prepending_hashtag() { + fn t(input: &str, expect: &str) { + let mut map = IdMap::new(); + let output = Markdown { + content: input, + links: &[], + ids: &mut map, + error_codes: ErrorCodes::Yes, + edition: DEFAULT_EDITION, + playground: &None, + heading_offset: HeadingOffset::H2, + } + .into_string(); + assert_eq!(output, expect, "original: {}", input); + } + + t( + r#"```ascii +#..#.####.#....#.....##.. +#..#.#....#....#....#..#. +####.###..#....#....#..#. +#..#.#....#....#....#..#. +#..#.#....#....#....#..#. +#..#.####.####.####..##.. +```"#, + "<div class=\"example-wrap\"><pre class=\"language-ascii\"><code>\ +#..#.####.#....#.....##.. +#..#.#....#....#....#..#. +####.###..#....#....#..#. +#..#.#....#....#....#..#. +#..#.#....#....#....#..#. +#..#.####.####.####..##.. +</code></pre></div>", + ); +} diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 62def4a94..5733d1f9c 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -17,8 +17,8 @@ use super::print_item::{full_path, item_path, print_item}; use super::search_index::build_index; use super::write_shared::write_shared; use super::{ - collect_spans_and_sources, print_sidebar, scrape_examples_help, AllTypes, LinkFromSrc, NameDoc, - StylePath, BASIC_KEYWORDS, + collect_spans_and_sources, print_sidebar, scrape_examples_help, sidebar_module_like, AllTypes, + LinkFromSrc, NameDoc, StylePath, BASIC_KEYWORDS, }; use crate::clean::{self, types::ExternalLocation, ExternalCrate}; @@ -430,7 +430,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { extension_css, resource_suffix, static_root_path, - unstable_features, generate_redirect_map, show_type_layout, generate_link_to_definition, @@ -511,7 +510,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { resource_suffix, static_root_path, fs: DocFS::new(sender), - codes: ErrorCodes::from(unstable_features.is_nightly_build()), + codes: ErrorCodes::from(options.unstable_features.is_nightly_build()), playground, all: RefCell::new(AllTypes::new()), errors: receiver, @@ -581,6 +580,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let crate_name = self.tcx().crate_name(LOCAL_CRATE); let final_file = self.dst.join(crate_name.as_str()).join("all.html"); let settings_file = self.dst.join("settings.html"); + let help_file = self.dst.join("help.html"); let scrape_examples_help_file = self.dst.join("scrape-examples-help.html"); let mut root_path = self.dst.to_str().expect("invalid path").to_owned(); @@ -597,16 +597,24 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { keywords: BASIC_KEYWORDS, resource_suffix: &shared.resource_suffix, }; - let sidebar = if shared.cache.crate_version.is_some() { - format!("<h2 class=\"location\">Crate {}</h2>", crate_name) - } else { - String::new() - }; let all = shared.all.replace(AllTypes::new()); + let mut sidebar = Buffer::html(); + if shared.cache.crate_version.is_some() { + write!(sidebar, "<h2 class=\"location\">Crate {}</h2>", crate_name) + }; + + let mut items = Buffer::html(); + sidebar_module_like(&mut items, all.item_sections()); + if !items.is_empty() { + sidebar.push_str("<div class=\"sidebar-elems\">"); + sidebar.push_buffer(items); + sidebar.push_str("</div>"); + } + let v = layout::render( &shared.layout, &page, - sidebar, + sidebar.into_inner(), |buf: &mut Buffer| all.print(buf), &shared.style_files, ); @@ -626,9 +634,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { write!( buf, "<div class=\"main-heading\">\ - <h1 class=\"fqn\">\ - <span class=\"in-band\">Rustdoc settings</span>\ - </h1>\ + <h1 class=\"fqn\">Rustdoc settings</h1>\ <span class=\"out-of-band\">\ <a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\ Back\ @@ -651,6 +657,39 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { ); shared.fs.write(settings_file, v)?; + // Generating help page. + page.title = "Rustdoc help"; + page.description = "Documentation for Rustdoc"; + page.root_path = "./"; + + let sidebar = "<h2 class=\"location\">Help</h2><div class=\"sidebar-elems\"></div>"; + let v = layout::render( + &shared.layout, + &page, + sidebar, + |buf: &mut Buffer| { + write!( + buf, + "<div class=\"main-heading\">\ + <h1 class=\"fqn\">Rustdoc help</h1>\ + <span class=\"out-of-band\">\ + <a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\ + Back\ + </a>\ + </span>\ + </div>\ + <noscript>\ + <section>\ + <p>You need to enable Javascript to use keyboard commands or search.</p>\ + <p>For more information, browse the <a href=\"https://doc.rust-lang.org/rustdoc/\">rustdoc handbook</a>.</p>\ + </section>\ + </noscript>", + ) + }, + &shared.style_files, + ); + shared.fs.write(help_file, v)?; + if shared.layout.scrape_examples_extension { page.title = "About scraped examples"; page.description = "How the scraped examples feature works in Rustdoc"; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 1e6f20d2b..96c57c8c8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -74,7 +74,9 @@ use crate::html::format::{ PrintWithSpace, }; use crate::html::highlight; -use crate::html::markdown::{HeadingOffset, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine}; +use crate::html::markdown::{ + HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, +}; use crate::html::sources; use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD; use crate::scrape_examples::{CallData, CallLocation}; @@ -239,8 +241,8 @@ struct AllTypes { opaque_tys: FxHashSet<ItemEntry>, statics: FxHashSet<ItemEntry>, constants: FxHashSet<ItemEntry>, - attributes: FxHashSet<ItemEntry>, - derives: FxHashSet<ItemEntry>, + attribute_macros: FxHashSet<ItemEntry>, + derive_macros: FxHashSet<ItemEntry>, trait_aliases: FxHashSet<ItemEntry>, } @@ -259,8 +261,8 @@ impl AllTypes { opaque_tys: new_set(100), statics: new_set(100), constants: new_set(100), - attributes: new_set(100), - derives: new_set(100), + attribute_macros: new_set(100), + derive_macros: new_set(100), trait_aliases: new_set(100), } } @@ -283,27 +285,75 @@ impl AllTypes { ItemType::OpaqueTy => self.opaque_tys.insert(ItemEntry::new(new_url, name)), ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)), ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)), - ItemType::ProcAttribute => self.attributes.insert(ItemEntry::new(new_url, name)), - ItemType::ProcDerive => self.derives.insert(ItemEntry::new(new_url, name)), + ItemType::ProcAttribute => { + self.attribute_macros.insert(ItemEntry::new(new_url, name)) + } + ItemType::ProcDerive => self.derive_macros.insert(ItemEntry::new(new_url, name)), ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)), _ => true, }; } } -} -impl AllTypes { + fn item_sections(&self) -> FxHashSet<ItemSection> { + let mut sections = FxHashSet::default(); + + if !self.structs.is_empty() { + sections.insert(ItemSection::Structs); + } + if !self.enums.is_empty() { + sections.insert(ItemSection::Enums); + } + if !self.unions.is_empty() { + sections.insert(ItemSection::Unions); + } + if !self.primitives.is_empty() { + sections.insert(ItemSection::PrimitiveTypes); + } + if !self.traits.is_empty() { + sections.insert(ItemSection::Traits); + } + if !self.macros.is_empty() { + sections.insert(ItemSection::Macros); + } + if !self.functions.is_empty() { + sections.insert(ItemSection::Functions); + } + if !self.typedefs.is_empty() { + sections.insert(ItemSection::TypeDefinitions); + } + if !self.opaque_tys.is_empty() { + sections.insert(ItemSection::OpaqueTypes); + } + if !self.statics.is_empty() { + sections.insert(ItemSection::Statics); + } + if !self.constants.is_empty() { + sections.insert(ItemSection::Constants); + } + if !self.attribute_macros.is_empty() { + sections.insert(ItemSection::AttributeMacros); + } + if !self.derive_macros.is_empty() { + sections.insert(ItemSection::DeriveMacros); + } + if !self.trait_aliases.is_empty() { + sections.insert(ItemSection::TraitAliases); + } + + sections + } + fn print(self, f: &mut Buffer) { - fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &str) { + fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, kind: ItemSection) { if !e.is_empty() { let mut e: Vec<&ItemEntry> = e.iter().collect(); e.sort(); write!( f, - "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">", - title.replace(' ', "-"), // IDs cannot contain whitespaces. - title, - class + "<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">", + id = kind.id(), + title = kind.name(), ); for s in e.iter() { @@ -314,27 +364,23 @@ impl AllTypes { } } - f.write_str( - "<h1 class=\"fqn\">\ - <span class=\"in-band\">List of all items</span>\ - </h1>", - ); + f.write_str("<h1 class=\"fqn\">List of all items</h1>"); // 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, "Structs", "structs"); - print_entries(f, &self.enums, "Enums", "enums"); - print_entries(f, &self.unions, "Unions", "unions"); - print_entries(f, &self.primitives, "Primitives", "primitives"); - print_entries(f, &self.traits, "Traits", "traits"); - print_entries(f, &self.macros, "Macros", "macros"); - print_entries(f, &self.attributes, "Attribute Macros", "attributes"); - print_entries(f, &self.derives, "Derive Macros", "derives"); - print_entries(f, &self.functions, "Functions", "functions"); - print_entries(f, &self.typedefs, "Typedefs", "typedefs"); - print_entries(f, &self.trait_aliases, "Trait Aliases", "trait-aliases"); - print_entries(f, &self.opaque_tys, "Opaque Types", "opaque-types"); - print_entries(f, &self.statics, "Statics", "statics"); - print_entries(f, &self.constants, "Constants", "constants") + print_entries(f, &self.structs, ItemSection::Structs); + print_entries(f, &self.enums, ItemSection::Enums); + print_entries(f, &self.unions, ItemSection::Unions); + print_entries(f, &self.primitives, ItemSection::PrimitiveTypes); + print_entries(f, &self.traits, ItemSection::Traits); + print_entries(f, &self.macros, ItemSection::Macros); + print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros); + print_entries(f, &self.derive_macros, ItemSection::DeriveMacros); + print_entries(f, &self.functions, ItemSection::Functions); + print_entries(f, &self.typedefs, ItemSection::TypeDefinitions); + print_entries(f, &self.trait_aliases, ItemSection::TraitAliases); + print_entries(f, &self.opaque_tys, ItemSection::OpaqueTypes); + print_entries(f, &self.statics, ItemSection::Statics); + print_entries(f, &self.constants, ItemSection::Constants); } } @@ -348,9 +394,7 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String { let mut ids = IdMap::default(); format!( "<div class=\"main-heading\">\ - <h1 class=\"fqn\">\ - <span class=\"in-band\">About scraped examples</span>\ - </h1>\ + <h1 class=\"fqn\">About scraped examples</h1>\ </div>\ <div>{}</div>", Markdown { @@ -536,7 +580,6 @@ fn short_item_info( parent: Option<&clean::Item>, ) -> Vec<String> { let mut extra_info = vec![]; - let error_codes = cx.shared.codes; if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) = item.deprecation(cx.tcx()) @@ -560,13 +603,7 @@ fn short_item_info( if let Some(note) = note { let note = note.as_str(); - let html = MarkdownHtml( - note, - &mut cx.id_map, - error_codes, - cx.shared.edition(), - &cx.shared.playground, - ); + let html = MarkdownItemInfo(note, &mut cx.id_map); message.push_str(&format!(": {}", html.into_string())); } extra_info.push(format!( @@ -1239,6 +1276,15 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { if let Some((did, ty)) = decl.output.as_return().and_then(|t| Some((t.def_id(cx.cache())?, t))) { + // Box has pass-through impls for Read, Write, Iterator, and Future when the + // boxed type implements one of those. We don't want to treat every Box return + // as being notably an Iterator (etc), though, so we exempt it. Pin has the same + // issue, with a pass-through impl for Future. + if Some(did) == cx.tcx().lang_items().owned_box() + || Some(did) == cx.tcx().lang_items().pin_type() + { + return "".to_string(); + } if let Some(impls) = cx.cache().impls.get(&did) { for i in impls { let impl_ = i.inner_impl(); @@ -1251,7 +1297,12 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { if let Some(trait_) = &impl_.trait_ { let trait_did = trait_.def_id(); - if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable) { + if cx + .cache() + .traits + .get(&trait_did) + .map_or(false, |t| t.is_notable_trait(cx.tcx())) + { if out.is_empty() { write!( &mut out, @@ -1555,7 +1606,7 @@ fn render_impl( link, render_mode, false, - trait_.map(|t| &t.trait_), + trait_, rendering_params, ); } @@ -1615,7 +1666,7 @@ fn render_impl( &mut default_impl_items, &mut impl_items, cx, - &t.trait_, + t, i.inner_impl(), &i.impl_item, parent, @@ -1747,7 +1798,7 @@ pub(crate) fn render_impl_summary( write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases); render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal); write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); - write!(w, "<h3 class=\"code-header in-band\">"); + write!(w, "<h3 class=\"code-header\">"); if let Some(use_absolute) = use_absolute { write!(w, "{}", inner_impl.print(use_absolute, cx)); @@ -1811,12 +1862,12 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { buffer.write_str("<div class=\"sidebar-elems\">"); if it.is_crate() { - write!(buffer, "<div class=\"block\"><ul>"); + write!(buffer, "<ul class=\"block\">"); if let Some(ref version) = cx.cache().crate_version { write!(buffer, "<li class=\"version\">Version {}</li>", Escape(version)); } write!(buffer, "<li><a id=\"all-types\" href=\"all.html\">All Items</a></li>"); - buffer.write_str("</ul></div>"); + buffer.write_str("</ul>"); } match *it.kind { @@ -1842,7 +1893,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { if !it.is_mod() { let path: String = cx.current.iter().map(|s| s.as_str()).intersperse("::").collect(); - write!(buffer, "<h2 class=\"location\"><a href=\"index.html\">In {}</a></h2>", path); + write!(buffer, "<h2><a href=\"index.html\">In {}</a></h2>", path); } // Closes sidebar-elems div. @@ -2216,21 +2267,8 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String } } -/// Don't call this function directly!!! Use `print_sidebar_title` or `print_sidebar_block` instead! -fn print_sidebar_title_inner(buf: &mut Buffer, id: &str, title: &str) { - write!( - buf, - "<h3 class=\"sidebar-title\">\ - <a href=\"#{}\">{}</a>\ - </h3>", - id, title - ); -} - fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) { - buf.push_str("<div class=\"block\">"); - print_sidebar_title_inner(buf, id, title); - buf.push_str("</div>"); + write!(buf, "<h3><a href=\"#{}\">{}</a></h3>", id, title); } fn print_sidebar_block( @@ -2239,13 +2277,12 @@ fn print_sidebar_block( title: &str, items: impl Iterator<Item = impl fmt::Display>, ) { - buf.push_str("<div class=\"block\">"); - print_sidebar_title_inner(buf, id, title); - buf.push_str("<ul>"); + print_sidebar_title(buf, id, title); + buf.push_str("<ul class=\"block\">"); for item in items { write!(buf, "<li>{}</li>", item); } - buf.push_str("</ul></div>"); + buf.push_str("</ul>"); } fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { @@ -2469,7 +2506,7 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean: } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -enum ItemSection { +pub(crate) enum ItemSection { Reexports, PrimitiveTypes, Modules, @@ -2621,11 +2658,27 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection { } } -fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) { +pub(crate) fn sidebar_module_like(buf: &mut Buffer, item_sections_in_use: FxHashSet<ItemSection>) { use std::fmt::Write as _; let mut sidebar = String::new(); + for &sec in ItemSection::ALL.iter().filter(|sec| item_sections_in_use.contains(sec)) { + let _ = write!(sidebar, "<li><a href=\"#{}\">{}</a></li>", sec.id(), sec.name()); + } + + if !sidebar.is_empty() { + write!( + buf, + "<section>\ + <ul class=\"block\">{}</ul>\ + </section>", + sidebar + ); + } +} + +fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) { let item_sections_in_use: FxHashSet<_> = items .iter() .filter(|it| { @@ -2640,21 +2693,8 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) { }) .map(|it| item_ty_to_section(it.type_())) .collect(); - for &sec in ItemSection::ALL.iter().filter(|sec| item_sections_in_use.contains(sec)) { - let _ = write!(sidebar, "<li><a href=\"#{}\">{}</a></li>", sec.id(), sec.name()); - } - if !sidebar.is_empty() { - write!( - buf, - "<section>\ - <div class=\"block\">\ - <ul>{}</ul>\ - </div>\ - </section>", - sidebar - ); - } + sidebar_module_like(buf, item_sections_in_use); } fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index cfa450942..632781736 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -400,7 +400,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: if myitem.fn_header(cx.tcx()).unwrap().unsafety == hir::Unsafety::Unsafe => { - "<a title=\"unsafe function\" href=\"#\"><sup>⚠</sup></a>" + "<sup title=\"unsafe function\">⚠</sup>" } _ => "", }; @@ -514,7 +514,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle + name.as_str().len() + generics_len; - wrap_into_docblock(w, |w| { + wrap_into_item_decl(w, |w| { wrap_item(w, "fn", |w| { render_attributes_in_pre(w, it, ""); w.reserve(header_len); @@ -553,7 +553,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: cx.tcx().trait_def(t.def_id).must_implement_one_of.clone(); // Output the trait definition - wrap_into_docblock(w, |w| { + wrap_into_item_decl(w, |w| { wrap_item(w, "trait", |w| { render_attributes_in_pre(w, it, ""); write!( @@ -716,9 +716,9 @@ 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, "<details class=\"rustdoc-toggle\" open><summary>"); + write!(w, "<details class=\"rustdoc-toggle method-toggle\" open><summary>"); } - write!(w, "<div id=\"{}\" class=\"method has-srclink\">", id); + write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id); render_rightside(w, cx, m, t, RenderMode::Normal); write!(w, "<h4 class=\"code-header\">"); render_assoc_item( @@ -730,7 +730,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: RenderMode::Normal, ); w.write_str("</h4>"); - w.write_str("</div>"); + w.write_str("</section>"); if toggled { write!(w, "</summary>"); w.push_buffer(content); @@ -890,7 +890,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w, "implementors", "Implementors", - "<div class=\"item-list\" id=\"implementors-list\">", + "<div id=\"implementors-list\">", ); for implementor in concrete { render_implementor(cx, implementor, it, w, &implementor_dups, &[]); @@ -902,7 +902,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w, "synthetic-implementors", "Auto implementors", - "<div class=\"item-list\" id=\"synthetic-implementors-list\">", + "<div id=\"synthetic-implementors-list\">", ); for implementor in synthetic { render_implementor( @@ -923,7 +923,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w, "implementors", "Implementors", - "<div class=\"item-list\" id=\"implementors-list\"></div>", + "<div id=\"implementors-list\"></div>", ); if t.is_auto(cx.tcx()) { @@ -931,7 +931,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: w, "synthetic-implementors", "Auto implementors", - "<div class=\"item-list\" id=\"synthetic-implementors-list\"></div>", + "<div id=\"synthetic-implementors-list\"></div>", ); } } @@ -1033,7 +1033,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_docblock(w, |w| { + wrap_into_item_decl(w, |w| { wrap_item(w, "trait-alias", |w| { render_attributes_in_pre(w, it, ""); write!( @@ -1057,7 +1057,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_docblock(w, |w| { + wrap_into_item_decl(w, |w| { wrap_item(w, "opaque", |w| { render_attributes_in_pre(w, it, ""); write!( @@ -1096,7 +1096,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea }); } - wrap_into_docblock(w, |w| write_content(w, cx, it, t)); + wrap_into_item_decl(w, |w| write_content(w, cx, it, t)); document(w, cx, it, None, HeadingOffset::H2); @@ -1110,7 +1110,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_docblock(w, |w| { + wrap_into_item_decl(w, |w| { wrap_item(w, "union", |w| { render_attributes_in_pre(w, it, ""); render_union(w, it, Some(&s.generics), &s.fields, "", cx); @@ -1174,7 +1174,7 @@ fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item] fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) { let count_variants = e.variants().count(); - wrap_into_docblock(w, |w| { + wrap_into_item_decl(w, |w| { wrap_item(w, "enum", |w| { render_attributes_in_pre(w, it, ""); write!( @@ -1333,14 +1333,14 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: } fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) { - wrap_into_docblock(w, |w| { + wrap_into_item_decl(w, |w| { highlight::render_macro_with_highlighting(&t.source, w); }); document(w, cx, it, None, HeadingOffset::H2) } fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &clean::ProcMacro) { - wrap_into_docblock(w, |w| { + wrap_into_item_decl(w, |w| { let name = it.name.expect("proc-macros always have names"); match m.kind { MacroKind::Bang => { @@ -1387,7 +1387,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_docblock(w, |w| { + wrap_into_item_decl(w, |w| { wrap_item(w, "const", |w| { render_attributes_in_code(w, it); @@ -1436,7 +1436,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_docblock(w, |w| { + wrap_into_item_decl(w, |w| { wrap_item(w, "struct", |w| { render_attributes_in_code(w, it); render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true, cx); @@ -1489,7 +1489,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_docblock(w, |w| { + wrap_into_item_decl(w, |w| { wrap_item(w, "static", |w| { render_attributes_in_code(w, it); write!( @@ -1506,7 +1506,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_docblock(w, |w| { + wrap_into_item_decl(w, |w| { wrap_item(w, "foreigntype", |w| { w.write_str("extern {\n"); render_attributes_in_code(w, it); @@ -1595,11 +1595,11 @@ fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) bounds } -fn wrap_into_docblock<F>(w: &mut Buffer, f: F) +fn wrap_into_item_decl<F>(w: &mut Buffer, f: F) where F: FnOnce(&mut Buffer), { - w.write_str("<div class=\"docblock item-decl\">"); + w.write_str("<div class=\"item-decl\">"); f(w); w.write_str("</div>") } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index fc4d46fe6..85f63c985 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -517,14 +517,12 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; }; let content = format!( - "<h1 class=\"fqn\">\ - <span class=\"in-band\">List of all crates</span>\ - </h1><ul class=\"crate mod\">{}</ul>", + "<h1 class=\"fqn\">List of all crates</h1><ul class=\"all-items\">{}</ul>", krates .iter() .map(|s| { format!( - "<li><a class=\"crate mod\" href=\"{}index.html\">{}</a></li>", + "<li><a href=\"{}index.html\">{}</a></li>", ensure_trailing_slash(s), s ) diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 2e2bee78b..7ab65bff3 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -274,7 +274,7 @@ pub(crate) fn print_src( ) { let lines = s.lines().count(); let mut line_numbers = Buffer::empty_from(buf); - line_numbers.write_str("<pre class=\"line-numbers\">"); + line_numbers.write_str("<pre class=\"src-line-numbers\">"); match source_context { SourceContext::Standalone => { for line in 1..=lines { diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 0a19a99ab..301f03a16 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -14,7 +14,11 @@ rules. display: none; } -.sub { +nav.sub { /* The search bar and related controls don't work without JS */ display: none; } + +.source .sidebar { + display: none; +} diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index bb35970eb..1cc954a98 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -132,19 +132,29 @@ h1, h2, h3, h4, h5, h6 { font-weight: 500; } h1, h2, h3, h4 { - margin: 20px 0 15px 0; + margin: 25px 0 15px 0; padding-bottom: 6px; } .docblock h3, .docblock h4, h5, h6 { margin: 15px 0 5px 0; } +.docblock > h2:first-child, +.docblock > h3:first-child, +.docblock > h4:first-child, +.docblock > h5:first-child, +.docblock > h6:first-child { + margin-top: 0; +} h1.fqn { margin: 0; padding: 0; - border-bottom-color: var(--headings-border-bottom-color); -} -h2, h3, h4 { - border-bottom-color: var(--headings-border-bottom-color); + flex-grow: 1; + /* We use overflow-wrap: break-word for Safari, which doesn't recognize + `anywhere`: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap */ + overflow-wrap: break-word; + /* Then override it with `anywhere`, which is required to make non-Safari browsers break + more aggressively when we want them to. */ + overflow-wrap: anywhere; } .main-heading { display: flex; @@ -153,9 +163,6 @@ h2, h3, h4 { padding-bottom: 6px; margin-bottom: 15px; } -.main-heading a:hover { - text-decoration: underline; -} #toggle-all-docs { text-decoration: none; } @@ -164,7 +171,7 @@ h2, h3, h4 { Rustdoc-generated h2 section headings (e.g. "Implementations", "Required Methods", etc) Underlines elsewhere in the documentation break up visual flow and tend to invert section hierarchies. */ -h2, +.content h2, .top-doc .docblock > h3, .top-doc .docblock > h4 { border-bottom: 1px solid var(--headings-border-bottom-color); @@ -177,48 +184,28 @@ h4.code-header { } .code-header { font-weight: 600; - border-bottom-style: none; margin: 0; padding: 0; - margin-top: 0.6em; - margin-bottom: 0.4em; -} -.impl, -.impl-items .method, -.methods .method, -.impl-items .type, -.methods .type, -.impl-items .associatedconstant, -.methods .associatedconstant, -.impl-items .associatedtype, -.methods .associatedtype { - flex-basis: 100%; - font-weight: 600; - position: relative; } +#crate-search, h1, h2, h3, h4, h5, h6, .sidebar, .mobile-topbar, -a.source, .search-input, .search-results .result-name, .item-left > a, .out-of-band, span.since, -details.rustdoc-toggle > summary::before, -.content ul.crate a.crate, a.srclink, -#help-button > button, +#help-button > a, details.rustdoc-toggle.top-doc > summary, -details.rustdoc-toggle.top-doc > summary::before, details.rustdoc-toggle.non-exhaustive > summary, -details.rustdoc-toggle.non-exhaustive > summary::before, .scraped-example-title, .more-examples-toggle summary, .more-examples-toggle .hide-more, .example-links a, /* This selector is for the items listed in the "all items" page. */ -#main-content > ul.docblock > li > a { +ul.all-items { font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif; } @@ -230,14 +217,14 @@ pre.rust a, .sidebar h2 a, .sidebar h3 a, .mobile-topbar h2 a, -.in-band a, +h1 a, .search-results a, .module-item .stab, .import-item .stab, .result-name .primitive > i, .result-name .keyword > i, -.content .method .where, -.content .fn .where, -.content .where.fmt-newline { +.method .where, +.fn .where, +.where.fmt-newline { color: var(--main-color); } @@ -274,7 +261,7 @@ pre.rust a, color: var(--macro-link-color); } -.content span.mod, .content a.mod, .block a.current.mod { +.content span.mod, .content a.mod { color: var(--mod-link-color); } @@ -299,32 +286,14 @@ p { https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html */ margin: 0 0 .75em 0; } - -summary { - outline: none; +/* For the last child of a div, the margin will be taken care of + by the margin-top of the next item. */ +p:last-child { + margin: 0; } /* Fix some style changes due to normalize.css 8 */ -td, -th { - padding: 0; -} - -table { - border-collapse: collapse; -} - -button, -input, -optgroup, -select, -textarea { - color: inherit; - font: inherit; - margin: 0; -} - button { /* Buttons on Safari have different default padding than other platforms. Make them the same. */ padding: 1px 6px; @@ -375,9 +344,6 @@ code, pre, a.test-arrow, .code-header { pre { padding: 14px; } -.docblock.item-decl { - margin-left: 0; -} .item-decl pre { overflow-x: auto; } @@ -394,22 +360,11 @@ img { overflow: visible; } -.sub-container { - display: flex; - flex-direction: row; - flex-wrap: nowrap; -} - .sub-logo-container { - display: none; - margin-right: 20px; + line-height: 0; } -.source .sub-logo-container { - display: block; -} - -.source .sub-logo-container > img { +.sub-logo-container > img { height: 60px; width: 60px; object-fit: contain; @@ -421,7 +376,7 @@ img { .sidebar { font-size: 0.875rem; - width: 250px; + width: 200px; min-width: 200px; overflow-y: scroll; position: sticky; @@ -430,15 +385,6 @@ img { left: 0; } -.sidebar-elems, -.sidebar > .location { - padding-left: 24px; -} - -.sidebar .location { - overflow-wrap: anywhere; -} - .rustdoc.source .sidebar { width: 50px; min-width: 0px; @@ -452,10 +398,6 @@ img { overflow-y: hidden; } -.rustdoc.source .sidebar .sidebar-logo { - display: none; -} - .source .sidebar, #sidebar-toggle, #source-sidebar { background-color: var(--sidebar-background-color); } @@ -465,16 +407,15 @@ img { } .source .sidebar > *:not(#sidebar-toggle) { - opacity: 0; visibility: hidden; } .source-sidebar-expanded .source .sidebar { overflow-y: auto; + width: 300px; } .source-sidebar-expanded .source .sidebar > *:not(#sidebar-toggle) { - opacity: 1; visibility: visible; } @@ -532,22 +473,15 @@ img { width: 100px; } -.location:empty { - border: none; -} - -.location a:first-of-type { - font-weight: 500; -} - -.block ul, .block li { +ul.block, .block li { padding: 0; margin: 0; list-style: none; } .block a, -h2.location a { +.sidebar h2 a, +.sidebar h3 a { display: block; padding: 0.25rem; margin-left: -0.25rem; @@ -557,8 +491,7 @@ h2.location a { } .sidebar h2 { - border-bottom: none; - font-weight: 500; + overflow-wrap: anywhere; padding: 0; margin: 0; margin-top: 0.7rem; @@ -567,11 +500,23 @@ h2.location a { .sidebar h3 { font-size: 1.125rem; /* 18px */ - font-weight: 500; padding: 0; margin: 0; } +.sidebar-elems, +.sidebar > h2 { + padding-left: 24px; +} + +.sidebar a, .sidebar .current { + color: var(--sidebar-link-color); +} +.sidebar .current, +.sidebar a:hover { + background-color: var(--sidebar-current-link-background-color); +} + .sidebar-elems .block { margin-bottom: 2em; } @@ -585,66 +530,61 @@ h2.location a { } .source .content pre.rust { - white-space: pre; overflow: auto; padding-left: 0; } .rustdoc .example-wrap { - display: inline-flex; + display: flex; + position: relative; margin-bottom: 10px; } +/* For the last child of a div, the margin will be taken care of + by the margin-top of the next item. */ +.rustdoc .example-wrap:last-child { + margin-bottom: 0px; +} -.example-wrap { - position: relative; - width: 100%; +.rustdoc .example-wrap > pre { + margin: 0; + flex-grow: 1; + overflow-x: auto; } -.example-wrap > pre.line-number { +.rustdoc .example-wrap > pre.example-line-numbers, +.rustdoc .example-wrap > pre.src-line-numbers { + flex-grow: 0; overflow: initial; + text-align: right; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.example-line-numbers { border: 1px solid; padding: 13px 8px; - text-align: right; border-top-left-radius: 5px; border-bottom-left-radius: 5px; + border-color: var(--example-line-numbers-border-color); } -.example-wrap > pre.rust a:hover { - text-decoration: underline; -} - -.line-numbers { - text-align: right; -} -.rustdoc:not(.source) .example-wrap > pre:not(.line-number) { - width: 100%; - overflow-x: auto; +.src-line-numbers span { + cursor: pointer; + color: var(--src-line-numbers-span-color); } - -.rustdoc:not(.source) .example-wrap > pre.line-numbers { - width: auto; - overflow-x: visible; +.src-line-numbers .line-highlighted { + background-color: var(--src-line-number-highlighted-background-color); } - -.rustdoc .example-wrap > pre { - margin: 0; +.src-line-numbers :target { + background-color: transparent; } .search-loading { text-align: center; } -.content > .example-wrap pre.line-numbers { - position: relative; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.line-numbers span { - cursor: pointer; -} - .docblock-short { overflow-wrap: break-word; overflow-wrap: anywhere; @@ -669,9 +609,6 @@ h2.location a { .docblock h5 { font-size: 1rem; } .docblock h6 { font-size: 0.875rem; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { - border-bottom-color: var(--headings-border-bottom-color); -} .docblock { margin-left: 24px; @@ -683,33 +620,9 @@ h2.location a { overflow-x: auto; } -.content .out-of-band { +.out-of-band { flex-grow: 0; font-size: 1.125rem; - font-weight: normal; - float: right; -} - -.method > .code-header, .trait-impl > .code-header { - max-width: calc(100% - 41px); - display: block; -} - -.content .in-band { - flex-grow: 1; - margin: 0px; - padding: 0px; - /* We use overflow-wrap: break-word for Safari, which doesn't recognize - `anywhere`: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap */ - overflow-wrap: break-word; - /* Then override it with `anywhere`, which is required to make non-Safari browsers break - more aggressively when we want them to. */ - overflow-wrap: anywhere; - background-color: var(--main-background-color); -} - -.in-band > code, .in-band > .code-header { - display: inline-block; } .docblock code, .docblock-short code, @@ -726,6 +639,7 @@ pre, .rustdoc.source .example-wrap { width: calc(100% - 2px); overflow-x: auto; display: block; + border-collapse: collapse; } .docblock table td { @@ -740,38 +654,21 @@ pre, .rustdoc.source .example-wrap { border: 1px solid var(--border-color); } -.content .item-list { - list-style-type: none; - padding: 0; -} - -.content > .methods > .method { - font-size: 1rem; - position: relative; -} /* Shift "where ..." part of method or fn definition down a line */ -.content .method .where, -.content .fn .where, -.content .where.fmt-newline { +.method .where, +.fn .where, +.where.fmt-newline { display: block; font-size: 0.875rem; } .item-info { display: block; -} - -.content .item-info code { - font-size: 0.875rem; -} - -.content .item-info { - position: relative; margin-left: 24px; } -.content .impl-items .docblock, .content .impl-items .item-info { - margin-bottom: .6em; +.item-info code { + font-size: 0.875rem; } #main-content > .item-info { @@ -780,16 +677,24 @@ pre, .rustdoc.source .example-wrap { } nav.sub { + flex-grow: 1; + flex-flow: row nowrap; + margin: 4px 0 25px 0; + display: flex; + align-items: center; +} +.search-form { position: relative; - font-size: 1rem; + display: flex; + height: 34px; flex-grow: 1; - margin-bottom: 25px; } .source nav.sub { + margin: 0 0 15px 0; +} +.source .search-form { margin-left: 32px; } -nav.sum { text-align: right; } -nav.sub form { display: inline; } a { text-decoration: none; @@ -805,9 +710,7 @@ a { display: initial; } -.in-band:hover > .anchor, .impl:hover > .anchor, .method.trait-impl:hover > .anchor, -.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor, -.associatedtype.trait-impl:hover > .anchor { +.impl:hover > .anchor, .trait-impl:hover > .anchor { display: inline-block; position: absolute; } @@ -831,12 +734,16 @@ h2.small-section-header > .anchor { content: '§'; } -.docblock a:not(.srclink):not(.test-arrow):not(.scrape-help):hover, -.docblock-short a:not(.srclink):not(.test-arrow):not(.scrape-help):hover, .item-info a { +.main-heading a:hover, +.example-wrap > pre.rust a:hover, +.all-items a:hover, +.docblock a:not(.test-arrow):not(.scrape-help):hover, +.docblock-short a:not(.test-arrow):not(.scrape-help):hover, +.item-info a { text-decoration: underline; } -.block a.current.crate { font-weight: 500; } +.crate.block a.current { font-weight: 500; } /* In most contexts we use `overflow-wrap: anywhere` to ensure that we can wrap as much as needed on mobile (see @@ -876,15 +783,6 @@ table, padding-right: 1.25rem; } -.search-container { - position: relative; - display: flex; - height: 34px; - margin-top: 4px; -} -.search-container > * { - height: 100%; -} .search-results-title { margin-top: 0; white-space: nowrap; @@ -922,6 +820,9 @@ table, /* Removes default arrow from firefox */ text-indent: 0.01px; background-color: var(--main-background-color); + color: inherit; + line-height: 1.5; + font-weight: 500; } /* cancel stylistic differences in padding in firefox for "appearance: none"-style (or equivalent) <select>s */ @@ -957,18 +858,14 @@ so that we can apply CSS-filters to change the arrow color in themes */ -webkit-appearance: textfield for search inputs. That causes rounded corners and no border on iOS Safari. */ -webkit-appearance: none; - /* Override Normalize.css: we have margins and do - not want to overflow - the `moz` attribute is necessary - until Firefox 29, too early to drop at this point */ - -moz-box-sizing: border-box !important; - box-sizing: border-box !important; outline: none; border: 1px solid var(--border-color); border-radius: 2px; padding: 8px; font-size: 1rem; - width: 100%; + flex-grow: 1; background-color: var(--button-background-color); + color: var(--search-color); } .search-input:focus { border-color: var(--search-input-focused-border-color); @@ -1005,13 +902,18 @@ so that we can apply CSS-filters to change the arrow color in themes */ flex-flow: row wrap; } -.search-results .result-name, .search-results div.desc, .search-results .result-description { +.search-results .result-name, .search-results div.desc { width: 50%; } .search-results .result-name { padding-right: 1em; } +.search-results a:hover, +.search-results a:focus { + background-color: var(--search-result-link-focus-background-color); +} + .popover { font-size: 1rem; position: absolute; @@ -1042,40 +944,36 @@ so that we can apply CSS-filters to change the arrow color in themes */ color: var(--main-color); } -#help-button .popover { +/* use larger max-width for help popover, but not for help.html */ +#help.popover { max-width: 600px; } -#help-button .popover::before { +#help.popover::before { right: 48px; } -#help-button dt { +#help dt { float: left; clear: left; display: block; margin-right: 0.5rem; } -#help-button span.top, #help-button span.bottom { +#help span.top, #help span.bottom { text-align: center; display: block; font-size: 1.125rem; } -#help-button span.top { - text-align: center; - display: block; +#help span.top { margin: 10px 0; border-bottom: 1px solid var(--border-color); padding-bottom: 4px; margin-bottom: 6px; } -#help-button span.bottom { +#help span.bottom { clear: both; border-top: 1px solid var(--border-color); } -.side-by-side { - text-align: initial; -} .side-by-side > div { width: 50%; float: left; @@ -1097,10 +995,13 @@ so that we can apply CSS-filters to change the arrow color in themes */ margin-bottom: 5px; font-size: 0.875rem; font-weight: normal; + color: var(--main-color); + background-color: var(--stab-background-color); } -.stab p { - display: inline; - margin: 0; + +.stab.portability > code { + background: none; + color: var(--stab-code-color); } .stab .emoji { @@ -1108,6 +1009,12 @@ 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: @@ -1142,7 +1049,6 @@ so that we can apply CSS-filters to change the arrow color in themes */ .rightside { padding-left: 12px; padding-right: 2px; - position: initial; float: right; } @@ -1151,23 +1057,55 @@ so that we can apply CSS-filters to change the arrow color in themes */ color: var(--right-side-color); } - -.impl-items .srclink, .impl .srclink, .methods .srclink { - /* Override header settings otherwise it's too bold */ - font-weight: normal; - font-size: 1rem; +pre.rust { + tab-size: 4; + -moz-tab-size: 4; } -td.summary-column { - width: 100%; +/* Code highlighting */ +pre.rust .kw { + color: var(--code-highlight-kw-color); } - -.summary { - padding-right: 0px; +pre.rust .kw-2 { + color: var(--code-highlight-kw-2-color); +} +pre.rust .lifetime { + color: var(--code-highlight-lifetime-color); +} +pre.rust .prelude-ty { + color: var(--code-highlight-prelude-color); +} +pre.rust .prelude-val { + color: var(--code-highlight-prelude-val-color); +} +pre.rust .string { + color: var(--code-highlight-string-color); +} +pre.rust .number { + color: var(--code-highlight-number-color); +} +pre.rust .bool-val { + color: var(--code-highlight-literal-color); +} +pre.rust .self { + color: var(--code-highlight-self-color); +} +pre.rust .attribute { + color: var(--code-highlight-attribute-color); +} +pre.rust .macro, +pre.rust .macro-nonterminal { + color: var(--code-highlight-macro-color); } - pre.rust .question-mark { font-weight: bold; + color: var(--code-highlight-question-mark-color); +} +pre.rust .comment { + color: var(--code-highlight-comment-color); +} +pre.rust .doccomment { + color: var(--code-highlight-doc-comment-color); } .example-wrap.compile_fail, @@ -1278,9 +1216,6 @@ a.test-arrow { .example-wrap:hover .test-arrow { visibility: visible; } -a.test-arrow:hover { - text-decoration: none; -} .code-attribute { font-weight: 300; @@ -1300,13 +1235,11 @@ h3.variant { font-weight: 600; font-size: 1.125rem; margin-bottom: 10px; - border-bottom: none; } .sub-variant h4 { font-size: 1rem; font-weight: 400; - border-bottom: none; margin-top: 0; margin-bottom: 0; } @@ -1357,7 +1290,7 @@ h3.variant { content: "\00a0\00a0\00a0"; } -.notable-traits .notable, .notable-traits .docblock { +.notable-traits .docblock { margin: 0; } @@ -1375,16 +1308,6 @@ h3.variant { font-size: 1.25rem; } -/* Example code has the "Run" button that needs to be positioned relative to the pre */ -pre.rust.rust-example-rendered { - position: relative; -} - -pre.rust { - tab-size: 4; - -moz-tab-size: 4; -} - .search-failed { text-align: center; margin-top: 20px; @@ -1416,6 +1339,8 @@ pre.rust { border: 0; border-top: 2px solid; flex: 1; + line-height: 1.5; + color: inherit; } #titles > button > div.count { @@ -1433,7 +1358,6 @@ pre.rust { position: sticky; top: 0; left: 0; - font-weight: bold; font-size: 1.25rem; border-bottom: 1px solid; display: flex; @@ -1444,7 +1368,6 @@ pre.rust { } #source-sidebar { width: 100%; - z-index: 1; overflow: auto; } #source-sidebar > .title { @@ -1454,6 +1377,8 @@ pre.rust { margin-bottom: 6px; } #sidebar-toggle > button { + font-size: inherit; + font-weight: bold; background: none; color: inherit; cursor: pointer; @@ -1476,23 +1401,29 @@ pre.rust { outline: none; } -#settings-menu > a, #help-button > button, #copy-path { - padding: 5px; +#settings-menu > a, #help-button > a, #copy-path { width: 33px; - border: 1px solid var(--border-color); - border-radius: 2px; cursor: pointer; + line-height: 1.5; } -#settings-menu > a, #help-button > button { +#settings-menu > a, #help-button > a { padding: 5px; height: 100%; display: block; background-color: var(--button-background-color); + border: 1px solid var(--border-color); + border-radius: 2px; } #copy-path { color: var(--copy-path-button-color); + background: var(--main-background-color); + height: 34px; + margin-left: 10px; + padding: 0; + padding-left: 2px; + border: 0; } #copy-path > img { filter: var(--copy-path-img-filter); @@ -1513,26 +1444,7 @@ pre.rust { animation: rotating 2s linear infinite; } -.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 .radio-line input:focus { - box-shadow: 0 0 1px 1px var(--settings-input-color); -} -/* In here we combine both `:focus` and `:checked` properties. */ -.setting-line .radio-line input:checked:focus { - box-shadow: inset 0 0 0 3px var(--main-background-color), - 0 0 2px 2px var(--settings-input-color); -} -.setting-line .radio-line input:hover { - border-color: var(--settings-input-color) !important; -} -input:checked + .slider { - background-color: var(--settings-input-color); -} - -#help-button > button { +#help-button > a { text-align: center; /* Rare exception to specifying font sizes in rem. Since this is acting as an icon, it's okay to specify their sizes in pixels. */ @@ -1540,15 +1452,6 @@ input:checked + .slider { padding-top: 2px; } -#copy-path { - height: 34px; - background-color: var(--main-background-color); - margin-left: 10px; - padding: 0; - padding-left: 2px; - border: 0; -} - kbd { display: inline-block; padding: 3px 5px; @@ -1560,25 +1463,39 @@ kbd { cursor: default; } -#main-content > ul { - padding-left: 10px; -} -#main-content > ul > li { +ul.all-items > li { list-style: none; } -.non-exhaustive { - margin-bottom: 1em; -} - 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-position: outside; + list-style: none; cursor: pointer; + position: relative; } details.dir-entry div.folders, details.dir-entry div.files { @@ -1589,6 +1506,17 @@ details.dir-entry a { display: block; } +/* We use CSS containment on the details elements because most sizeable elements + of the page are contained in one of these. This also makes re-rendering + faster on document changes (like closing and opening toggles). + Unfortunately we can't yet specify contain: content or contain: strict + because the [-]/[+] toggles extend past the boundaries of the <details> + https://developer.mozilla.org/en-US/docs/Web/CSS/contain */ +details.rustdoc-toggle { + contain: layout; + position: relative; +} + /* 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". */ @@ -1598,6 +1526,8 @@ details.rustdoc-toggle > summary.hideme { details.rustdoc-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 { @@ -1621,7 +1551,6 @@ details.rustdoc-toggle > summary::before { } details.rustdoc-toggle > summary.hideme > span, -details.rustdoc-toggle > summary::before, .more-examples-toggle summary, .more-examples-toggle .hide-more { color: var(--toggles-color); } @@ -1646,6 +1575,15 @@ details.rustdoc-toggle > summary:hover::before { opacity: 1; } +details.rustdoc-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. + */ + outline: 1px dotted #000; + outline-offset: 1px; +} + details.rustdoc-toggle.top-doc > summary, details.rustdoc-toggle.top-doc > summary::before, details.rustdoc-toggle.non-exhaustive > summary, @@ -1681,10 +1619,6 @@ details.rustdoc-toggle[open] > summary.hideme { position: absolute; } -details.rustdoc-toggle { - position: relative; -} - details.rustdoc-toggle[open] > summary.hideme > span { display: none; } @@ -1718,37 +1652,20 @@ details.rustdoc-toggle[open] > summary.hideme::after { display: inline-block; } -/* Media Queries */ - -/* -WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY; -If you update this line, then you also need to update the line with the same warning -in storage.js plus the media query with (max-width: 700px) -*/ -@media (min-width: 701px) { - /* In case there is no documentation before a code block, we need to add some margin at the top - to prevent an overlay between the "collapse toggle" and the information tooltip. - However, it's not needed with smaller screen width because the doc/code block is always put - "one line" below. */ - .docblock > .example-wrap:first-child .tooltip { - margin-top: 16px; - } - - /* When we expand the sidebar on the source code page, we hide the logo on the left of the - search bar to have more space. */ - .source-sidebar-expanded .source .sidebar + main .width-limiter .sub-logo-container.rust-logo { - display: none; - } - - .source-sidebar-expanded .source .sidebar { - width: 300px; - } +/* In case there is no documentation before a code block, we need to add some margin at the top +to prevent an overlay between the "collapse toggle" and the information tooltip. +However, it's not needed with smaller screen width because the doc/code block is always put +"one line" below. */ +.docblock > .example-wrap:first-child .tooltip { + margin-top: 16px; } +/* Media Queries */ + /* WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY If you update this line, then you also need to update the line with the same warning -in storage.js plus the media query with (min-width: 701px) +in storage.js */ @media (max-width: 700px) { /* When linking to an item with an `id` (for instance, by clicking a link in the sidebar, @@ -1775,13 +1692,13 @@ in storage.js plus the media query with (min-width: 701px) flex-direction: column; } - .content .out-of-band { + .out-of-band { text-align: left; margin-left: initial; padding: initial; } - .content .out-of-band .since::before { + .out-of-band .since::before { content: "Since "; } @@ -1827,24 +1744,13 @@ in storage.js plus the media query with (min-width: 701px) } .rustdoc.source > .sidebar { - position: fixed; - margin: 0; - z-index: 11; width: 0; } - .mobile-topbar .location a { - padding: 0; - margin: 0; - } - - .mobile-topbar .location { - border: none; - padding: 0; + .mobile-topbar h2 { + padding-bottom: 0; margin: auto 0.5em auto auto; - text-overflow: ellipsis; overflow: hidden; - white-space: nowrap; /* Rare exception to specifying font sizes in rem. Since the topbar height is specified in pixels, this also has to be specified in pixels to avoid overflowing the topbar when the user sets a bigger @@ -1852,6 +1758,13 @@ in storage.js plus the media query with (min-width: 701px) font-size: 24px; } + .mobile-topbar h2 a { + display: block; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + .mobile-topbar .logo-container { max-height: 45px; } @@ -1876,16 +1789,13 @@ in storage.js plus the media query with (min-width: 701px) top: 0; } - .source .mobile-topbar { - display: none; - } - .sidebar-menu-toggle { width: 45px; /* Rare exception to specifying font sizes in rem. Since this is acting as an icon, it's okay to specify its sizes in pixels. */ font-size: 32px; border: none; + color: var(--main-color); } .sidebar-elems { @@ -1897,10 +1807,6 @@ in storage.js plus the media query with (min-width: 701px) margin-left: 0px; } - .source .content { - margin-top: 10px; - } - .anchor { display: none !important; } @@ -1941,7 +1847,6 @@ in storage.js plus the media query with (min-width: 701px) border-top-right-radius: 3px; border-bottom-right-radius: 3px; cursor: pointer; - font-weight: bold; border: 1px solid; border-left: 0; } @@ -1957,14 +1862,6 @@ in storage.js plus the media query with (min-width: 701px) border-bottom: 1px solid; } - #source-sidebar { - z-index: 11; - } - - #main-content > .line-numbers { - margin-top: 0; - } - .notable-traits .notable-traits-tooltiptext { left: 0; top: 100%; @@ -1992,10 +1889,10 @@ in storage.js plus the media query with (min-width: 701px) border-bottom: 1px solid #aaa9; padding: 5px 0px; } - .search-results .result-name, .search-results div.desc, .search-results .result-description { + .search-results .result-name, .search-results div.desc { width: 100%; } - .search-results div.desc, .search-results .result-description, .item-right { + .search-results div.desc, .item-right { padding-left: 2em; } @@ -2015,13 +1912,18 @@ in storage.js plus the media query with (min-width: 701px) } /* Align summary-nested and unnested item-info gizmos. */ - .content .impl-items > .item-info { + .impl-items > .item-info { margin-left: 34px; } + + .source nav.sub { + margin: 0; + padding: 8px; + } } @media print { - nav.sidebar, nav.sub, .content .out-of-band, a.srclink, #copy-path, + 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 { display: none; @@ -2037,10 +1939,6 @@ in storage.js plus the media query with (min-width: 701px) } @media (max-width: 464px) { - #crate-search { - border-radius: 4px; - } - .docblock { margin-left: 12px; } @@ -2050,15 +1948,15 @@ in storage.js plus the media query with (min-width: 701px) overflow-wrap: anywhere; } - .sub-container { + nav.sub { flex-direction: column; } - .sub-logo-container { - align-self: center; + .search-form { + align-self: stretch; } - .source .sub-logo-container > img { + .sub-logo-container > img { height: 35px; width: 35px; } @@ -2071,23 +1969,24 @@ in storage.js plus the media query with (min-width: 701px) } } -.method-toggle summary, -.implementors-toggle summary, -.impl { +.method-toggle > summary, +.implementors-toggle > summary, +.impl, +#implementors-list > .docblock, +.impl-items > section, +.methods > section +{ margin-bottom: 0.75em; } -.method-toggle[open] { +.method-toggle[open]:not(:last-child), +.implementors-toggle[open]:not(:last-child) { margin-bottom: 2em; } -.implementors-toggle[open] { - margin-bottom: 2em; -} - -#trait-implementations-list .method-toggle, -#synthetic-implementations-list .method-toggle, -#blanket-implementations-list .method-toggle { +#trait-implementations-list .method-toggle:not(:last-child), +#synthetic-implementations-list .method-toggle:not(:last-child), +#blanket-implementations-list .method-toggle:not(:last-child) { margin-bottom: 1em; } @@ -2124,10 +2023,6 @@ in storage.js plus the media query with (min-width: 701px) padding-bottom: 0; } -.scraped-example:not(.expanded) .code-wrapper pre.line-numbers { - overflow-x: hidden; -} - .scraped-example .code-wrapper .prev { position: absolute; top: 0.25em; @@ -2170,12 +2065,12 @@ in storage.js plus the media query with (min-width: 701px) bottom: 0; } -.scraped-example .code-wrapper .line-numbers { +.scraped-example .code-wrapper .src-line-numbers { margin: 0; padding: 14px 0; } -.scraped-example .code-wrapper .line-numbers span { +.scraped-example .code-wrapper .src-line-numbers span { padding: 0 14px; } diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index e82ec0426..83939f63b 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -12,7 +12,8 @@ margin-right: 0.3em; height: 1.2rem; width: 1.2rem; - border: 1px solid; + color: inherit; + border: 1px solid currentColor; outline: none; -webkit-appearance: none; cursor: pointer; @@ -88,3 +89,22 @@ input:checked + .slider:before { #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 .radio-line input:focus { + box-shadow: 0 0 1px 1px var(--settings-input-color); +} +/* In here we combine both `:focus` and `:checked` properties. */ +.setting-line .radio-line input:checked:focus { + box-shadow: inset 0 0 0 3px var(--main-background-color), + 0 0 2px 2px var(--settings-input-color); +} +.setting-line .radio-line input:hover { + border-color: var(--settings-input-color) !important; +} +input:checked + .slider { + background-color: var(--settings-input-color); +} diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index e7a898e9f..fdfdb3e19 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -35,6 +35,29 @@ Original by Dempfi (https://github.com/dempfi/ayu) --keyword-link-color: #39afd7; --mod-link-color: #39afd7; --link-color: #39afd7; + --sidebar-link-color: #53b1db; + --sidebar-current-link-background-color: transparent; + --search-result-link-focus-background-color: #3c3c3c; + --stab-background-color: #314559; + --stab-code-color: #e6e1cf; + --search-color: #fff; + --code-highlight-kw-color: #ff7733; + --code-highlight-kw-2-color: #ff7733; + --code-highlight-lifetime-color: #ff7733; + --code-highlight-prelude-color: #69f2df; + --code-highlight-prelude-val-color: #ff7733; + --code-highlight-number-color: #b8cc52; + --code-highlight-string-color: #b8cc52; + --code-highlight-literal-color: #ff7733; + --code-highlight-attribute-color: #e6e1cf; + --code-highlight-self-color: #36a3d9; + --code-highlight-macro-color: #a37acc; + --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); } .slider { @@ -50,7 +73,7 @@ input:focus + .slider { h1, h2, h3, h4 { color: white; } -h1.fqn a { +h1 a { color: #fff; } h4 { @@ -85,7 +108,6 @@ pre, .rustdoc.source .example-wrap { .sidebar .current, .sidebar a:hover { - background-color: transparent; color: #ffb44c; } @@ -93,10 +115,8 @@ pre, .rustdoc.source .example-wrap { color: #ff7733; } -.line-numbers span { color: #5c6773; } -.line-numbers .line-highlighted { +.src-line-numbers .line-highlighted { color: #708090; - background-color: rgba(255, 236, 164, 0.06); padding-right: 4px; border-right: 1px solid #ffb44c; } @@ -119,12 +139,6 @@ pre, .rustdoc.source .example-wrap { .content .item-info::before { color: #ccc; } -.sidebar a { color: #53b1db; } -.sidebar a.current.type { color: #53b1db; } - -pre.rust .comment { color: #788797; } -pre.rust .doccomment { color: #a1ac88; } - .sidebar h2 a, .sidebar h3 a { color: white; @@ -148,53 +162,15 @@ details.rustdoc-toggle > summary::before { filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%); } -.search-input { - color: #fff; -} - .module-item .stab, .import-item .stab { color: #000; } -.stab { - color: #c5c5c5; - background: #314559 !important; -} - -.stab.portability > code { - color: #e6e1cf; - background: none; -} - .result-name .primitive > i, .result-name .keyword > i { color: #788797; } -.line-numbers :target { background-color: transparent; } - -/* Code highlighting */ -pre.rust .number, pre.rust .string { color: #b8cc52; } -pre.rust .kw, pre.rust .kw-2, pre.rust .prelude-ty, -pre.rust .bool-val, pre.rust .prelude-val, -pre.rust .lifetime { color: #ff7733; } -pre.rust .macro, pre.rust .macro-nonterminal { color: #a37acc; } -pre.rust .question-mark { - color: #ff9011; -} -pre.rust .self { - color: #36a3d9; - font-style: italic; -} -pre.rust .attribute { - color: #e6e1cf; -} - -.example-wrap > pre.line-number { - color: #5c67736e; - border: none; -} - a.test-arrow { font-size: 100%; color: #788797; @@ -260,52 +236,13 @@ pre.rust .kw {} pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, pre.rust .attribute {} pre.rust .kw-2, pre.rust .prelude-ty {} -.search-results a:focus span {} -a.result-trait:focus {} -a.result-traitalias:focus {} -a.result-mod:focus, -a.result-externcrate:focus {} -a.result-mod:focus {} -a.result-externcrate:focus {} -a.result-enum:focus {} -a.result-struct:focus {} -a.result-union:focus {} -a.result-fn:focus, -a.result-method:focus, -a.result-tymethod:focus {} -a.result-type:focus {} -a.result-associatedtype:focus {} -a.result-foreigntype:focus {} -a.result-attr:focus, -a.result-derive:focus, -a.result-macro:focus {} -a.result-constant:focus, -a.result-static:focus {} -a.result-primitive:focus {} -a.result-keyword:focus {} - -.sidebar a.current.enum {} -.sidebar a.current.struct {} -.sidebar a.current.foreigntype {} -.sidebar a.current.attr, -.sidebar a.current.derive, -.sidebar a.current.macro {} -.sidebar a.current.union {} -.sidebar a.current.constant -.sidebar a.current.static {} -.sidebar a.current.primitive {} -.sidebar a.current.trait {} -.sidebar a.current.traitalias {} -.sidebar a.current.fn {} -.sidebar a.current.keyword {} - kbd { color: #c5c5c5; background-color: #314559; box-shadow: inset 0 -1px 0 #5c6773; } -#settings-menu > a, #help-button > button { +#settings-menu > a, #help-button > a { color: #fff; } @@ -314,7 +251,7 @@ kbd { } #settings-menu > a:hover, #settings-menu > a:focus, -#help-button > button:hover, #help-button > button:focus { +#help-button > a:hover, #help-button > a:focus { border-color: #e0e0e0; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 07a1ed8b7..361d3d4a2 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -30,6 +30,29 @@ --keyword-link-color: #d2991d; --mod-link-color: #d2991d; --link-color: #d2991d; + --sidebar-link-color: #fdbf35; + --sidebar-current-link-background-color: #444; + --search-result-link-focus-background-color: #616161; + --stab-background-color: #314559; + --stab-code-color: #e6e1cf; + --search-color: #111; + --code-highlight-kw-color: #ab8ac1; + --code-highlight-kw-2-color: #769acb; + --code-highlight-lifetime-color: #d97f26; + --code-highlight-prelude-color: #769acb; + --code-highlight-prelude-val-color: #ee6868; + --code-highlight-number-color: #83a300; + --code-highlight-string-color: #83a300; + --code-highlight-literal-color: #ee6868; + --code-highlight-attribute-color: #ee6868; + --code-highlight-self-color: #ee6868; + --code-highlight-macro-color: #3e999f; + --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; } .slider { @@ -49,68 +72,8 @@ input:focus + .slider { drop-shadow(0 -1px 0 #fff) } -.sidebar .current, -.sidebar a:hover { - background: #444; -} - -.line-numbers span { color: #3B91E2; } -.line-numbers .line-highlighted { - background-color: #0a042f !important; -} - -.search-results a:hover { - background-color: #777; -} - -.search-results a:focus { - color: #eee !important; - background-color: #616161; -} -.search-results a:focus span { color: #eee !important; } -a.result-trait:focus { background-color: #013191; } -a.result-traitalias:focus { background-color: #013191; } -a.result-mod:focus, -a.result-externcrate:focus { background-color: #884719; } -a.result-enum:focus { background-color: #194e9f; } -a.result-struct:focus { background-color: #194e9f; } -a.result-union:focus { background-color: #194e9f; } -a.result-fn:focus, -a.result-method:focus, -a.result-tymethod:focus { background-color: #4950ed; } -a.result-type:focus { background-color: #194e9f; } -a.result-associatedtype:focus { background-color: #884719; } -a.result-foreigntype:focus { background-color: #194e9f; } -a.result-attr:focus, -a.result-derive:focus, -a.result-macro:focus { background-color: #217d1c; } -a.result-constant:focus, -a.result-static:focus { background-color: #884719; } -a.result-primitive:focus { background-color: #194e9f; } -a.result-keyword:focus { background-color: #884719; } - .content .item-info::before { color: #ccc; } -.sidebar a { color: #fdbf35; } -.sidebar a.current.enum { color: #12ece2; } -.sidebar a.current.struct { color: #12ece2; } -.sidebar a.current.type { color: #12ece2; } -.sidebar a.current.foreigntype { color: #12ece2; } -.sidebar a.current.attr, -.sidebar a.current.derive, -.sidebar a.current.macro { color: #0be900; } -.sidebar a.current.union { color: #12ece2; } -.sidebar a.current.constant -.sidebar a.current.static { color: #fdbf35; } -.sidebar a.current.primitive { color: #12ece2; } -.sidebar a.current.trait { color: #cca7ff; } -.sidebar a.current.traitalias { color: #cca7ff; } -.sidebar a.current.fn { color: #32d479; } -.sidebar a.current.keyword { color: #fdbf35; } - -pre.rust .comment { color: #8d8d8b; } -pre.rust .doccomment { color: #8ca375; } - body.source .example-wrap pre.rust a { background: #333; } @@ -119,10 +82,6 @@ details.rustdoc-toggle > summary::before { filter: invert(100%); } -.search-input { - color: #111; -} - #crate-search-div::after { /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%); @@ -134,31 +93,6 @@ details.rustdoc-toggle > summary::before { filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%); } -.stab { background: #314559; } - -.stab.portability > code { - color: #e6e1cf; - background: none; -} - -.line-numbers :target { background-color: transparent; } - -/* Code highlighting */ -pre.rust .kw { color: #ab8ac1; } -pre.rust .kw-2, pre.rust .prelude-ty { color: #769acb; } -pre.rust .number, pre.rust .string { color: #83a300; } -pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, -pre.rust .attribute { color: #ee6868; } -pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } -pre.rust .lifetime { color: #d97f26; } -pre.rust .question-mark { - color: #ff9011; -} - -.example-wrap > pre.line-number { - border-color: #4a4949; -} - a.test-arrow { color: #dedede; background-color: rgba(78, 139, 202, 0.2); @@ -211,12 +145,12 @@ kbd { box-shadow: inset 0 -1px 0 #c6cbd1; } -#settings-menu > a, #help-button > button { +#settings-menu > a, #help-button > a { color: #000; } #settings-menu > a:hover, #settings-menu > a:focus, -#help-button > button:hover, #help-button > button:focus { +#help-button > a:hover, #help-button > a:focus { border-color: #ffb900; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 64335f629..5eb4bbcf8 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -30,6 +30,29 @@ --keyword-link-color: #3873ad; --mod-link-color: #3873ad; --link-color: #3873ad; + --sidebar-link-color: #356da4; + --sidebar-current-link-background-color: #fff; + --search-result-link-focus-background-color: #ccc; + --stab-background-color: #fff5d6; + --stab-code-color: #000; + --search-color: #000; + --code-highlight-kw-color: #8959a8; + --code-highlight-kw-2-color: #4271ae; + --code-highlight-lifetime-color: #b76514; + --code-highlight-prelude-color: #4271ae; + --code-highlight-prelude-val-color: #c82829; + --code-highlight-number-color: #718c00; + --code-highlight-string-color: #718c00; + --code-highlight-literal-color: #c82829; + --code-highlight-attribute-color: #c82829; + --code-highlight-self-color: #c82829; + --code-highlight-macro-color: #3e999f; + --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; } .slider { @@ -48,65 +71,8 @@ input:focus + .slider { */ } -.sidebar .current, -.sidebar a:hover { - background-color: #fff; -} - -.line-numbers span { color: #c67e2d; } -.line-numbers .line-highlighted { - background-color: #FDFFD3 !important; -} - -.search-results a:hover { - background-color: #ddd; -} - -.search-results a:focus { - color: #000 !important; - background-color: #ccc; -} -.search-results a:focus span { color: #000 !important; } -a.result-trait:focus { background-color: #c7b6ff; } -a.result-traitalias:focus { background-color: #c7b6ff; } -a.result-mod:focus, -a.result-externcrate:focus { background-color: #afc6e4; } -a.result-enum:focus { background-color: #e7b1a0; } -a.result-struct:focus { background-color: #e7b1a0; } -a.result-union:focus { background-color: #e7b1a0; } -a.result-fn:focus, -a.result-method:focus, -a.result-tymethod:focus { background-color: #c6afb3; } -a.result-type:focus { background-color: #e7b1a0; } -a.result-associatedtype:focus { background-color: #afc6e4; } -a.result-foreigntype:focus { background-color: #e7b1a0; } -a.result-attr:focus, -a.result-derive:focus, -a.result-macro:focus { background-color: #8ce488; } -a.result-constant:focus, -a.result-static:focus { background-color: #afc6e4; } -a.result-primitive:focus { background-color: #e7b1a0; } -a.result-keyword:focus { background-color: #afc6e4; } - .content .item-info::before { color: #ccc; } -.sidebar a { color: #356da4; } -.sidebar a.current.enum { color: #a63283; } -.sidebar a.current.struct { color: #a63283; } -.sidebar a.current.type { color: #a63283; } -.sidebar a.current.foreigntype { color: #356da4; } -.sidebar a.current.attr, -.sidebar a.current.derive, -.sidebar a.current.macro { color: #067901; } -.sidebar a.current.union { color: #a63283; } -.sidebar a.current.constant -.sidebar a.current.static { color: #356da4; } -.sidebar a.current.primitive { color: #a63283; } -.sidebar a.current.trait { color: #6849c3; } -.sidebar a.current.traitalias { color: #4b349e; } -.sidebar a.current.fn { color: #a67736; } -.sidebar a.current.keyword { color: #356da4; } - body.source .example-wrap pre.rust a { background: #eee; } @@ -122,29 +88,6 @@ body.source .example-wrap pre.rust a { filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%); } -.stab { background: #FFF5D6; border-color: #FFC600; } -.stab.portability > code { background: none; } - -.line-numbers :target { background-color: transparent; } - -/* Code highlighting */ -pre.rust .kw { color: #8959A8; } -pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; } -pre.rust .number, pre.rust .string { color: #718C00; } -pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, -pre.rust .attribute { color: #C82829; } -pre.rust .comment { color: #8E908C; } -pre.rust .doccomment { color: #4D4D4C; } -pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } -pre.rust .lifetime { color: #B76514; } -pre.rust .question-mark { - color: #ff9011; -} - -.example-wrap > pre.line-number { - border-color: #c7c7c7; -} - a.test-arrow { color: #f5f5f5; background-color: rgba(78, 139, 202, 0.2); @@ -196,8 +139,12 @@ kbd { box-shadow: inset 0 -1px 0 #c6cbd1; } +#settings-menu > a, #help-button > a { + color: #000; +} + #settings-menu > a:hover, #settings-menu > a:focus, -#help-button > button:hover, #help-button > button:focus { +#help-button > a:hover, #help-button > a:focus { border-color: #717171; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 6e9660ddc..33480fa41 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -55,7 +55,7 @@ function blurHandler(event, parentElem, hideCallback) { function setMobileTopbar() { // FIXME: It would be nicer to generate this text content directly in HTML, // but with the current code it's hard to get the right information in the right place. - const mobileLocationTitle = document.querySelector(".mobile-topbar h2.location"); + const mobileLocationTitle = document.querySelector(".mobile-topbar h2"); const locationTitle = document.querySelector(".sidebar h2.location"); if (mobileLocationTitle && locationTitle) { mobileLocationTitle.innerHTML = locationTitle.innerHTML; @@ -192,6 +192,8 @@ function loadCss(cssFileName) { } (function() { + const isHelpPage = window.location.pathname.endsWith("/help.html"); + function loadScript(url) { const script = document.createElement("script"); script.src = url; @@ -199,6 +201,9 @@ function loadCss(cssFileName) { } getSettingsButton().onclick = event => { + if (event.ctrlKey || event.altKey || event.metaKey) { + return; + } addClass(getSettingsButton(), "rotate"); event.preventDefault(); // Sending request for the CSS and the JS files at the same time so it will @@ -404,9 +409,12 @@ function loadCss(cssFileName) { break; case "+": + ev.preventDefault(); + expandAllDocs(); + break; case "-": ev.preventDefault(); - toggleAllDocs(); + collapseAllDocs(); break; case "?": @@ -442,18 +450,15 @@ function loadCss(cssFileName) { return; } - const div = document.createElement("div"); - div.className = "block " + shortty; const h3 = document.createElement("h3"); h3.innerHTML = `<a href="index.html#${id}">${longty}</a>`; - div.appendChild(h3); const ul = document.createElement("ul"); + ul.className = "block " + shortty; for (const item of filtered) { const name = item[0]; const desc = item[1]; // can be null - let klass = shortty; let path; if (shortty === "mod") { path = name + "/index.html"; @@ -461,20 +466,19 @@ function loadCss(cssFileName) { path = shortty + "." + name + ".html"; } const current_page = document.location.href.split("/").pop(); - if (path === current_page) { - klass += " current"; - } const link = document.createElement("a"); link.href = path; link.title = desc; - link.className = klass; + if (path === current_page) { + link.className = "current"; + } link.textContent = name; const li = document.createElement("li"); li.appendChild(link); ul.appendChild(li); } - div.appendChild(ul); - sidebar.appendChild(div); + sidebar.appendChild(h3); + sidebar.appendChild(ul); } if (sidebar) { @@ -522,7 +526,7 @@ function loadCss(cssFileName) { } let currentNbImpls = implementors.getElementsByClassName("impl").length; - const traitName = document.querySelector("h1.fqn > .in-band > .trait").textContent; + const traitName = document.querySelector("h1.fqn > .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. @@ -555,7 +559,6 @@ function loadCss(cssFileName) { const code = document.createElement("h3"); code.innerHTML = struct[TEXT_IDX]; addClass(code, "code-header"); - addClass(code, "in-band"); onEachLazy(code.getElementsByTagName("a"), elem => { const href = elem.getAttribute("href"); @@ -593,38 +596,52 @@ function loadCss(cssFileName) { return; } // Draw a convenient sidebar of known crates if we have a listing - const div = document.createElement("div"); - div.className = "block crate"; - div.innerHTML = "<h3>Crates</h3>"; + const h3 = document.createElement("h3"); + h3.innerHTML = "Crates"; const ul = document.createElement("ul"); - div.appendChild(ul); + ul.className = "block crate"; for (const crate of window.ALL_CRATES) { - let klass = "crate"; - if (window.rootPath !== "./" && crate === window.currentCrate) { - klass += " current"; - } const link = document.createElement("a"); link.href = window.rootPath + crate + "/index.html"; - link.className = klass; + if (window.rootPath !== "./" && crate === window.currentCrate) { + link.className = "current"; + } link.textContent = crate; const li = document.createElement("li"); li.appendChild(link); ul.appendChild(li); } - sidebarElems.appendChild(div); + sidebarElems.appendChild(h3); + sidebarElems.appendChild(ul); } + function expandAllDocs() { + const innerToggle = document.getElementById(toggleAllDocsId); + removeClass(innerToggle, "will-expand"); + onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { + if (!hasClass(e, "type-contents-toggle")) { + e.open = true; + } + }); + innerToggle.title = "collapse all docs"; + innerToggle.children[0].innerText = "\u2212"; // "\u2212" is "−" minus sign + } - function labelForToggleButton(sectionIsCollapsed) { - if (sectionIsCollapsed) { - // button will expand the section - return "+"; - } - // button will collapse the section - // note that this text is also set in the HTML template in ../render/mod.rs - return "\u2212"; // "\u2212" is "−" minus sign + function collapseAllDocs() { + const innerToggle = document.getElementById(toggleAllDocsId); + addClass(innerToggle, "will-expand"); + onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { + if (e.parentNode.id !== "implementations-list" || + (!hasClass(e, "implementors-toggle") && + !hasClass(e, "type-contents-toggle")) + ) { + e.open = false; + } + }); + innerToggle.title = "expand all docs"; + innerToggle.children[0].innerText = "+"; } function toggleAllDocs() { @@ -632,29 +649,11 @@ function loadCss(cssFileName) { if (!innerToggle) { return; } - let sectionIsCollapsed = false; if (hasClass(innerToggle, "will-expand")) { - removeClass(innerToggle, "will-expand"); - onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { - if (!hasClass(e, "type-contents-toggle")) { - e.open = true; - } - }); - innerToggle.title = "collapse all docs"; + expandAllDocs(); } else { - addClass(innerToggle, "will-expand"); - onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { - if (e.parentNode.id !== "implementations-list" || - (!hasClass(e, "implementors-toggle") && - !hasClass(e, "type-contents-toggle")) - ) { - e.open = false; - } - }); - sectionIsCollapsed = true; - innerToggle.title = "expand all docs"; + collapseAllDocs(); } - innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed); } (function() { @@ -697,60 +696,95 @@ function loadCss(cssFileName) { } }()); + window.rustdoc_add_line_numbers_to_examples = () => { + onEachLazy(document.getElementsByClassName("rust-example-rendered"), x => { + const parent = x.parentNode; + const line_numbers = parent.querySelectorAll(".example-line-numbers"); + if (line_numbers.length > 0) { + return; + } + const count = x.textContent.split("\n").length; + const elems = []; + for (let i = 0; i < count; ++i) { + elems.push(i + 1); + } + const node = document.createElement("pre"); + addClass(node, "example-line-numbers"); + node.innerHTML = elems.join("\n"); + parent.insertBefore(node, x); + }); + }; + + window.rustdoc_remove_line_numbers_from_examples = () => { + onEachLazy(document.getElementsByClassName("rust-example-rendered"), x => { + const parent = x.parentNode; + const line_numbers = parent.querySelectorAll(".example-line-numbers"); + for (const node of line_numbers) { + parent.removeChild(node); + } + }); + }; + (function() { // To avoid checking on "rustdoc-line-numbers" value on every loop... if (getSettingValue("line-numbers") === "true") { - onEachLazy(document.getElementsByClassName("rust-example-rendered"), x => { - const count = x.textContent.split("\n").length; - const elems = []; - for (let i = 0; i < count; ++i) { - elems.push(i + 1); - } - const node = document.createElement("pre"); - addClass(node, "line-number"); - node.innerHTML = elems.join("\n"); - x.parentNode.insertBefore(node, x); - }); + window.rustdoc_add_line_numbers_to_examples(); } }()); let oldSidebarScrollPosition = null; - function showSidebar() { - if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + // Scroll locking used both here and in source-script.js + + window.rustdocMobileScrollLock = function() { + const mobile_topbar = document.querySelector(".mobile-topbar"); + if (window.innerWidth <= window.RUSTDOC_MOBILE_BREAKPOINT) { // This is to keep the scroll position on mobile. oldSidebarScrollPosition = window.scrollY; document.body.style.width = `${document.body.offsetWidth}px`; document.body.style.position = "fixed"; document.body.style.top = `-${oldSidebarScrollPosition}px`; - document.querySelector(".mobile-topbar").style.top = `${oldSidebarScrollPosition}px`; - document.querySelector(".mobile-topbar").style.position = "relative"; + if (mobile_topbar) { + mobile_topbar.style.top = `${oldSidebarScrollPosition}px`; + mobile_topbar.style.position = "relative"; + } } else { oldSidebarScrollPosition = null; } - const sidebar = document.getElementsByClassName("sidebar")[0]; - addClass(sidebar, "shown"); - } + }; - function hideSidebar() { + window.rustdocMobileScrollUnlock = function() { + const mobile_topbar = document.querySelector(".mobile-topbar"); if (oldSidebarScrollPosition !== null) { // This is to keep the scroll position on mobile. document.body.style.width = ""; document.body.style.position = ""; document.body.style.top = ""; - document.querySelector(".mobile-topbar").style.top = ""; - document.querySelector(".mobile-topbar").style.position = ""; + if (mobile_topbar) { + mobile_topbar.style.top = ""; + mobile_topbar.style.position = ""; + } // The scroll position is lost when resetting the style, hence why we store it in // `oldSidebarScrollPosition`. window.scrollTo(0, oldSidebarScrollPosition); oldSidebarScrollPosition = null; } + }; + + function showSidebar() { + window.rustdocMobileScrollLock(); + const sidebar = document.getElementsByClassName("sidebar")[0]; + addClass(sidebar, "shown"); + } + + function hideSidebar() { + window.rustdocMobileScrollUnlock(); const sidebar = document.getElementsByClassName("sidebar")[0]; removeClass(sidebar, "shown"); } window.addEventListener("resize", () => { - if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT && + if (window.innerWidth > window.RUSTDOC_MOBILE_BREAKPOINT && oldSidebarScrollPosition !== null) { // If the user opens the sidebar in "mobile" mode, and then grows the browser window, // we need to switch away from mobile mode and make the main content area scrollable. @@ -859,7 +893,10 @@ function loadCss(cssFileName) { rustdoc_version.appendChild(rustdoc_version_code); const container = document.createElement("div"); - container.className = "popover"; + if (!isHelpPage) { + container.className = "popover"; + } + container.id = "help"; container.style.display = "none"; const side_by_side = document.createElement("div"); @@ -871,15 +908,22 @@ function loadCss(cssFileName) { container.appendChild(side_by_side); container.appendChild(rustdoc_version); - const help_button = getHelpButton(); - help_button.appendChild(container); - - container.onblur = helpBlurHandler; - container.onclick = event => { - event.preventDefault(); - }; - help_button.onblur = helpBlurHandler; - help_button.children[0].onblur = helpBlurHandler; + if (isHelpPage) { + const help_section = document.createElement("section"); + help_section.appendChild(container); + document.getElementById("main-content").appendChild(help_section); + container.style.display = "block"; + } else { + const help_button = getHelpButton(); + help_button.appendChild(container); + + container.onblur = helpBlurHandler; + container.onclick = event => { + event.preventDefault(); + }; + help_button.onblur = helpBlurHandler; + help_button.children[0].onblur = helpBlurHandler; + } return container; } @@ -888,7 +932,7 @@ function loadCss(cssFileName) { * Hide all the popover menus. */ window.hidePopoverMenus = function() { - onEachLazy(document.querySelectorAll(".search-container .popover"), elem => { + onEachLazy(document.querySelectorAll(".search-form .popover"), elem => { elem.style.display = "none"; }); }; @@ -920,19 +964,43 @@ function loadCss(cssFileName) { } } - document.querySelector(`#${HELP_BUTTON_ID} > button`).addEventListener("click", event => { - const target = event.target; - if (target.tagName !== "BUTTON" || target.parentElement.id !== HELP_BUTTON_ID) { - return; - } - const menu = getHelpMenu(true); - const shouldShowHelp = menu.style.display === "none"; - if (shouldShowHelp) { - showHelp(); - } else { - window.hidePopoverMenus(); - } - }); + if (isHelpPage) { + showHelp(); + document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click", event => { + // Already on the help page, make help button a no-op. + const target = event.target; + if (target.tagName !== "A" || + target.parentElement.id !== HELP_BUTTON_ID || + event.ctrlKey || + event.altKey || + event.metaKey) { + return; + } + event.preventDefault(); + }); + } else { + document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click", event => { + // By default, have help button open docs in a popover. + // If user clicks with a moderator, though, use default browser behavior, + // probably opening in a new window or tab. + const target = event.target; + if (target.tagName !== "A" || + target.parentElement.id !== HELP_BUTTON_ID || + event.ctrlKey || + event.altKey || + event.metaKey) { + return; + } + event.preventDefault(); + const menu = getHelpMenu(true); + const shouldShowHelp = menu.style.display === "none"; + if (shouldShowHelp) { + showHelp(); + } else { + window.hidePopoverMenus(); + } + }); + } setMobileTopbar(); addSidebarItems(); diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js index fd7a14497..d0fd115fd 100644 --- a/src/librustdoc/html/static/js/scrape-examples.js +++ b/src/librustdoc/html/static/js/scrape-examples.js @@ -8,7 +8,7 @@ // Scroll code block to the given code location function scrollToLoc(elt, loc) { - const lines = elt.querySelector(".line-numbers"); + const lines = elt.querySelector(".src-line-numbers"); let scrollOffset; // If the block is greater than the size of the viewer, diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 797b931af..5e1c7e6f0 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -19,6 +19,13 @@ updateSystemTheme(); updateLightAndDark(); break; + case "line-numbers": + if (value === true) { + window.rustdoc_add_line_numbers_to_examples(); + } else { + window.rustdoc_remove_line_numbers_from_examples(); + } + break; } } @@ -209,7 +216,9 @@ const innerHTML = `<div class="settings">${buildSettingsPageSections(settings)}</div>`; const el = document.createElement(elementKind); el.id = "settings"; - el.className = "popover"; + if (!isSettingsPage) { + el.className = "popover"; + } el.innerHTML = innerHTML; if (isSettingsPage) { diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js index 06d15d9e5..0b9368dd8 100644 --- a/src/librustdoc/html/static/js/source-script.js +++ b/src/librustdoc/html/static/js/source-script.js @@ -10,7 +10,6 @@ (function() { const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value; -let oldScrollPosition = null; const NAME_OFFSET = 0; const DIRS_OFFSET = 1; @@ -70,44 +69,18 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) { function toggleSidebar() { const child = this.parentNode.children[0]; if (child.innerText === ">") { - if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { - // This is to keep the scroll position on mobile. - oldScrollPosition = window.scrollY; - document.body.style.position = "fixed"; - document.body.style.top = `-${oldScrollPosition}px`; - } else { - oldScrollPosition = null; - } + window.rustdocMobileScrollLock(); addClass(document.documentElement, "source-sidebar-expanded"); child.innerText = "<"; updateLocalStorage("source-sidebar-show", "true"); } else { - if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) { - // This is to keep the scroll position on mobile. - document.body.style.position = ""; - document.body.style.top = ""; - // The scroll position is lost when resetting the style, hence why we store it in - // `oldScrollPosition`. - window.scrollTo(0, oldScrollPosition); - oldScrollPosition = null; - } + window.rustdocMobileScrollUnlock(); removeClass(document.documentElement, "source-sidebar-expanded"); child.innerText = ">"; updateLocalStorage("source-sidebar-show", "false"); } } -window.addEventListener("resize", () => { - if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) { - // If the user opens the sidebar in "mobile" mode, and then grows the browser window, - // we need to switch away from mobile mode and make the main content area scrollable. - document.body.style.position = ""; - document.body.style.top = ""; - window.scrollTo(0, oldScrollPosition); - oldScrollPosition = null; - } -}); - function createSidebarToggle() { const sidebarToggle = document.createElement("div"); sidebarToggle.id = "sidebar-toggle"; @@ -125,7 +98,7 @@ function createSidebarToggle() { return sidebarToggle; } -// This function is called from "source-files.js", generated in `html/render/mod.rs`. +// This function is called from "source-files.js", generated in `html/render/write_shared.rs`. // eslint-disable-next-line no-unused-vars function createSourceSidebar() { const container = document.querySelector("nav.sidebar"); @@ -183,7 +156,7 @@ function highlightSourceLines(match) { if (x) { x.scrollIntoView(); } - onEachLazy(document.getElementsByClassName("line-numbers"), e => { + onEachLazy(document.getElementsByClassName("src-line-numbers"), e => { onEachLazy(e.getElementsByTagName("span"), i_e => { removeClass(i_e, "line-highlighted"); }); @@ -245,7 +218,7 @@ window.addEventListener("hashchange", () => { } }); -onEachLazy(document.getElementsByClassName("line-numbers"), el => { +onEachLazy(document.getElementsByClassName("src-line-numbers"), el => { el.addEventListener("click", handleSourceHighlight); }); diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 0c5389d45..b462a2c50 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -10,9 +10,9 @@ window.currentTheme = document.getElementById("themeStyle"); window.mainTheme = document.getElementById("mainThemeStyle"); // WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY -// If you update this line, then you also need to update the two media queries with the same +// If you update this line, then you also need to update the media query with the same // warning in rustdoc.css -window.RUSTDOC_MOBILE_BREAKPOINT = 701; +window.RUSTDOC_MOBILE_BREAKPOINT = 700; const settingsDataset = (function() { const settingsElement = document.getElementById("default-settings"); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 7caffeae3..c32386916 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -73,6 +73,7 @@ </div> {#- -#} <![endif]--> {#- -#} {{- layout.external_html.before_content|safe -}} + {%- if page.css_class != "source" -%} <nav class="mobile-topbar"> {#- -#} <button class="sidebar-menu-toggle">☰</button> {#- -#} <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#} @@ -84,9 +85,11 @@ {%- endif -%} </div> {#- -#} </a> {#- -#} - <h2 class="location"></h2> {#- -#} + <h2></h2> {#- -#} </nav> {#- -#} + {%- endif -%} <nav class="sidebar"> {#- -#} + {%- if page.css_class != "source" -%} <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#} <div class="logo-container"> {#- -#} {%- if !layout.logo.is_empty() %} @@ -96,11 +99,13 @@ {%- endif -%} </div> {#- -#} </a> {#- -#} + {%- endif -%} {{- sidebar|safe -}} </nav> {#- -#} <main> {#- -#} <div class="width-limiter"> {#- -#} - <div class="sub-container"> {#- -#} + <nav class="sub"> {#- -#} + {%- if page.css_class == "source" -%} <a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#} {%- if !layout.logo.is_empty() %} <img src="{{layout.logo}}" alt="logo"> {#- -#} @@ -108,30 +113,27 @@ <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#} {%- endif -%} </a> {#- -#} - <nav class="sub"> {#- -#} - <form class="search-form"> {#- -#} - <div class="search-container"> {#- -#} - <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#} - <input {# -#} - class="search-input" {# -#} - name="search" {# -#} - autocomplete="off" {# -#} - spellcheck="false" {# -#} - placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#} - type="search"> {#- -#} - <div id="help-button" title="help" tabindex="-1"> {#- -#} - <button type="button">?</button> {#- -#} - </div> {#- -#} - <div id="settings-menu" tabindex="-1"> {#- -#} - <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#} - <img width="22" height="22" alt="Change settings" {# -#} - src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#} - </a> {#- -#} - </div> {#- -#} - </div> {#- -#} - </form> {#- -#} - </nav> {#- -#} - </div> {#- -#} + {%- endif -%} + <form class="search-form"> {#- -#} + <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#} + <input {# -#} + class="search-input" {# -#} + name="search" {# -#} + autocomplete="off" {# -#} + spellcheck="false" {# -#} + placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#} + type="search"> {#- -#} + <div id="help-button" title="help" tabindex="-1"> {#- -#} + <a href="{{page.root_path|safe}}help.html">?</a> {#- -#} + </div> {#- -#} + <div id="settings-menu" tabindex="-1"> {#- -#} + <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#} + <img width="22" height="22" alt="Change settings" {# -#} + src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#} + </a> {#- -#} + </div> {#- -#} + </form> {#- -#} + </nav> {#- -#} <section id="main-content" class="content">{{- content|safe -}}</section> {#- -#} </div> {#- -#} </main> {#- -#} diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html index c755157d2..b6ce3ea3d 100644 --- a/src/librustdoc/html/templates/print_item.html +++ b/src/librustdoc/html/templates/print_item.html @@ -1,18 +1,16 @@ <div class="main-heading"> {#- -#} <h1 class="fqn"> {#- -#} - <span class="in-band"> {#- -#} - {{-typ-}} - {#- The breadcrumbs of the item path, like std::string -#} - {%- for component in path_components -%} - <a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr> - {%- endfor -%} - <a class="{{item_type}}" href="#">{{name}}</a> {#- -#} - <button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#} - <img src="{{static_root_path|safe}}clipboard{{page.resource_suffix}}.svg" {# -#} - width="19" height="18" {# -#} - alt="Copy item path"> {#- -#} - </button> {#- -#} - </span> {#- -#} + {{-typ-}} + {#- The breadcrumbs of the item path, like std::string -#} + {%- for component in path_components -%} + <a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr> + {%- endfor -%} + <a class="{{item_type}}" href="#">{{name}}</a> {#- -#} + <button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#} + <img src="{{static_root_path|safe}}clipboard{{page.resource_suffix}}.svg" {# -#} + width="19" height="18" {# -#} + alt="Copy item path"> {#- -#} + </button> {#- -#} </h1> {#- -#} <span class="out-of-band"> {#- -#} {% if !stability_since_raw.is_empty() %} |