diff options
Diffstat (limited to 'src/librustdoc/html')
| -rw-r--r-- | src/librustdoc/html/format.rs | 43 | ||||
| -rw-r--r-- | src/librustdoc/html/highlight.rs | 7 | ||||
| -rw-r--r-- | src/librustdoc/html/markdown.rs | 17 | ||||
| -rw-r--r-- | src/librustdoc/html/render/context.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/html/render/mod.rs | 111 | ||||
| -rw-r--r-- | src/librustdoc/html/render/print_item.rs | 33 | ||||
| -rw-r--r-- | src/librustdoc/html/render/search_index.rs | 215 | ||||
| -rw-r--r-- | src/librustdoc/html/render/search_index/encode.rs | 23 | ||||
| -rw-r--r-- | src/librustdoc/html/static/css/noscript.css | 1 | ||||
| -rw-r--r-- | src/librustdoc/html/static/css/rustdoc.css | 48 | ||||
| -rw-r--r-- | src/librustdoc/html/static/images/clipboard.svg | 1 | ||||
| -rw-r--r-- | src/librustdoc/html/static/images/wheel.svg | 1 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/externs.js | 19 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/main.js | 20 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/search.js | 87 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/storage.js | 43 | ||||
| -rw-r--r-- | src/librustdoc/html/static_files.rs | 2 | ||||
| -rw-r--r-- | src/librustdoc/html/templates/page.html | 27 |
18 files changed, 470 insertions, 232 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f82b89fdd5f..57949001774 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -13,7 +13,7 @@ use std::fmt::{self, Display, Write}; use std::iter::{self, once}; use rustc_ast as ast; -use rustc_attr::{ConstStability, StabilityLevel}; +use rustc_attr::{ConstStability, StabilityLevel, StableSince}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -594,9 +594,9 @@ fn generate_item_def_id_path( root_path: Option<&str>, original_def_kind: DefKind, ) -> Result<(String, ItemType, Vec<Symbol>), HrefError> { - use crate::rustc_trait_selection::infer::TyCtxtInferExt; - use crate::rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_middle::traits::ObligationCause; + use rustc_trait_selection::infer::TyCtxtInferExt; + use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; let tcx = cx.tcx(); let crate_name = tcx.crate_name(def_id.krate); @@ -1013,7 +1013,7 @@ fn fmt_type<'cx>( } clean::BareFunction(ref decl) => { print_higher_ranked_params_with_space(&decl.generic_params, cx).fmt(f)?; - decl.unsafety.print_with_space().fmt(f)?; + decl.safety.print_with_space().fmt(f)?; print_abi_with_space(decl.abi).fmt(f)?; if f.alternate() { f.write_str("fn")?; @@ -1303,7 +1303,7 @@ impl clean::Impl { // Link should match `# Trait implementations` print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?; - bare_fn.unsafety.print_with_space().fmt(f)?; + bare_fn.safety.print_with_space().fmt(f)?; print_abi_with_space(bare_fn.abi).fmt(f)?; let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" }; primitive_link_fragment( @@ -1604,11 +1604,11 @@ pub(crate) trait PrintWithSpace { fn print_with_space(&self) -> &str; } -impl PrintWithSpace for hir::Unsafety { +impl PrintWithSpace for hir::Safety { fn print_with_space(&self) -> &str { match self { - hir::Unsafety::Unsafe => "unsafe ", - hir::Unsafety::Normal => "", + hir::Safety::Unsafe => "unsafe ", + hir::Safety::Safe => "", } } } @@ -1633,17 +1633,24 @@ impl PrintWithSpace for hir::Mutability { pub(crate) fn print_constness_with_space( c: &hir::Constness, - s: Option<ConstStability>, + overall_stab: Option<StableSince>, + const_stab: Option<ConstStability>, ) -> &'static str { - match (c, s) { - // const stable or when feature(staged_api) is not set - ( - hir::Constness::Const, - Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }), - ) - | (hir::Constness::Const, None) => "const ", - // const unstable or not const - _ => "", + match c { + hir::Constness::Const => match (overall_stab, const_stab) { + // const stable... + (_, Some(ConstStability { level: StabilityLevel::Stable { .. }, .. })) + // ...or when feature(staged_api) is not set... + | (_, None) + // ...or when const unstable, but overall unstable too + | (None, Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => { + "const " + } + // const unstable (and overall stable) + (Some(_), Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => "", + }, + // not const + hir::Constness::NotConst => "", } } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index aa5998876d9..336d18a1df1 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -876,9 +876,10 @@ impl<'src> Classifier<'src> { }, Some(c) => c, }, - TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => { - Class::Ident(self.new_span(before, text)) - } + TokenKind::RawIdent + | TokenKind::UnknownPrefix + | TokenKind::InvalidPrefix + | TokenKind::InvalidIdent => Class::Ident(self.new_span(before, text)), TokenKind::Lifetime { .. } => Class::Lifetime, TokenKind::Eof => panic!("Eof in advance"), }; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 64f0e096cd0..362f9021671 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -35,13 +35,13 @@ use rustc_resolve::rustdoc::may_be_doc_link; use rustc_span::edition::Edition; use rustc_span::{Span, Symbol}; -use once_cell::sync::Lazy; use std::borrow::Cow; use std::collections::VecDeque; use std::fmt::Write; use std::iter::Peekable; use std::ops::{ControlFlow, Range}; use std::str::{self, CharIndices}; +use std::sync::OnceLock; use crate::clean::RenderedLink; use crate::doctest; @@ -834,8 +834,9 @@ impl<'tcx> ExtraInfo<'tcx> { crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, self.tcx.local_def_id_to_hir_id(def_id), self.sp, - msg, - |_| {}, + |lint| { + lint.primary_message(msg); + }, ); } } @@ -850,8 +851,10 @@ impl<'tcx> ExtraInfo<'tcx> { crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, self.tcx.local_def_id_to_hir_id(def_id), self.sp, - msg, - f, + |lint| { + lint.primary_message(msg); + f(lint); + }, ); } } @@ -1994,7 +1997,7 @@ pub struct IdMap { } // The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly. -static DEFAULT_ID_MAP: Lazy<FxHashMap<Cow<'static, str>, usize>> = Lazy::new(|| init_id_map()); +static DEFAULT_ID_MAP: OnceLock<FxHashMap<Cow<'static, str>, usize>> = OnceLock::new(); fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { let mut map = FxHashMap::default(); @@ -2051,7 +2054,7 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { impl IdMap { pub fn new() -> Self { - IdMap { map: DEFAULT_ID_MAP.clone() } + IdMap { map: DEFAULT_ID_MAP.get_or_init(init_id_map).clone() } } pub(crate) fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 4cab2d64257..db1119eca1d 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -78,8 +78,10 @@ pub(crate) struct Context<'tcx> { } // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. -#[cfg(all(not(windows), target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(not(windows), target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Context<'_>, 160); +#[cfg(all(windows, target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(Context<'_>, 168); /// Shared mutable state used in [`Context`] and elsewhere. pub(crate) struct SharedContext<'tcx> { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index a949f795753..8ee4cc5c75e 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -52,6 +52,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::Mutability; +use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::RustcVersion; use rustc_span::{ @@ -111,11 +112,13 @@ pub(crate) enum RenderMode { #[derive(Debug)] pub(crate) struct IndexItem { pub(crate) ty: ItemType, + pub(crate) defid: Option<DefId>, pub(crate) name: Symbol, pub(crate) path: String, pub(crate) desc: String, pub(crate) parent: Option<DefId>, pub(crate) parent_idx: Option<isize>, + pub(crate) exact_path: Option<String>, pub(crate) impl_id: Option<DefId>, pub(crate) search_type: Option<IndexItemFunctionType>, pub(crate) aliases: Box<[Symbol]>, @@ -180,6 +183,7 @@ pub(crate) enum RenderTypeId { Primitive(clean::PrimitiveType), AssociatedType(Symbol), Index(isize), + Mut, } impl RenderTypeId { @@ -924,13 +928,15 @@ fn assoc_method( // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove // this condition. let constness = match render_mode { - RenderMode::Normal => { - print_constness_with_space(&header.constness, meth.const_stability(tcx)) - } + RenderMode::Normal => print_constness_with_space( + &header.constness, + meth.stable_since(tcx), + meth.const_stability(tcx), + ), RenderMode::ForDeref { .. } => "", }; let asyncness = header.asyncness.print_with_space(); - let unsafety = header.unsafety.print_with_space(); + let safety = header.safety.print_with_space(); let abi = print_abi_with_space(header.abi).to_string(); let href = assoc_href_attr(meth, link, cx); @@ -941,7 +947,7 @@ fn assoc_method( + defaultness.len() + constness.len() + asyncness.len() - + unsafety.len() + + safety.len() + abi.len() + name.as_str().len() + generics_len; @@ -960,14 +966,14 @@ fn assoc_method( w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len()); write!( w, - "{indent}{vis}{defaultness}{constness}{asyncness}{unsafety}{abi}fn \ + "{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \ <a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}", indent = indent_str, vis = vis, defaultness = defaultness, constness = constness, asyncness = asyncness, - unsafety = unsafety, + safety = safety, abi = abi, href = href, name = name, @@ -994,48 +1000,41 @@ fn assoc_method( /// consequence of the above rules. fn render_stability_since_raw_with_extra( w: &mut Buffer, - ver: Option<StableSince>, + stable_version: Option<StableSince>, const_stability: Option<ConstStability>, - containing_ver: Option<StableSince>, - containing_const_ver: Option<StableSince>, extra_class: &str, ) -> bool { - let stable_version = if ver != containing_ver - && let Some(ver) = &ver - { - since_to_string(ver) - } else { - None - }; - let mut title = String::new(); let mut stability = String::new(); - if let Some(ver) = stable_version { - stability.push_str(ver.as_str()); - title.push_str(&format!("Stable since Rust version {ver}")); + if let Some(version) = stable_version.and_then(|version| since_to_string(&version)) { + stability.push_str(&version); + title.push_str(&format!("Stable since Rust version {version}")); } let const_title_and_stability = match const_stability { - Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. }) - if Some(since) != containing_const_ver => - { + Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. }) => { since_to_string(&since) .map(|since| (format!("const since {since}"), format!("const: {since}"))) } Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => { - let unstable = if let Some(n) = issue { - format!( - "<a \ + if stable_version.is_none() { + // don't display const unstable if entirely unstable + None + } else { + let unstable = if let Some(n) = issue { + format!( + "<a \ href=\"https://github.com/rust-lang/rust/issues/{n}\" \ title=\"Tracking issue for {feature}\"\ >unstable</a>" - ) - } else { - String::from("unstable") - }; + ) + } else { + String::from("unstable") + }; - Some((String::from("const unstable"), format!("const: {unstable}"))) + Some((String::from("const unstable"), format!("const: {unstable}"))) + } } _ => None, }; @@ -1074,17 +1073,8 @@ fn render_stability_since_raw( w: &mut Buffer, ver: Option<StableSince>, const_stability: Option<ConstStability>, - containing_ver: Option<StableSince>, - containing_const_ver: Option<StableSince>, ) -> bool { - render_stability_since_raw_with_extra( - w, - ver, - const_stability, - containing_ver, - containing_const_ver, - "", - ) + render_stability_since_raw_with_extra(w, ver, const_stability, "") } fn render_assoc_item( @@ -1441,6 +1431,10 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O if let Some(impls) = cx.cache().impls.get(&did) { for i in impls { let impl_ = i.inner_impl(); + if impl_.polarity != ty::ImplPolarity::Positive { + continue; + } + if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. @@ -1476,6 +1470,10 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { for i in impls { let impl_ = i.inner_impl(); + if impl_.polarity != ty::ImplPolarity::Positive { + continue; + } + if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. @@ -1583,7 +1581,6 @@ fn render_impl( cx: &mut Context<'_>, item: &clean::Item, parent: &clean::Item, - containing_item: &clean::Item, link: AssocItemLink<'_>, render_mode: RenderMode, is_default_item: bool, @@ -1679,7 +1676,7 @@ fn render_impl( }) .map(|item| format!("{}.{name}", item.type_())); write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"); - render_rightside(w, cx, item, containing_item, render_mode); + render_rightside(w, cx, item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>"); @@ -1701,7 +1698,7 @@ fn render_impl( let source_id = format!("{item_type}.{name}"); let id = cx.derive_id(&source_id); write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"); - render_rightside(w, cx, item, containing_item, render_mode); + render_rightside(w, cx, item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>"); @@ -1787,7 +1784,6 @@ fn render_impl( cx, trait_item, if trait_.is_some() { &i.impl_item } else { parent }, - parent, link, render_mode, false, @@ -1803,7 +1799,6 @@ fn render_impl( t: &clean::Trait, i: &clean::Impl, parent: &clean::Item, - containing_item: &clean::Item, render_mode: RenderMode, rendering_params: ImplRenderingParameters, ) { @@ -1831,7 +1826,6 @@ fn render_impl( cx, trait_item, parent, - containing_item, assoc_link, render_mode, true, @@ -1854,7 +1848,6 @@ fn render_impl( t, i.inner_impl(), &i.impl_item, - parent, render_mode, rendering_params, ); @@ -1876,7 +1869,6 @@ fn render_impl( cx, i, parent, - parent, rendering_params.show_def_docs, use_absolute, aliases, @@ -1924,20 +1916,14 @@ fn render_impl( // Render the items that appear on the right side of methods, impls, and // associated types. For example "1.0.0 (const: 1.39.0) · source". -fn render_rightside( - w: &mut Buffer, - cx: &Context<'_>, - item: &clean::Item, - containing_item: &clean::Item, - render_mode: RenderMode, -) { +fn render_rightside(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, render_mode: RenderMode) { let tcx = cx.tcx(); // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove // this condition. - let (const_stability, const_stable_since) = match render_mode { - RenderMode::Normal => (item.const_stability(tcx), containing_item.const_stable_since(tcx)), - RenderMode::ForDeref { .. } => (None, None), + let const_stability = match render_mode { + RenderMode::Normal => item.const_stability(tcx), + RenderMode::ForDeref { .. } => None, }; let src_href = cx.src_href(item); let has_src_ref = src_href.is_some(); @@ -1947,8 +1933,6 @@ fn render_rightside( &mut rightside, item.stable_since(tcx), const_stability, - containing_item.stable_since(tcx), - const_stable_since, if has_src_ref { "" } else { " rightside" }, ); if let Some(link) = src_href { @@ -1970,7 +1954,6 @@ pub(crate) fn render_impl_summary( cx: &mut Context<'_>, i: &Impl, parent: &clean::Item, - containing_item: &clean::Item, show_def_docs: bool, use_absolute: Option<bool>, // This argument is used to reference same type with different paths to avoid duplication @@ -1985,7 +1968,7 @@ pub(crate) fn render_impl_summary( format!(" data-aliases=\"{}\"", aliases.join(",")) }; write!(w, "<section id=\"{id}\" class=\"impl\"{aliases}>"); - render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal); + render_rightside(w, cx, &i.impl_item, RenderMode::Normal); write!( w, "<a href=\"#{id}\" class=\"anchor\">§</a>\ diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 168db5c0948..c5b88c7a951 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -214,8 +214,6 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf &mut stability_since_raw, item.stable_since(cx.tcx()), item.const_stability(cx.tcx()), - None, - None, ); let stability_since_raw: String = stability_since_raw.into_inner(); @@ -494,7 +492,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: let unsafety_flag = match *myitem.kind { clean::FunctionItem(_) | clean::ForeignFunctionItem(_) - if myitem.fn_header(tcx).unwrap().unsafety == hir::Unsafety::Unsafe => + if myitem.fn_header(tcx).unwrap().safety == hir::Safety::Unsafe => { "<sup title=\"unsafe function\">⚠</sup>" } @@ -617,8 +615,19 @@ fn extra_info_tags<'a, 'tcx: 'a>( fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) { let tcx = cx.tcx(); let header = it.fn_header(tcx).expect("printing a function which isn't a function"); - let constness = print_constness_with_space(&header.constness, it.const_stability(tcx)); - let unsafety = header.unsafety.print_with_space(); + debug!( + "item_function/const: {:?} {:?} {:?} {:?}", + it.name, + &header.constness, + it.stable_since(tcx), + it.const_stability(tcx), + ); + let constness = print_constness_with_space( + &header.constness, + it.stable_since(tcx), + it.const_stability(tcx), + ); + let safety = header.safety.print_with_space(); let abi = print_abi_with_space(header.abi).to_string(); let asyncness = header.asyncness.print_with_space(); let visibility = visibility_print_with_space(it, cx).to_string(); @@ -629,7 +638,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle + visibility.len() + constness.len() + asyncness.len() - + unsafety.len() + + safety.len() + abi.len() + name.as_str().len() + generics_len; @@ -640,13 +649,13 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle w.reserve(header_len); write!( w, - "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \ + "{attrs}{vis}{constness}{asyncness}{safety}{abi}fn \ {name}{generics}{decl}{notable_traits}{where_clause}", attrs = render_attributes_in_pre(it, "", cx), vis = visibility, constness = constness, asyncness = asyncness, - unsafety = unsafety, + safety = safety, abi = abi, name = name, generics = f.generics.print(cx), @@ -676,10 +685,10 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: wrap_item(w, |mut w| { write!( w, - "{attrs}{vis}{unsafety}{is_auto}trait {name}{generics}{bounds}", + "{attrs}{vis}{safety}{is_auto}trait {name}{generics}{bounds}", attrs = render_attributes_in_pre(it, "", cx), vis = visibility_print_with_space(it, cx), - unsafety = t.unsafety(tcx).print_with_space(), + safety = t.safety(tcx).print_with_space(), is_auto = if t.is_auto(tcx) { "auto " } else { "" }, name = it.name.unwrap(), generics = t.generics.print(cx), @@ -825,7 +834,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>"); } write!(w, "<section id=\"{id}\" class=\"method\">"); - render_rightside(w, cx, m, t, RenderMode::Normal); + render_rightside(w, cx, m, RenderMode::Normal); write!(w, "<h4 class=\"code-header\">"); render_assoc_item( w, @@ -1686,8 +1695,6 @@ fn item_variants( w, variant.stable_since(tcx), variant.const_stability(tcx), - it.stable_since(tcx), - it.const_stable_since(tcx), " rightside", ); w.write_str("<h3 class=\"code-header\">"); diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 7083999de68..e635c1e611d 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::sym; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{kw, Symbol}; use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer}; use thin_vec::ThinVec; @@ -59,10 +59,13 @@ pub(crate) fn build_index<'tcx>( cache: &mut Cache, tcx: TyCtxt<'tcx>, ) -> SerializedSearchIndex { + // Maps from ID to position in the `crate_paths` array. let mut itemid_to_pathid = FxHashMap::default(); let mut primitives = FxHashMap::default(); let mut associated_types = FxHashMap::default(); - let mut crate_paths = vec![]; + + // item type, display path, re-exported internal path + let mut crate_paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)> = vec![]; // Attach all orphan items to the type's definition if the type // has since been learned. @@ -72,11 +75,13 @@ pub(crate) fn build_index<'tcx>( let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); cache.search_index.push(IndexItem { ty: item.type_(), + defid: item.item_id.as_def_id(), name: item.name.unwrap(), path: join_with_double_colon(&fqp[..fqp.len() - 1]), desc, parent: Some(parent), parent_idx: None, + exact_path: None, impl_id, search_type: get_function_type_for_search( item, @@ -126,9 +131,10 @@ pub(crate) fn build_index<'tcx>( map: &mut FxHashMap<F, isize>, itemid: F, lastpathid: &mut isize, - crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>, + crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>, item_type: ItemType, path: &[Symbol], + exact_path: Option<&[Symbol]>, ) -> RenderTypeId { match map.entry(itemid) { Entry::Occupied(entry) => RenderTypeId::Index(*entry.get()), @@ -136,7 +142,11 @@ pub(crate) fn build_index<'tcx>( let pathid = *lastpathid; entry.insert(pathid); *lastpathid += 1; - crate_paths.push((item_type, path.to_vec())); + crate_paths.push(( + item_type, + path.to_vec(), + exact_path.map(|path| path.to_vec()), + )); RenderTypeId::Index(pathid) } } @@ -149,14 +159,33 @@ pub(crate) fn build_index<'tcx>( primitives: &mut FxHashMap<Symbol, isize>, associated_types: &mut FxHashMap<Symbol, isize>, lastpathid: &mut isize, - crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>, + crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>, ) -> Option<RenderTypeId> { - let Cache { ref paths, ref external_paths, .. } = *cache; + let Cache { ref paths, ref external_paths, ref exact_paths, .. } = *cache; match id { + RenderTypeId::Mut => Some(insert_into_map( + primitives, + kw::Mut, + lastpathid, + crate_paths, + ItemType::Keyword, + &[kw::Mut], + None, + )), RenderTypeId::DefId(defid) => { if let Some(&(ref fqp, item_type)) = paths.get(&defid).or_else(|| external_paths.get(&defid)) { + let exact_fqp = exact_paths + .get(&defid) + .or_else(|| external_paths.get(&defid).map(|&(ref fqp, _)| fqp)) + // Re-exports only count if the name is exactly the same. + // This is a size optimization, since it means we only need + // to store the name once (and the path is re-used for everything + // exported from this same module). It's also likely to Do + // What I Mean, since if a re-export changes the name, it might + // also be a change in semantic meaning. + .filter(|fqp| fqp.last() == fqp.last()); Some(insert_into_map( itemid_to_pathid, ItemId::DefId(defid), @@ -164,6 +193,7 @@ pub(crate) fn build_index<'tcx>( crate_paths, item_type, fqp, + exact_fqp.map(|x| &x[..]).filter(|exact_fqp| exact_fqp != fqp), )) } else { None @@ -178,6 +208,7 @@ pub(crate) fn build_index<'tcx>( crate_paths, ItemType::Primitive, &[sym], + None, )) } RenderTypeId::Index(_) => Some(id), @@ -188,6 +219,7 @@ pub(crate) fn build_index<'tcx>( crate_paths, ItemType::AssocType, &[sym], + None, )), } } @@ -199,7 +231,7 @@ pub(crate) fn build_index<'tcx>( primitives: &mut FxHashMap<Symbol, isize>, associated_types: &mut FxHashMap<Symbol, isize>, lastpathid: &mut isize, - crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>, + crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>, ) { if let Some(generics) = &mut ty.generics { for item in generics { @@ -296,7 +328,7 @@ pub(crate) fn build_index<'tcx>( } } - let Cache { ref paths, .. } = *cache; + let Cache { ref paths, ref exact_paths, ref external_paths, .. } = *cache; // Then, on parent modules let crate_items: Vec<&IndexItem> = search_index @@ -311,7 +343,13 @@ pub(crate) fn build_index<'tcx>( lastpathid += 1; if let Some(&(ref fqp, short)) = paths.get(&defid) { - crate_paths.push((short, fqp.clone())); + let exact_fqp = exact_paths + .get(&defid) + .or_else(|| external_paths.get(&defid).map(|&(ref fqp, _)| fqp)) + .filter(|exact_fqp| { + exact_fqp.last() == Some(&item.name) && *exact_fqp != fqp + }); + crate_paths.push((short, fqp.clone(), exact_fqp.cloned())); Some(pathid) } else { None @@ -319,6 +357,42 @@ pub(crate) fn build_index<'tcx>( } }); + if let Some(defid) = item.defid + && item.parent_idx.is_none() + { + // If this is a re-export, retain the original path. + // Associated items don't use this. + // Their parent carries the exact fqp instead. + let exact_fqp = exact_paths + .get(&defid) + .or_else(|| external_paths.get(&defid).map(|&(ref fqp, _)| fqp)); + item.exact_path = exact_fqp.and_then(|fqp| { + // Re-exports only count if the name is exactly the same. + // This is a size optimization, since it means we only need + // to store the name once (and the path is re-used for everything + // exported from this same module). It's also likely to Do + // What I Mean, since if a re-export changes the name, it might + // also be a change in semantic meaning. + if fqp.last() != Some(&item.name) { + return None; + } + let path = + if item.ty == ItemType::Macro && tcx.has_attr(defid, sym::macro_export) { + // `#[macro_export]` always exports to the crate root. + tcx.crate_name(defid.krate).to_string() + } else { + if fqp.len() < 2 { + return None; + } + join_with_double_colon(&fqp[..fqp.len() - 1]) + }; + if path == item.path { + return None; + } + Some(path) + }); + } + // Omit the parent path if it is same to that of the prior item. if lastpath == &item.path { item.path.clear(); @@ -356,7 +430,7 @@ pub(crate) fn build_index<'tcx>( struct CrateData<'a> { items: Vec<&'a IndexItem>, - paths: Vec<(ItemType, Vec<Symbol>)>, + paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>, // The String is alias name and the vec is the list of the elements with this alias. // // To be noted: the `usize` elements are indexes to `items`. @@ -374,6 +448,7 @@ pub(crate) fn build_index<'tcx>( ty: ItemType, name: Symbol, path: Option<usize>, + exact_path: Option<usize>, } impl Serialize for Paths { @@ -387,6 +462,10 @@ pub(crate) fn build_index<'tcx>( if let Some(ref path) = self.path { seq.serialize_element(path)?; } + if let Some(ref path) = self.exact_path { + assert!(self.path.is_some()); + seq.serialize_element(path)?; + } seq.end() } } @@ -409,14 +488,39 @@ pub(crate) fn build_index<'tcx>( mod_paths.insert(&item.path, index); } let mut paths = Vec::with_capacity(self.paths.len()); - for (ty, path) in &self.paths { + for (ty, path, exact) in &self.paths { if path.len() < 2 { - paths.push(Paths { ty: *ty, name: path[0], path: None }); + paths.push(Paths { ty: *ty, name: path[0], path: None, exact_path: None }); continue; } let full_path = join_with_double_colon(&path[..path.len() - 1]); + let full_exact_path = exact + .as_ref() + .filter(|exact| exact.last() == path.last() && exact.len() >= 2) + .map(|exact| join_with_double_colon(&exact[..exact.len() - 1])); + let exact_path = extra_paths.len() + self.items.len(); + let exact_path = full_exact_path.as_ref().map(|full_exact_path| match extra_paths + .entry(full_exact_path.clone()) + { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + if let Some(index) = mod_paths.get(&full_exact_path) { + return *index; + } + entry.insert(exact_path); + if !revert_extra_paths.contains_key(&exact_path) { + revert_extra_paths.insert(exact_path, full_exact_path.clone()); + } + exact_path + } + }); if let Some(index) = mod_paths.get(&full_path) { - paths.push(Paths { ty: *ty, name: *path.last().unwrap(), path: Some(*index) }); + paths.push(Paths { + ty: *ty, + name: *path.last().unwrap(), + path: Some(*index), + exact_path, + }); continue; } // It means it comes from an external crate so the item and its path will be @@ -424,28 +528,54 @@ pub(crate) fn build_index<'tcx>( // // `index` is put after the last `mod_paths` let index = extra_paths.len() + self.items.len(); - if !revert_extra_paths.contains_key(&index) { - revert_extra_paths.insert(index, full_path.clone()); - } - match extra_paths.entry(full_path) { + match extra_paths.entry(full_path.clone()) { Entry::Occupied(entry) => { paths.push(Paths { ty: *ty, name: *path.last().unwrap(), path: Some(*entry.get()), + exact_path, }); } Entry::Vacant(entry) => { entry.insert(index); + if !revert_extra_paths.contains_key(&index) { + revert_extra_paths.insert(index, full_path); + } paths.push(Paths { ty: *ty, name: *path.last().unwrap(), path: Some(index), + exact_path, }); } } } + // Direct exports use adjacent arrays for the current crate's items, + // but re-exported exact paths don't. + let mut re_exports = Vec::new(); + for (item_index, item) in self.items.iter().enumerate() { + if let Some(exact_path) = item.exact_path.as_ref() { + if let Some(path_index) = mod_paths.get(&exact_path) { + re_exports.push((item_index, *path_index)); + } else { + let path_index = extra_paths.len() + self.items.len(); + let path_index = match extra_paths.entry(exact_path.clone()) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + entry.insert(path_index); + if !revert_extra_paths.contains_key(&path_index) { + revert_extra_paths.insert(path_index, exact_path.clone()); + } + path_index + } + }; + re_exports.push((item_index, path_index)); + } + } + } + let mut names = Vec::with_capacity(self.items.len()); let mut types = String::with_capacity(self.items.len()); let mut full_paths = Vec::with_capacity(self.items.len()); @@ -501,6 +631,7 @@ pub(crate) fn build_index<'tcx>( crate_data.serialize_field("f", &functions)?; crate_data.serialize_field("D", &self.desc_index)?; crate_data.serialize_field("p", &paths)?; + crate_data.serialize_field("r", &re_exports)?; crate_data.serialize_field("b", &self.associated_item_disambiguators)?; crate_data.serialize_field("c", &bitmap_to_string(&deprecated))?; crate_data.serialize_field("e", &bitmap_to_string(&self.empty_desc))?; @@ -643,9 +774,8 @@ fn get_index_type_id( bounds.get(0).map(|b| RenderTypeId::DefId(b.trait_.def_id())) } clean::Primitive(p) => Some(RenderTypeId::Primitive(p)), - clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => { - get_index_type_id(type_, rgen) - } + clean::BorrowedRef { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::Reference)), + clean::RawPointer(_, ref type_) => get_index_type_id(type_, rgen), // The type parameters are converted to generics in `simplify_fn_type` clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)), clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)), @@ -711,28 +841,14 @@ fn simplify_fn_type<'tcx, 'a>( } // First, check if it's "Self". - let mut is_self = false; - let mut arg = if let Some(self_) = self_ { - match &*arg { - Type::BorrowedRef { type_, .. } if type_.is_self_type() => { - is_self = true; - self_ - } - type_ if type_.is_self_type() => { - is_self = true; - self_ - } - arg => arg, - } + let (is_self, arg) = if let Some(self_) = self_ + && arg.is_self_type() + { + (true, self_) } else { - arg + (false, arg) }; - // strip references from the argument type - while let Type::BorrowedRef { type_, .. } = &*arg { - arg = &*type_; - } - // If this argument is a type parameter and not a trait bound or a type, we need to look // for its bounds. if let Type::Generic(arg_s) = *arg { @@ -905,6 +1021,27 @@ fn simplify_fn_type<'tcx, 'a>( bindings: Some(ty_bindings), generics: Some(ty_generics), }); + } else if let Type::BorrowedRef { lifetime: _, mutability, ref type_ } = *arg { + let mut ty_generics = Vec::new(); + if mutability.is_mut() { + ty_generics.push(RenderType { + id: Some(RenderTypeId::Mut), + generics: None, + bindings: None, + }); + } + simplify_fn_type( + self_, + generics, + &type_, + tcx, + recurse + 1, + &mut ty_generics, + rgen, + is_return, + cache, + ); + res.push(get_index_type(arg, ty_generics, rgen)); } else { // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't. diff --git a/src/librustdoc/html/render/search_index/encode.rs b/src/librustdoc/html/render/search_index/encode.rs index 54407c614c4..8d715814faa 100644 --- a/src/librustdoc/html/render/search_index/encode.rs +++ b/src/librustdoc/html/render/search_index/encode.rs @@ -166,13 +166,12 @@ pub(crate) fn write_bitmap_to_bytes( containers.push(container); } // https://github.com/RoaringBitmap/RoaringFormatSpec - use byteorder::{WriteBytesExt, LE}; const SERIAL_COOKIE_NO_RUNCONTAINER: u32 = 12346; const SERIAL_COOKIE: u32 = 12347; const NO_OFFSET_THRESHOLD: u32 = 4; let size: u32 = containers.len().try_into().unwrap(); let start_offset = if has_run { - out.write_u32::<LE>(SERIAL_COOKIE | ((size - 1) << 16))?; + out.write_all(&u32::to_le_bytes(SERIAL_COOKIE | ((size - 1) << 16)))?; for set in containers.chunks(8) { let mut b = 0; for (i, container) in set.iter().enumerate() { @@ -180,7 +179,7 @@ pub(crate) fn write_bitmap_to_bytes( b |= 1 << i; } } - out.write_u8(b)?; + out.write_all(&[b])?; } if size < NO_OFFSET_THRESHOLD { 4 + 4 * size + ((size + 7) / 8) @@ -188,21 +187,21 @@ pub(crate) fn write_bitmap_to_bytes( 4 + 8 * size + ((size + 7) / 8) } } else { - out.write_u32::<LE>(SERIAL_COOKIE_NO_RUNCONTAINER)?; - out.write_u32::<LE>(containers.len().try_into().unwrap())?; + out.write_all(&u32::to_le_bytes(SERIAL_COOKIE_NO_RUNCONTAINER))?; + out.write_all(&u32::to_le_bytes(containers.len().try_into().unwrap()))?; 4 + 4 + 4 * size + 4 * size }; for (&key, container) in keys.iter().zip(&containers) { // descriptive header let key: u32 = key.into(); let count: u32 = container.popcount() - 1; - out.write_u32::<LE>((count << 16) | key)?; + out.write_all(&u32::to_le_bytes((count << 16) | key))?; } if !has_run || size >= NO_OFFSET_THRESHOLD { // offset header let mut starting_offset = start_offset; for container in &containers { - out.write_u32::<LE>(starting_offset)?; + out.write_all(&u32::to_le_bytes(starting_offset))?; starting_offset += match container { Container::Bits(_) => 8192u32, Container::Array(array) => u32::try_from(array.len()).unwrap() * 2, @@ -214,19 +213,19 @@ pub(crate) fn write_bitmap_to_bytes( match container { Container::Bits(bits) => { for chunk in bits.iter() { - out.write_u64::<LE>(*chunk)?; + out.write_all(&u64::to_le_bytes(*chunk))?; } } Container::Array(array) => { for value in array.iter() { - out.write_u16::<LE>(*value)?; + out.write_all(&u16::to_le_bytes(*value))?; } } Container::Run(runs) => { - out.write_u16::<LE>((runs.len()).try_into().unwrap())?; + out.write_all(&u16::to_le_bytes(runs.len().try_into().unwrap()))?; for (start, lenm1) in runs.iter().copied() { - out.write_u16::<LE>(start)?; - out.write_u16::<LE>(lenm1)?; + out.write_all(&u16::to_le_bytes(start))?; + out.write_all(&u16::to_le_bytes(lenm1))?; } } } diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index ccb97d7df4c..6e10cf21537 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -85,6 +85,7 @@ nav.sub { --search-tab-button-not-selected-background: #e6e6e6; --search-tab-button-selected-border-top-color: #0089ff; --search-tab-button-selected-background: #fff; + --settings-menu-filter: none; --stab-background-color: #fff5d6; --stab-code-color: #000; --code-highlight-kw-color: #8959a8; diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index e9c687b42fa..4c0ba75d261 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1133,6 +1133,7 @@ so that we can apply CSS-filters to change the arrow color in themes */ .setting-check input:checked { background-color: var(--settings-input-color); border-width: 1px; + /* cross-mark image in the settings checkboxes */ content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\ <path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\ <path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>'); @@ -1608,12 +1609,27 @@ a.tooltip:hover::after { font-size: 0; } #settings-menu > a:before { - content: url('wheel-63255fc4502dca9a.svg'); + /* Wheel <https://www.svgrepo.com/svg/384069/settings-cog-gear> */ + content: url('data:image/svg+xml,<svg width="22" height="22" viewBox="0 0 12 12" \ + enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\ + <path d="M10.25,6c0-0.1243286-0.0261841-0.241333-0.0366211-0.362915l1.6077881-1.5545654l\ + -1.25-2.1650391 c0,0-1.2674561,0.3625488-2.1323853,0.6099854c-0.2034912-0.1431885-0.421875\ + -0.2639771-0.6494751-0.3701782L7.25,0h-2.5 c0,0-0.3214111,1.2857666-0.5393066,2.1572876\ + C3.9830933,2.2634888,3.7647095,2.3842773,3.5612183,2.5274658L1.428833,1.9174805 \ + l-1.25,2.1650391c0,0,0.9641113,0.9321899,1.6077881,1.5545654C1.7761841,5.758667,\ + 1.75,5.8756714,1.75,6 s0.0261841,0.241333,0.0366211,0.362915L0.178833,7.9174805l1.25,\ + 2.1650391l2.1323853-0.6099854 c0.2034912,0.1432495,0.421875,0.2639771,0.6494751,0.3701782\ + L4.75,12h2.5l0.5393066-2.1572876 c0.2276001-0.1062012,0.4459839-0.2269287,0.6494751\ + -0.3701782l2.1323853,0.6099854l1.25-2.1650391L10.2133789,6.362915 C10.2238159,6.241333,\ + 10.25,6.1243286,10.25,6z M6,7.5C5.1715698,7.5,4.5,6.8284302,4.5,6S5.1715698,4.5,6,4.5S7.5\ + ,5.1715698,7.5,6 S6.8284302,7.5,6,7.5z" fill="black"/></svg>'); width: 22px; height: 22px; + filter: var(--settings-menu-filter); } #sidebar-button > a:before { + /* sidebar resizer image */ content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" \ fill="none" stroke="black">\ <rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5"/>\ @@ -1627,24 +1643,37 @@ a.tooltip:hover::after { color: var(--copy-path-button-color); background: var(--main-background-color); height: 34px; + width: 33px; margin-left: 10px; padding: 0; padding-left: 2px; border: 0; - width: 33px; - line-height: 0; font-size: 0; } - -#copy-path:before { +#copy-path::before { filter: var(--copy-path-img-filter); - content: url('clipboard-24048e6d87f63d07.svg'); + /* clipboard <https://github.com/rust-lang/crates.io/commits/main/public/assets/copy.svg> */ + content: url('data:image/svg+xml,<svg width="19" height="18" viewBox="0 0 24 25" \ +xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard">\ +<path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 \ +0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 \ +7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 \ +2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/>\ +<path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/>\ +</svg>'); width: 19px; height: 18px; } -#copy-path:hover:before { +#copy-path:hover::before { filter: var(--copy-path-img-hover-filter); } +#copy-path.clicked::before { + /* Checkmark <https://www.svgrepo.com/svg/335033/checkmark> */ + content: url('data:image/svg+xml,<svg viewBox="-1 -1 23 23" xmlns="http://www.w3.org/2000/svg" \ + fill="black" height="18px">\ + <g><path d="M9 19.414l-6.707-6.707 1.414-1.414L9 16.586 20.293 5.293l1.414 1.414"></path>\ + </g></svg>'); +} @keyframes rotating { from { @@ -1834,6 +1863,7 @@ However, it's not needed with smaller screen width because the doc/code block is /* sidebar button opens modal use hamburger button */ .src #sidebar-button > a:before, .sidebar-menu-toggle:before { + /* hamburger button image */ content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \ viewBox="0 0 22 22" fill="none" stroke="black">\ <path d="M3,5h16M3,11h16M3,17h16" stroke-width="2.75"/></svg>'); @@ -1847,6 +1877,7 @@ However, it's not needed with smaller screen width because the doc/code block is /* src sidebar button opens a folder view */ .src #sidebar-button > a:before { + /* folder image */ content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \ viewBox="0 0 22 22" fill="none" stroke="black">\ <path d="M16,9v-4h-6v-1l-2,-2h-4l-2,2v16h13L21,9h-15L2,19" stroke-width="1.25"/>\ @@ -2389,6 +2420,7 @@ by default. --search-tab-button-not-selected-background: #e6e6e6; --search-tab-button-selected-border-top-color: #0089ff; --search-tab-button-selected-background: #fff; + --settings-menu-filter: none; --stab-background-color: #fff5d6; --stab-code-color: #000; --code-highlight-kw-color: #8959a8; @@ -2494,6 +2526,7 @@ by default. --search-tab-button-not-selected-background: #252525; --search-tab-button-selected-border-top-color: #0089ff; --search-tab-button-selected-background: #353535; + --settings-menu-filter: none; --stab-background-color: #314559; --stab-code-color: #e6e1cf; --code-highlight-kw-color: #ab8ac1; @@ -2606,6 +2639,7 @@ Original by Dempfi (https://github.com/dempfi/ayu) --search-tab-button-not-selected-background: transparent !important; --search-tab-button-selected-border-top-color: none; --search-tab-button-selected-background: #141920 !important; + --settings-menu-filter: invert(100%); --stab-background-color: #314559; --stab-code-color: #e6e1cf; --code-highlight-kw-color: #ff7733; diff --git a/src/librustdoc/html/static/images/clipboard.svg b/src/librustdoc/html/static/images/clipboard.svg deleted file mode 100644 index e437c83fb6b..00000000000 --- a/src/librustdoc/html/static/images/clipboard.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="19" height="18" viewBox="0 0 24 25" xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard"><path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/><path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/></svg> diff --git a/src/librustdoc/html/static/images/wheel.svg b/src/librustdoc/html/static/images/wheel.svg deleted file mode 100644 index ba30f13dd58..00000000000 --- a/src/librustdoc/html/static/images/wheel.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" enable-background="new 0 0 22 22" viewBox="0 0 27.434 29.5"><path d="M27.316 18.39a2.696 2.696 0 0 0-.98-1.46 1.62 1.62 0 0 1-.016-.762l.035-.176v-1.191c0-1.246-.003-1.278-.046-1.473a1.717 1.717 0 0 1 .007-.805c.477-.343.829-.859.997-1.472.257-.957.074-2.094-.508-3.117l-.594-1.032c-.746-1.304-1.965-2.117-3.18-2.117-.379 0-.75.078-1.086.235a1.958 1.958 0 0 1-.855-.391l-.102-.082-.117-.063-1.855-1.07-.094-.055-.106-.043c-.378-.156-.66-.41-.77-.554C17.919 1.172 16.349 0 14.297 0h-1.155c-2.043 0-3.61 1.152-3.75 2.723-.114.14-.391.382-.758.527l-.102.04-.094.05-1.94 1.066-.134.074-.117.094a2.019 2.019 0 0 1-.832.403 2.518 2.518 0 0 0-1.008-.211c-1.199 0-2.414.82-3.168 2.14l-.59 1.032c-.41.718-.64 1.523-.64 2.257-.004.953.36 1.758 1.012 2.258.035.152.058.445-.016.785-.04.168-.063.282-.063 1.563 0 1.148 0 1.148.016 1.261l.008.075.015.074c.075.344.047.64.012.8-.644.5-1.004 1.302-.992 2.259.008.726.238 1.52.648 2.242l.59 1.027c.758 1.332 1.965 2.16 3.149 2.16.324 0 .644-.062.937-.187.168.039.492.156.813.418l.11.086.124.07 2.047 1.156.102.059.105.043c.363.144.648.379.766.52.164 1.519 1.718 2.632 3.746 2.632h1.156c2.035 0 3.598-1.133 3.746-2.672.117-.144.402-.394.773-.55l.114-.047.101-.063 1.961-1.156.106-.063.097-.078c.309-.246.653-.37.832-.398.313.136.66.21 1.016.21 1.2 0 2.41-.82 3.164-2.14l.594-1.031c.59-1.028.777-2.164.52-3.117Zm-2.043 2.247-.59 1.031c-.437.766-1.105 1.25-1.636 1.25a.7.7 0 0 1-.371-.094 1.146 1.146 0 0 0-.567-.129c-.593 0-1.382.297-2.007.797l-1.961 1.156c-1.016.426-1.848 1.293-1.848 1.93 0 .64-.898 1.16-1.996 1.16H13.14c-1.102 0-2-.515-2-1.14 0-.63-.832-1.477-1.852-1.887l-2.047-1.16c-.637-.512-1.426-.813-2.008-.813-.199 0-.379.035-.515.114a.648.648 0 0 1-.332.085c-.52 0-1.18-.5-1.621-1.273l-.59-1.031c-.543-.953-.555-1.98-.024-2.285.532-.305.782-1.434.551-2.504V14.8c0-1.09.02-1.18.02-1.18.238-1.074-.008-2.203-.551-2.516-.54-.304-.54-1.34.008-2.293l.59-1.03c.437-.766 1.101-1.255 1.636-1.255a.73.73 0 0 1 .364.094c.152.086.343.125.566.125.594 0 1.379-.297 2.004-.793l1.945-1.066c1.02-.407 1.856-1.278 1.856-1.934 0-.656.898-1.191 2-1.191h1.156c1.098 0 1.996.543 1.996 1.21 0 .669.832 1.555 1.848 1.973L20 6.012c.617.492 1.402.777 2.012.777.242 0 .453-.047.62-.14a.79.79 0 0 1 .403-.102c.55 0 1.223.476 1.652 1.23l.59 1.032c.543.953.52 2.004-.062 2.336-.574.332-.86 1.48-.625 2.554 0 0 .008.04.008 1.102v1.011c-.215 1.051.07 2.176.636 2.5.567.325.586 1.368.04 2.325Zm0 0"/><path d="M13.61 7.61a7.084 7.084 0 0 0-7.083 7.085 7.085 7.085 0 1 0 14.168 0A7.088 7.088 0 0 0 13.61 7.61Zm0 12.41a5.33 5.33 0 0 1-5.325-5.325 5.33 5.33 0 0 1 5.324-5.32 5.327 5.327 0 0 1 5.325 5.32 5.328 5.328 0 0 1-5.325 5.325Zm0 0"/><path d="M13.684 9.906a4.722 4.722 0 0 0-4.72 4.719 4.722 4.722 0 0 0 4.72 4.719 4.724 4.724 0 0 0 4.714-4.719 4.724 4.724 0 0 0-4.714-4.719Zm0 7.676a2.954 2.954 0 1 1 0-5.91 2.953 2.953 0 0 1 2.953 2.953 2.957 2.957 0 0 1-2.953 2.957Zm0 0"/></svg> \ No newline at end of file diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js index d24148b9556..8cebce7ae86 100644 --- a/src/librustdoc/html/static/js/externs.js +++ b/src/librustdoc/html/static/js/externs.js @@ -239,20 +239,27 @@ let FunctionType; * `doc` contains the description of the crate. * * `p` is a list of path/type pairs. It is used for parents and function parameters. + * The first item is the type, the second is the name, the third is the visible path (if any) and + * the fourth is the canonical path used for deduplication (if any). + * + * `r` is the canonical path used for deduplication of re-exported items. + * It is not used for associated items like methods (that's the fourth element + * of `p`) but is used for modules items like free functions. * * `c` is an array of item indices that are deprecated. * @typedef {{ * doc: string, * a: Object, * n: Array<string>, - * t: String, + * t: string, * d: Array<string>, - * q: Array<[Number, string]>, - * i: Array<Number>, + * q: Array<[number, string]>, + * i: Array<number>, * f: string, - * p: Array<Object>, - * b: Array<[Number, String]>, - * c: Array<Number> + * p: Array<[number, string] | [number, string, number] | [number, string, number, number]>, + * b: Array<[number, String]>, + * c: Array<number>, + * r: Array<[number, number]>, * }} */ let RawSearchIndexCrate; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index ee7d19634b4..64c35660778 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1798,31 +1798,15 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm document.execCommand("copy"); document.body.removeChild(el); - // There is always one children, but multiple childNodes. - but.children[0].style.display = "none"; - - let tmp; - if (but.childNodes.length < 2) { - tmp = document.createTextNode("✓"); - but.appendChild(tmp); - } else { - onEachLazy(but.childNodes, e => { - if (e.nodeType === Node.TEXT_NODE) { - tmp = e; - return true; - } - }); - tmp.textContent = "✓"; - } + but.classList.add("clicked"); if (reset_button_timeout !== null) { window.clearTimeout(reset_button_timeout); } function reset_button() { - tmp.textContent = ""; reset_button_timeout = null; - but.children[0].style.display = ""; + but.classList.remove("clicked"); } reset_button_timeout = window.setTimeout(reset_button, 1000); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 3daf1ad22de..76a6fc9008e 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -79,6 +79,7 @@ const longItemTypes = [ // used for special search precedence const TY_GENERIC = itemTypes.indexOf("generic"); +const TY_IMPORT = itemTypes.indexOf("import"); const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../"; // Hard limit on how deep to recurse into generics when doing type-driven search. @@ -785,6 +786,37 @@ function initSearch(rawSearchIndex) { } elems.push(makePrimitiveElement(name, { bindingName, generics })); } + } else if (parserState.userQuery[parserState.pos] === "&") { + if (parserState.typeFilter !== null && parserState.typeFilter !== "primitive") { + throw [ + "Invalid search type: primitive ", + "&", + " and ", + parserState.typeFilter, + " both specified", + ]; + } + parserState.typeFilter = null; + parserState.pos += 1; + let c = parserState.userQuery[parserState.pos]; + while (c === " " && parserState.pos < parserState.length) { + parserState.pos += 1; + c = parserState.userQuery[parserState.pos]; + } + const generics = []; + if (parserState.userQuery.slice(parserState.pos, parserState.pos + 3) === "mut") { + generics.push(makePrimitiveElement("mut", { typeFilter: "keyword"})); + parserState.pos += 3; + c = parserState.userQuery[parserState.pos]; + } + while (c === " " && parserState.pos < parserState.length) { + parserState.pos += 1; + c = parserState.userQuery[parserState.pos]; + } + if (!isEndCharacter(c) && parserState.pos < parserState.length) { + getFilteredNextElem(query, parserState, generics, isInGenerics); + } + elems.push(makePrimitiveElement("reference", { generics })); } else { const isStringElem = parserState.userQuery[start] === "\""; // We handle the strings on their own mostly to make code easier to follow. @@ -1324,14 +1356,23 @@ function initSearch(rawSearchIndex) { obj.dist = result.dist; const res = buildHrefAndPath(obj); obj.displayPath = pathSplitter(res[0]); - obj.fullPath = obj.displayPath + obj.name; - // To be sure than it some items aren't considered as duplicate. - obj.fullPath += "|" + obj.ty; + // To be sure than it some items aren't considered as duplicate. + obj.fullPath = res[2] + "|" + obj.ty; if (duplicates.has(obj.fullPath)) { continue; } + + // Exports are specifically not shown if the items they point at + // are already in the results. + if (obj.ty === TY_IMPORT && duplicates.has(res[2])) { + continue; + } + if (duplicates.has(res[2] + "|" + TY_IMPORT)) { + continue; + } duplicates.add(obj.fullPath); + duplicates.add(res[2]); obj.href = res[1]; out.push(obj); @@ -1454,16 +1495,7 @@ function initSearch(rawSearchIndex) { return 0; }); - const transformed = transformResults(result_list); - const descs = await Promise.all(transformed.map(result => { - return searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex) ? - "" : - searchState.loadDesc(result); - })); - for (const [i, result] of transformed.entries()) { - result.desc = descs[i]; - } - return transformed; + return transformResults(result_list); } /** @@ -2085,6 +2117,7 @@ function initSearch(rawSearchIndex) { path: item.path, descShard: item.descShard, descIndex: item.descIndex, + exactPath: item.exactPath, ty: item.ty, parent: item.parent, type: item.type, @@ -2506,6 +2539,16 @@ function initSearch(rawSearchIndex) { sorted_others, parsedQuery); handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates, currentCrate); + await Promise.all([ret.others, ret.returned, ret.in_args].map(async list => { + const descs = await Promise.all(list.map(result => { + return searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex) ? + "" : + searchState.loadDesc(result); + })); + for (const [i, result] of list.entries()) { + result.desc = descs[i]; + } + })); if (parsedQuery.error !== null && ret.others.length !== 0) { // It means some doc aliases were found so let's "remove" the error! ret.query.error = null; @@ -2538,6 +2581,7 @@ function initSearch(rawSearchIndex) { const type = itemTypes[item.ty]; const name = item.name; let path = item.path; + let exactPath = item.exactPath; if (type === "mod") { displayPath = path + "::"; @@ -2559,6 +2603,7 @@ function initSearch(rawSearchIndex) { const parentType = itemTypes[myparent.ty]; let pageType = parentType; let pageName = myparent.name; + exactPath = `${myparent.exactPath}::${myparent.name}`; if (parentType === "primitive") { displayPath = myparent.name + "::"; @@ -2587,7 +2632,7 @@ function initSearch(rawSearchIndex) { href = ROOT_PATH + item.path.replace(/::/g, "/") + "/" + type + "." + name + ".html"; } - return [displayPath, href]; + return [displayPath, href, `${exactPath}::${name}`]; } function pathSplitter(path) { @@ -2980,6 +3025,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ id: pathIndex, ty: TY_GENERIC, path: null, + exactPath: null, generics, bindings, }; @@ -2989,6 +3035,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ id: null, ty: null, path: null, + exactPath: null, generics, bindings, }; @@ -2998,6 +3045,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ id: buildTypeMapIndex(item.name, isAssocType), ty: item.ty, path: item.path, + exactPath: item.exactPath, generics, bindings, }; @@ -3453,6 +3501,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ path: "", descShard, descIndex, + exactPath: "", + desc: crateCorpus.doc, parent: undefined, type: null, id, @@ -3478,6 +3528,9 @@ ${item.displayPath}<span class="${type}">${name}</span>\ // i.e. if indices 4 and 11 are present, but 5-10 and 12-13 are not present, // 5-10 will fall back to the path for 4 and 12-13 will fall back to the path for 11 const itemPaths = new Map(crateCorpus.q); + // An array of [(Number) item index, (Number) path index] + // Used to de-duplicate inlined and re-exported stuff + const itemReexports = new Map(crateCorpus.r); // an array of (Number) the parent path index + 1 to `paths`, or 0 if none const itemParentIdxs = crateCorpus.i; // a map Number, string for impl disambiguators @@ -3511,9 +3564,10 @@ ${item.displayPath}<span class="${type}">${name}</span>\ path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath; lastPath = path; } + const exactPath = elem.length > 3 ? itemPaths.get(elem[3]) : path; - lowercasePaths.push({ty: ty, name: name.toLowerCase(), path: path}); - paths[i] = {ty: ty, name: name, path: path}; + lowercasePaths.push({ty, name: name.toLowerCase(), path, exactPath}); + paths[i] = {ty, name, path, exactPath}; } // convert `item*` into an object form, and construct word indices. @@ -3572,6 +3626,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ path, descShard, descIndex, + exactPath: itemReexports.has(i) ? itemPaths.get(itemReexports.get(i)) : path, parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined, type, id, diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 73c543567c0..4a27ca92fff 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -239,3 +239,46 @@ window.addEventListener("pageshow", ev => { setTimeout(updateSidebarWidth, 0); } }); + +// Custom elements are used to insert some JS-dependent features into Rustdoc, +// because the [parser] runs the connected callback +// synchronously. It needs to be added synchronously so that nothing below it +// becomes visible until after it's done. Otherwise, you get layout jank. +// +// That's also why this is in storage.js and not main.js. +// +// [parser]: https://html.spec.whatwg.org/multipage/parsing.html +class RustdocSearchElement extends HTMLElement { + constructor() { + super(); + } + connectedCallback() { + const rootPath = getVar("root-path"); + const currentCrate = getVar("current-crate"); + this.innerHTML = `<nav class="sub"> + <form class="search-form"> + <span></span> <!-- This empty span is a hacky fix for Safari - See #93184 --> + <div id="sidebar-button" tabindex="-1"> + <a href="${rootPath}${currentCrate}/all.html" title="show sidebar"></a> + </div> + <input + class="search-input" + name="search" + aria-label="Run search in the documentation" + autocomplete="off" + spellcheck="false" + placeholder="Type ‘S’ or ‘/’ to search, ‘?’ for more options…" + type="search"> + <div id="help-button" tabindex="-1"> + <a href="${rootPath}help.html" title="help">?</a> + </div> + <div id="settings-menu" tabindex="-1"> + <a href="${rootPath}settings.html" title="settings"> + Settings + </a> + </div> + </form> + </nav>`; + } +} +window.customElements.define("rustdoc-search", RustdocSearchElement); diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index d8874c2fda0..035376bace9 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -99,8 +99,6 @@ static_files! { src_script_js => "static/js/src-script.js", storage_js => "static/js/storage.js", scrape_examples_js => "static/js/scrape-examples.js", - wheel_svg => "static/images/wheel.svg", - clipboard_svg => "static/images/clipboard.svg", copyright => "static/COPYRIGHT.txt", license_apache => "static/LICENSE-APACHE.txt", license_mit => "static/LICENSE-MIT.txt", diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 1e01cd70b96..cdf01fa7a97 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -117,30 +117,9 @@ <div class="sidebar-resizer"></div> {# #} <main> {# #} {% if page.css_class != "src" %}<div class="width-limiter">{% endif %} - <nav class="sub"> {# #} - <form class="search-form"> {# #} - <span></span> {# This empty span is a hacky fix for Safari - See #93184 #} - <div id="sidebar-button" tabindex="-1"> {# #} - <a href="{{page.root_path|safe}}{{layout.krate|safe}}/all.html" title="show sidebar"></a> {# #} - </div> {# #} - <input {#+ #} - class="search-input" {#+ #} - name="search" {#+ #} - aria-label="Run search in the documentation" {#+ #} - autocomplete="off" {#+ #} - spellcheck="false" {#+ #} - placeholder="Type ‘S’ or ‘/’ to search, ‘?’ for more options…" {#+ #} - type="search"> {# #} - <div id="help-button" tabindex="-1"> {# #} - <a href="{{page.root_path|safe}}help.html" title="help">?</a> {# #} - </div> {# #} - <div id="settings-menu" tabindex="-1"> {# #} - <a href="{{page.root_path|safe}}settings.html" title="settings"> {# #} - Settings {# #} - </a> {# #} - </div> {# #} - </form> {# #} - </nav> {# #} + {# defined in storage.js to avoid duplicating complex UI across every page #} + {# and because the search form only works if JS is enabled anyway #} + <rustdoc-search></rustdoc-search> {# #} <section id="main-content" class="content">{{ content|safe }}</section> {# #} {% if page.css_class != "src" %}</div>{% endif %} </main> {# #} |
