summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/html
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html')
-rw-r--r--src/librustdoc/html/format.rs31
-rw-r--r--src/librustdoc/html/highlight.rs46
-rw-r--r--src/librustdoc/html/markdown.rs43
-rw-r--r--src/librustdoc/html/markdown/tests.rs8
-rw-r--r--src/librustdoc/html/render/context.rs33
-rw-r--r--src/librustdoc/html/render/mod.rs35
-rw-r--r--src/librustdoc/html/render/print_item.rs91
-rw-r--r--src/librustdoc/html/render/search_index.rs92
-rw-r--r--src/librustdoc/html/render/write_shared.rs64
-rw-r--r--src/librustdoc/html/sources.rs62
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css376
-rw-r--r--src/librustdoc/html/static/css/settings.css37
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css63
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css49
-rw-r--r--src/librustdoc/html/static/css/themes/light.css49
-rw-r--r--src/librustdoc/html/static/js/main.js49
-rw-r--r--src/librustdoc/html/static/js/search.js130
-rw-r--r--src/librustdoc/html/static/js/settings.js6
-rw-r--r--src/librustdoc/html/static/js/source-script.js2
-rw-r--r--src/librustdoc/html/templates/page.html32
-rw-r--r--src/librustdoc/html/templates/print_item.html2
21 files changed, 621 insertions, 679 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 39e2a9022..d3dc4065d 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -569,7 +569,7 @@ fn generate_macro_def_id_path(
root_path: Option<&str>,
) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
let tcx = cx.shared.tcx;
- let crate_name = tcx.crate_name(def_id.krate).to_string();
+ let crate_name = tcx.crate_name(def_id.krate);
let cache = cx.cache();
let fqp: Vec<Symbol> = tcx
@@ -584,7 +584,7 @@ fn generate_macro_def_id_path(
}
})
.collect();
- let mut relative = fqp.iter().map(|elem| elem.to_string());
+ let mut relative = fqp.iter().copied();
let cstore = CStore::from_tcx(tcx);
// We need this to prevent a `panic` when this function is used from intra doc links...
if !cstore.has_crate_data(def_id.krate) {
@@ -602,9 +602,9 @@ fn generate_macro_def_id_path(
};
let mut path = if is_macro_2 {
- once(crate_name.clone()).chain(relative).collect()
+ once(crate_name).chain(relative).collect()
} else {
- vec![crate_name.clone(), relative.next_back().unwrap()]
+ vec![crate_name, relative.next_back().unwrap()]
};
if path.len() < 2 {
// The minimum we can have is the crate name followed by the macro name. If shorter, then
@@ -614,17 +614,22 @@ fn generate_macro_def_id_path(
}
if let Some(last) = path.last_mut() {
- *last = format!("macro.{}.html", last);
+ *last = Symbol::intern(&format!("macro.{}.html", last.as_str()));
}
let url = match cache.extern_locations[&def_id.krate] {
ExternalLocation::Remote(ref s) => {
// `ExternalLocation::Remote` always end with a `/`.
- format!("{}{}", s, path.join("/"))
+ format!("{}{}", s, path.iter().map(|p| p.as_str()).join("/"))
}
ExternalLocation::Local => {
// `root_path` always end with a `/`.
- format!("{}{}/{}", root_path.unwrap_or(""), crate_name, path.join("/"))
+ format!(
+ "{}{}/{}",
+ root_path.unwrap_or(""),
+ crate_name,
+ path.iter().map(|p| p.as_str()).join("/")
+ )
}
ExternalLocation::Unknown => {
debug!("crate {} not in cache when linkifying macros", crate_name);
@@ -957,7 +962,7 @@ fn fmt_type<'cx>(
clean::Tuple(ref typs) => {
match &typs[..] {
&[] => primitive_link(f, PrimitiveType::Unit, "()", cx),
- &[ref one] => {
+ [one] => {
if let clean::Generic(name) = one {
primitive_link(f, PrimitiveType::Tuple, &format!("({name},)"), cx)
} else {
@@ -1050,7 +1055,7 @@ fn fmt_type<'cx>(
_ => String::new(),
};
let m = mutability.print_with_space();
- let amp = if f.alternate() { "&".to_string() } else { "&amp;".to_string() };
+ let amp = if f.alternate() { "&" } else { "&amp;" };
match **ty {
clean::DynTrait(ref bounds, ref trait_lt)
if bounds.len() > 1 || trait_lt.is_some() =>
@@ -1655,10 +1660,10 @@ impl clean::types::Term {
&'a self,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
- match self {
- clean::types::Term::Type(ty) => ty.print(cx),
- _ => todo!(),
- }
+ display_fn(move |f| match self {
+ clean::types::Term::Type(ty) => fmt::Display::fmt(&ty.print(cx), f),
+ clean::types::Term::Constant(ct) => fmt::Display::fmt(&ct.print(cx.tcx()), f),
+ })
}
}
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index cd8c8c463..8a9e6caf6 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -21,15 +21,15 @@ use rustc_span::{BytePos, Span, DUMMY_SP};
use super::format::{self, Buffer};
/// This type is needed in case we want to render links on items to allow to go to their definition.
-pub(crate) struct HrefContext<'a, 'b, 'c> {
- pub(crate) context: &'a Context<'b>,
+pub(crate) struct HrefContext<'a, 'tcx> {
+ pub(crate) context: &'a Context<'tcx>,
/// This span contains the current file we're going through.
pub(crate) file_span: Span,
/// This field is used to know "how far" from the top of the directory we are to link to either
/// documentation pages or other source pages.
- pub(crate) root_path: &'c str,
+ pub(crate) root_path: &'a str,
/// This field is used to calculate precise local URLs.
- pub(crate) current_href: &'c str,
+ pub(crate) current_href: String,
}
/// Decorations are represented as a map from CSS class to vector of character ranges.
@@ -70,7 +70,7 @@ pub(crate) fn render_source_with_highlighting(
src: &str,
out: &mut Buffer,
line_numbers: Buffer,
- href_context: HrefContext<'_, '_, '_>,
+ href_context: HrefContext<'_, '_>,
decoration_info: DecorationInfo,
extra: Option<&str>,
) {
@@ -137,7 +137,7 @@ fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool {
/// This type is used as a conveniency to prevent having to pass all its fields as arguments into
/// the various functions (which became its methods).
-struct TokenHandler<'a, 'b, 'c, 'd, 'e> {
+struct TokenHandler<'a, 'tcx> {
out: &'a mut Buffer,
/// It contains the closing tag and the associated `Class`.
closing_tags: Vec<(&'static str, Class)>,
@@ -149,11 +149,11 @@ struct TokenHandler<'a, 'b, 'c, 'd, 'e> {
current_class: Option<Class>,
/// We need to keep the `Class` for each element because it could contain a `Span` which is
/// used to generate links.
- pending_elems: Vec<(&'b str, Option<Class>)>,
- href_context: Option<HrefContext<'c, 'd, 'e>>,
+ pending_elems: Vec<(&'a str, Option<Class>)>,
+ href_context: Option<HrefContext<'a, 'tcx>>,
}
-impl<'a, 'b, 'c, 'd, 'e> TokenHandler<'a, 'b, 'c, 'd, 'e> {
+impl<'a, 'tcx> TokenHandler<'a, 'tcx> {
fn handle_exit_span(&mut self) {
// We can't get the last `closing_tags` element using `pop()` because `closing_tags` is
// being used in `write_pending_elems`.
@@ -205,7 +205,7 @@ impl<'a, 'b, 'c, 'd, 'e> TokenHandler<'a, 'b, 'c, 'd, 'e> {
}
}
-impl<'a, 'b, 'c, 'd, 'e> Drop for TokenHandler<'a, 'b, 'c, 'd, 'e> {
+impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> {
/// When leaving, we need to flush all pending data to not have missing content.
fn drop(&mut self) {
if self.pending_exit_span.is_some() {
@@ -230,7 +230,7 @@ impl<'a, 'b, 'c, 'd, 'e> Drop for TokenHandler<'a, 'b, 'c, 'd, 'e> {
fn write_code(
out: &mut Buffer,
src: &str,
- href_context: Option<HrefContext<'_, '_, '_>>,
+ href_context: Option<HrefContext<'_, '_>>,
decoration_info: Option<DecorationInfo>,
) {
// This replace allows to fix how the code source with DOS backline characters is displayed.
@@ -514,18 +514,18 @@ impl Decorations {
/// Processes program tokens, classifying strings of text by highlighting
/// category (`Class`).
-struct Classifier<'a> {
- tokens: PeekIter<'a>,
+struct Classifier<'src> {
+ tokens: PeekIter<'src>,
in_attribute: bool,
in_macro: bool,
in_macro_nonterminal: bool,
byte_pos: u32,
file_span: Span,
- src: &'a str,
+ src: &'src str,
decorations: Option<Decorations>,
}
-impl<'a> Classifier<'a> {
+impl<'src> Classifier<'src> {
/// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
/// file span which will be used later on by the `span_correspondance_map`.
fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> {
@@ -603,7 +603,7 @@ impl<'a> Classifier<'a> {
///
/// It returns the token's kind, the token as a string and its byte position in the source
/// string.
- fn next(&mut self) -> Option<(TokenKind, &'a str, u32)> {
+ fn next(&mut self) -> Option<(TokenKind, &'src str, u32)> {
if let Some((kind, text)) = self.tokens.next() {
let before = self.byte_pos;
self.byte_pos += text.len() as u32;
@@ -618,7 +618,7 @@ impl<'a> Classifier<'a> {
/// The general structure for this method is to iterate over each token,
/// possibly giving it an HTML span with a class specifying what flavor of
/// token is used.
- fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
+ fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'src>)) {
loop {
if let Some(decs) = self.decorations.as_mut() {
let byte_pos = self.byte_pos;
@@ -666,8 +666,8 @@ impl<'a> Classifier<'a> {
fn advance(
&mut self,
token: TokenKind,
- text: &'a str,
- sink: &mut dyn FnMut(Highlight<'a>),
+ text: &'src str,
+ sink: &mut dyn FnMut(Highlight<'src>),
before: u32,
) {
let lookahead = self.peek();
@@ -881,7 +881,7 @@ impl<'a> Classifier<'a> {
fn enter_span(
out: &mut Buffer,
klass: Class,
- href_context: &Option<HrefContext<'_, '_, '_>>,
+ href_context: &Option<HrefContext<'_, '_>>,
) -> &'static str {
string_without_closing_tag(out, "", Some(klass), href_context, true).expect(
"internal error: enter_span was called with Some(klass) but did not return a \
@@ -914,7 +914,7 @@ fn string<T: Display>(
out: &mut Buffer,
text: T,
klass: Option<Class>,
- href_context: &Option<HrefContext<'_, '_, '_>>,
+ href_context: &Option<HrefContext<'_, '_>>,
open_tag: bool,
) {
if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag)
@@ -936,7 +936,7 @@ fn string_without_closing_tag<T: Display>(
out: &mut Buffer,
text: T,
klass: Option<Class>,
- href_context: &Option<HrefContext<'_, '_, '_>>,
+ href_context: &Option<HrefContext<'_, '_>>,
open_tag: bool,
) -> Option<&'static str> {
let Some(klass) = klass
@@ -985,7 +985,7 @@ fn string_without_closing_tag<T: Display>(
// https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
match href {
LinkFromSrc::Local(span) => {
- context.href_from_span_relative(*span, href_context.current_href)
+ context.href_from_span_relative(*span, &href_context.current_href)
}
LinkFromSrc::External(def_id) => {
format::href_with_root_path(*def_id, context, Some(href_context.root_path))
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 1e1c657b0..4ff67fe15 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -30,7 +30,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
use rustc_middle::ty::TyCtxt;
use rustc_span::edition::Edition;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
use once_cell::sync::Lazy;
use std::borrow::Cow;
@@ -198,7 +198,7 @@ fn slugify(c: char) -> Option<char> {
#[derive(Clone, Debug)]
pub struct Playground {
- pub crate_name: Option<String>,
+ pub crate_name: Option<Symbol>,
pub url: String,
}
@@ -236,12 +236,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
return event;
};
- let mut origtext = String::new();
+ let mut original_text = String::new();
for event in &mut self.inner {
match event {
Event::End(Tag::CodeBlock(..)) => break,
Event::Text(ref s) => {
- origtext.push_str(s);
+ original_text.push_str(s);
}
_ => {}
}
@@ -258,7 +258,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
<pre class=\"language-{}\"><code>{}</code></pre>\
</div>",
lang,
- Escape(&origtext),
+ Escape(&original_text),
)
.into(),
));
@@ -268,7 +268,7 @@ 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 lines = original_text.lines().filter_map(|l| map_line(l).for_html());
let text = lines.intersperse("\n".into()).collect::<String>();
compile_fail = parse_result.compile_fail;
@@ -285,12 +285,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
if url.is_empty() {
return None;
}
- let test = origtext
+ let test = original_text
.lines()
.map(|l| map_line(l).for_code())
.intersperse("\n".into())
.collect::<String>();
- let krate = krate.as_ref().map(|s| &**s);
+ let krate = krate.as_ref().map(|s| s.as_str());
let (test, _, _) =
doctest::make_test(&test, krate, false, &Default::default(), edition, None);
let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
@@ -567,11 +567,12 @@ struct SummaryLine<'a, I: Iterator<Item = Event<'a>>> {
inner: I,
started: bool,
depth: u32,
+ skipped_tags: u32,
}
impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> {
fn new(iter: I) -> Self {
- SummaryLine { inner: iter, started: false, depth: 0 }
+ SummaryLine { inner: iter, started: false, depth: 0, skipped_tags: 0 }
}
}
@@ -601,6 +602,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
let is_allowed_tag = match event {
Event::Start(ref c) => {
if is_forbidden_tag(c) {
+ self.skipped_tags += 1;
return None;
}
self.depth += 1;
@@ -608,6 +610,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
}
Event::End(ref c) => {
if is_forbidden_tag(c) {
+ self.skipped_tags += 1;
return None;
}
self.depth -= 1;
@@ -616,6 +619,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
}
_ => true,
};
+ if !is_allowed_tag {
+ self.skipped_tags += 1;
+ }
return if !is_allowed_tag {
if is_start {
Some(Event::Start(Tag::Paragraph))
@@ -1096,11 +1102,11 @@ impl MarkdownItemInfo<'_> {
}
impl MarkdownSummaryLine<'_> {
- pub(crate) fn into_string(self) -> String {
+ pub(crate) fn into_string_with_has_more_content(self) -> (String, bool) {
let MarkdownSummaryLine(md, links) = self;
// This is actually common enough to special-case
if md.is_empty() {
- return String::new();
+ return (String::new(), false);
}
let mut replacer = |broken_link: BrokenLink<'_>| {
@@ -1110,17 +1116,26 @@ impl MarkdownSummaryLine<'_> {
.map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
};
- let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
+ let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer))
+ .peekable();
+ let mut summary = SummaryLine::new(p);
let mut s = String::new();
- let without_paragraphs = LinkReplacer::new(SummaryLine::new(p), links).filter(|event| {
+ let without_paragraphs = LinkReplacer::new(&mut summary, links).filter(|event| {
!matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph))
});
html::push_html(&mut s, without_paragraphs);
- s
+ let has_more_content =
+ matches!(summary.inner.peek(), Some(Event::Start(_))) || summary.skipped_tags > 0;
+
+ (s, has_more_content)
+ }
+
+ pub(crate) fn into_string(self) -> String {
+ self.into_string_with_has_more_content().0
}
}
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index 68b31a6ee..5878c5826 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -345,4 +345,12 @@ fn test_ascii_with_prepending_hashtag() {
#..#.####.####.####..##..
</code></pre></div>",
);
+ t(
+ r#"```markdown
+# hello
+```"#,
+ "<div class=\"example-wrap\"><pre class=\"language-markdown\"><code>\
+# hello
+</code></pre></div>",
+ );
}
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 73690c86f..5cefe9475 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -309,7 +309,7 @@ impl<'tcx> Context<'tcx> {
pub(crate) fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option<String> {
let mut root = self.root_path();
- let mut path = String::new();
+ let mut path: String;
let cnum = span.cnum(self.sess());
// We can safely ignore synthetic `SourceFile`s.
@@ -340,10 +340,24 @@ impl<'tcx> Context<'tcx> {
ExternalLocation::Unknown => return None,
};
- sources::clean_path(&src_root, file, false, |component| {
- path.push_str(&component.to_string_lossy());
+ let href = RefCell::new(PathBuf::new());
+ sources::clean_path(
+ &src_root,
+ file,
+ |component| {
+ href.borrow_mut().push(component);
+ },
+ || {
+ href.borrow_mut().pop();
+ },
+ );
+
+ path = href.into_inner().to_string_lossy().to_string();
+
+ if let Some(c) = path.as_bytes().last() && *c != b'/' {
path.push('/');
- });
+ }
+
let mut fname = file.file_name().expect("source has no filename").to_os_string();
fname.push(".html");
path.push_str(&fname.to_string_lossy());
@@ -450,8 +464,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
// If user passed in `--playground-url` arg, we fill in crate name here
let mut playground = None;
if let Some(url) = playground_url {
- playground =
- Some(markdown::Playground { crate_name: Some(krate.name(tcx).to_string()), url });
+ playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url });
}
let mut layout = layout::Layout {
logo: String::new(),
@@ -477,7 +490,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
}
(sym::html_playground_url, Some(s)) => {
playground = Some(markdown::Playground {
- crate_name: Some(krate.name(tcx).to_string()),
+ crate_name: Some(krate.name(tcx)),
url: s.to_string(),
});
}
@@ -625,7 +638,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
write!(
buf,
"<div class=\"main-heading\">\
- <h1 class=\"fqn\">Rustdoc settings</h1>\
+ <h1>Rustdoc settings</h1>\
<span class=\"out-of-band\">\
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
Back\
@@ -637,7 +650,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
You need to enable Javascript be able to update your settings.\
</section>\
</noscript>\
- <link rel=\"stylesheet\" type=\"text/css\" \
+ <link rel=\"stylesheet\" \
href=\"{static_root_path}{settings_css}\">\
<script defer src=\"{static_root_path}{settings_js}\"></script>",
static_root_path = page.get_static_root_path(),
@@ -663,7 +676,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
write!(
buf,
"<div class=\"main-heading\">\
- <h1 class=\"fqn\">Rustdoc help</h1>\
+ <h1>Rustdoc help</h1>\
<span class=\"out-of-band\">\
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
Back\
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 36d15ec3b..4fa33e890 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -100,7 +100,7 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
#[derive(Debug)]
pub(crate) struct IndexItem {
pub(crate) ty: ItemType,
- pub(crate) name: String,
+ pub(crate) name: Symbol,
pub(crate) path: String,
pub(crate) desc: String,
pub(crate) parent: Option<DefId>,
@@ -364,7 +364,7 @@ impl AllTypes {
}
}
- f.write_str("<h1 class=\"fqn\">List of all items</h1>");
+ f.write_str("<h1>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, ItemSection::Structs);
@@ -394,7 +394,7 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
let mut ids = IdMap::default();
format!(
"<div class=\"main-heading\">\
- <h1 class=\"fqn\">About scraped examples</h1>\
+ <h1>About scraped examples</h1>\
</div>\
<div>{}</div>",
Markdown {
@@ -467,9 +467,10 @@ fn document_short(
return;
}
if let Some(s) = item.doc_value() {
- let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string();
+ let (mut summary_html, has_more_content) =
+ MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content();
- if s.contains('\n') {
+ if has_more_content {
let link = format!(r#" <a{}>Read more</a>"#, assoc_href_attr(item, link, cx));
if let Some(idx) = summary_html.rfind("</p>") {
@@ -512,7 +513,7 @@ fn document_full_inner(
debug!("Doc block: =====\n{}\n=====", s);
if is_collapsible {
w.write_str(
- "<details class=\"rustdoc-toggle top-doc\" open>\
+ "<details class=\"toggle top-doc\" open>\
<summary class=\"hideme\">\
<span>Expand description</span>\
</summary>",
@@ -1342,7 +1343,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
write!(
&mut out,
"<h3>Notable traits for <code>{}</code></h3>\
- <pre class=\"content\"><code>",
+ <pre><code>",
impl_.for_.print(cx)
);
}
@@ -1512,9 +1513,8 @@ fn render_impl(
let toggled = !doc_buffer.is_empty();
if toggled {
- let method_toggle_class =
- if item_type == ItemType::Method { " method-toggle" } else { "" };
- write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
+ let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
+ write!(w, "<details class=\"toggle{}\" open><summary>", method_toggle_class);
}
match &*item.kind {
clean::MethodItem(..) | clean::TyMethodItem(_) => {
@@ -1730,7 +1730,7 @@ fn render_impl(
close_tags.insert_str(0, "</details>");
write!(
w,
- "<details class=\"rustdoc-toggle implementors-toggle\"{}>",
+ "<details class=\"toggle implementors-toggle\"{}>",
if rendering_params.toggle_open_by_default { " open" } else { "" }
);
write!(w, "<summary>")
@@ -2769,8 +2769,8 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
let mut work = VecDeque::new();
let mut process_path = |did: DefId| {
- let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
- let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
+ let get_extern = || cache.external_paths.get(&did).map(|s| &s.0);
+ let fqp = cache.exact_paths.get(&did).or_else(get_extern);
if let Some(path) = fqp {
out.push(join_with_double_colon(&path));
@@ -2921,7 +2921,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
// Look for the example file in the source map if it exists, otherwise return a dummy span
let file_span = (|| {
let source_map = tcx.sess.source_map();
- let crate_src = tcx.sess.local_crate_source_file.as_ref()?;
+ let crate_src = tcx.sess.local_crate_source_file()?;
let abs_crate_src = crate_src.canonicalize().ok()?;
let crate_root = abs_crate_src.parent()?.parent()?;
let rel_path = path.strip_prefix(crate_root).ok()?;
@@ -2999,14 +2999,13 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
if it.peek().is_some() {
write!(
w,
- "<details class=\"rustdoc-toggle more-examples-toggle\">\
+ "<details class=\"toggle more-examples-toggle\">\
<summary class=\"hideme\">\
<span>More examples</span>\
</summary>\
<div class=\"hide-more\">Hide additional examples</div>\
<div class=\"more-scraped-examples\">\
- <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
- <div class=\"more-scraped-examples-inner\">"
+ <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>"
);
// Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
@@ -3030,7 +3029,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
write!(w, "</ul></div>");
}
- write!(w, "</div></div></details>");
+ write!(w, "</div></details>");
}
write!(w, "</div>");
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index acbe3f228..f824c9e3a 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -204,7 +204,7 @@ fn should_hide_fields(n_fields: usize) -> bool {
fn toggle_open(w: &mut Buffer, text: impl fmt::Display) {
write!(
w,
- "<details class=\"rustdoc-toggle type-contents-toggle\">\
+ "<details class=\"toggle type-contents-toggle\">\
<summary class=\"hideme\">\
<span>Show {}</span>\
</summary>",
@@ -531,7 +531,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx));
wrap_into_item_decl(w, |w| {
- wrap_item(w, "fn", |w| {
+ wrap_item(w, |w| {
render_attributes_in_pre(w, it, "");
w.reserve(header_len);
write!(
@@ -570,7 +570,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
// Output the trait definition
wrap_into_item_decl(w, |w| {
- wrap_item(w, "trait", |w| {
+ wrap_item(w, |w| {
render_attributes_in_pre(w, it, "");
write!(
w,
@@ -732,7 +732,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
document(&mut content, cx, m, Some(t), HeadingOffset::H5);
let toggled = !content.is_empty();
if toggled {
- write!(w, "<details class=\"rustdoc-toggle method-toggle\" open><summary>");
+ let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
+ write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
}
write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id);
render_rightside(w, cx, m, t, RenderMode::Normal);
@@ -1026,8 +1027,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
.chain(std::iter::once("implementors"))
.collect();
if let Some(did) = it.item_id.as_def_id() &&
- let get_extern = { || cache.external_paths.get(&did).map(|s| s.0.clone()) } &&
- let Some(fqp) = cache.exact_paths.get(&did).cloned().or_else(get_extern) {
+ let get_extern = { || cache.external_paths.get(&did).map(|s| &s.0) } &&
+ let Some(fqp) = cache.exact_paths.get(&did).or_else(get_extern) {
js_src_path.extend(fqp[..fqp.len() - 1].iter().copied());
js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap()));
} else {
@@ -1050,7 +1051,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
wrap_into_item_decl(w, |w| {
- wrap_item(w, "trait-alias", |w| {
+ wrap_item(w, |w| {
render_attributes_in_pre(w, it, "");
write!(
w,
@@ -1074,7 +1075,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &
fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
wrap_into_item_decl(w, |w| {
- wrap_item(w, "opaque", |w| {
+ wrap_item(w, |w| {
render_attributes_in_pre(w, it, "");
write!(
w,
@@ -1098,7 +1099,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl
fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Typedef) {
fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
- wrap_item(w, "typedef", |w| {
+ wrap_item(w, |w| {
render_attributes_in_pre(w, it, "");
write!(w, "{}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx));
write!(
@@ -1127,7 +1128,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) {
wrap_into_item_decl(w, |w| {
- wrap_item(w, "union", |w| {
+ wrap_item(w, |w| {
render_attributes_in_pre(w, it, "");
render_union(w, it, Some(&s.generics), &s.fields, "", cx);
});
@@ -1192,7 +1193,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
let tcx = cx.tcx();
let count_variants = e.variants().count();
wrap_into_item_decl(w, |w| {
- wrap_item(w, "enum", |w| {
+ wrap_item(w, |w| {
render_attributes_in_pre(w, it, "");
write!(
w,
@@ -1219,25 +1220,16 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
w.write_str(" ");
let name = v.name.unwrap();
match *v.kind {
- clean::VariantItem(ref var) => match var {
- // FIXME(#101337): Show discriminant
- clean::Variant::CLike(..) => write!(w, "{}", name),
- clean::Variant::Tuple(ref s) => {
+ // FIXME(#101337): Show discriminant
+ clean::VariantItem(ref var) => match var.kind {
+ clean::VariantKind::CLike => write!(w, "{}", name),
+ clean::VariantKind::Tuple(ref s) => {
write!(w, "{}(", name);
print_tuple_struct_fields(w, cx, s);
w.write_str(")");
}
- clean::Variant::Struct(ref s) => {
- render_struct(
- w,
- v,
- None,
- s.ctor_kind,
- &s.fields,
- " ",
- false,
- cx,
- );
+ clean::VariantKind::Struct(ref s) => {
+ render_struct(w, v, None, None, &s.fields, " ", false, cx);
}
},
_ => unreachable!(),
@@ -1285,25 +1277,28 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
" rightside",
);
write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
- if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind {
+
+ let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
+
+ if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
w.write_str("(");
print_tuple_struct_fields(w, cx, s);
w.write_str(")");
}
w.write_str("</h3></section>");
- use crate::clean::Variant;
-
- let heading_and_fields = match &*variant.kind {
- clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)),
- // Documentation on tuple variant fields is rare, so to reduce noise we only emit
- // the section if at least one field is documented.
- clean::VariantItem(Variant::Tuple(fields))
- if fields.iter().any(|f| f.doc_value().is_some()) =>
- {
- Some(("Tuple Fields", fields))
+ let heading_and_fields = match &variant_data.kind {
+ clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)),
+ clean::VariantKind::Tuple(fields) => {
+ // Documentation on tuple variant fields is rare, so to reduce noise we only emit
+ // the section if at least one field is documented.
+ if fields.iter().any(|f| f.doc_value().is_some()) {
+ Some(("Tuple Fields", fields))
+ } else {
+ None
+ }
}
- _ => None,
+ clean::VariantKind::CLike => None,
};
if let Some((heading, fields)) = heading_and_fields {
@@ -1362,17 +1357,17 @@ fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &c
let name = it.name.expect("proc-macros always have names");
match m.kind {
MacroKind::Bang => {
- wrap_item(w, "macro", |w| {
+ wrap_item(w, |w| {
write!(w, "{}!() {{ /* proc-macro */ }}", name);
});
}
MacroKind::Attr => {
- wrap_item(w, "attr", |w| {
+ wrap_item(w, |w| {
write!(w, "#[{}]", name);
});
}
MacroKind::Derive => {
- wrap_item(w, "derive", |w| {
+ wrap_item(w, |w| {
write!(w, "#[derive({})]", name);
if !m.helpers.is_empty() {
w.push_str("\n{\n");
@@ -1406,7 +1401,7 @@ fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
wrap_into_item_decl(w, |w| {
- wrap_item(w, "const", |w| {
+ wrap_item(w, |w| {
let tcx = cx.tcx();
render_attributes_in_code(w, it);
@@ -1456,7 +1451,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
wrap_into_item_decl(w, |w| {
- wrap_item(w, "struct", |w| {
+ wrap_item(w, |w| {
render_attributes_in_code(w, it);
render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
});
@@ -1509,7 +1504,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
wrap_into_item_decl(w, |w| {
- wrap_item(w, "static", |w| {
+ wrap_item(w, |w| {
render_attributes_in_code(w, it);
write!(
w,
@@ -1526,7 +1521,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
wrap_into_item_decl(w, |w| {
- wrap_item(w, "foreigntype", |w| {
+ wrap_item(w, |w| {
w.write_str("extern {\n");
render_attributes_in_code(w, it);
write!(
@@ -1623,11 +1618,11 @@ where
w.write_str("</div>")
}
-fn wrap_item<F>(w: &mut Buffer, item_name: &str, f: F)
+fn wrap_item<F>(w: &mut Buffer, f: F)
where
F: FnOnce(&mut Buffer),
{
- w.write_fmt(format_args!("<pre class=\"rust {}\"><code>", item_name));
+ w.write_str(r#"<pre class="rust"><code>"#);
f(w);
w.write_str("</code></pre>");
}
@@ -1845,7 +1840,7 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
if item.is_non_exhaustive() {
write!(
w,
- "<details class=\"rustdoc-toggle non-exhaustive\">\
+ "<details class=\"toggle non-exhaustive\">\
<summary class=\"hideme\"><span>{}</span></summary>\
<div class=\"docblock\">",
{
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 8eb9c07f8..5b0caac09 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -3,7 +3,6 @@ use std::collections::BTreeMap;
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::Symbol;
use serde::ser::{Serialize, SerializeStruct, Serializer};
@@ -24,18 +23,19 @@ pub(crate) fn build_index<'tcx>(
tcx: TyCtxt<'tcx>,
) -> String {
let mut itemid_to_pathid = FxHashMap::default();
+ let mut primitives = FxHashMap::default();
let mut crate_paths = vec![];
// Attach all orphan items to the type's definition if the type
// has since been learned.
for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items {
- if let Some(&(ref fqp, _)) = cache.paths.get(&parent) {
+ if let Some((fqp, _)) = cache.paths.get(&parent) {
let desc = item
.doc_value()
.map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache)));
cache.search_index.push(IndexItem {
ty: item.type_(),
- name: item.name.unwrap().to_string(),
+ name: item.name.unwrap(),
path: join_with_double_colon(&fqp[..fqp.len() - 1]),
desc,
parent: Some(parent),
@@ -58,8 +58,8 @@ pub(crate) fn build_index<'tcx>(
// Sort search index items. This improves the compressibility of the search index.
cache.search_index.sort_unstable_by(|k1, k2| {
// `sort_unstable_by_key` produces lifetime errors
- let k1 = (&k1.path, &k1.name, &k1.ty, &k1.parent);
- let k2 = (&k2.path, &k2.name, &k2.ty, &k2.parent);
+ let k1 = (&k1.path, k1.name.as_str(), &k1.ty, &k1.parent);
+ let k2 = (&k2.path, k2.name.as_str(), &k2.ty, &k2.parent);
std::cmp::Ord::cmp(&k1, &k2)
});
@@ -78,16 +78,45 @@ pub(crate) fn build_index<'tcx>(
// First, on function signatures
let mut search_index = std::mem::replace(&mut cache.search_index, Vec::new());
for item in search_index.iter_mut() {
+ fn insert_into_map<F: std::hash::Hash + Eq>(
+ ty: &mut RenderType,
+ map: &mut FxHashMap<F, usize>,
+ itemid: F,
+ lastpathid: &mut usize,
+ crate_paths: &mut Vec<(ItemType, Symbol)>,
+ item_type: ItemType,
+ path: Symbol,
+ ) {
+ match map.entry(itemid) {
+ Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())),
+ Entry::Vacant(entry) => {
+ let pathid = *lastpathid;
+ entry.insert(pathid);
+ *lastpathid += 1;
+ crate_paths.push((item_type, path));
+ ty.id = Some(RenderTypeId::Index(pathid));
+ }
+ }
+ }
+
fn convert_render_type(
ty: &mut RenderType,
cache: &mut Cache,
itemid_to_pathid: &mut FxHashMap<ItemId, usize>,
+ primitives: &mut FxHashMap<Symbol, usize>,
lastpathid: &mut usize,
crate_paths: &mut Vec<(ItemType, Symbol)>,
) {
if let Some(generics) = &mut ty.generics {
for item in generics {
- convert_render_type(item, cache, itemid_to_pathid, lastpathid, crate_paths);
+ convert_render_type(
+ item,
+ cache,
+ itemid_to_pathid,
+ primitives,
+ lastpathid,
+ crate_paths,
+ );
}
}
let Cache { ref paths, ref external_paths, .. } = *cache;
@@ -95,33 +124,37 @@ pub(crate) fn build_index<'tcx>(
assert!(ty.generics.is_some());
return;
};
- let (itemid, path, item_type) = match id {
+ match id {
RenderTypeId::DefId(defid) => {
if let Some(&(ref fqp, item_type)) =
paths.get(&defid).or_else(|| external_paths.get(&defid))
{
- (ItemId::DefId(defid), *fqp.last().unwrap(), item_type)
+ insert_into_map(
+ ty,
+ itemid_to_pathid,
+ ItemId::DefId(defid),
+ lastpathid,
+ crate_paths,
+ item_type,
+ *fqp.last().unwrap(),
+ );
} else {
ty.id = None;
- return;
}
}
- RenderTypeId::Primitive(primitive) => (
- ItemId::Primitive(primitive, LOCAL_CRATE),
- primitive.as_sym(),
- ItemType::Primitive,
- ),
- RenderTypeId::Index(_) => return,
- };
- match itemid_to_pathid.entry(itemid) {
- Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())),
- Entry::Vacant(entry) => {
- let pathid = *lastpathid;
- entry.insert(pathid);
- *lastpathid += 1;
- crate_paths.push((item_type, path));
- ty.id = Some(RenderTypeId::Index(pathid));
+ RenderTypeId::Primitive(primitive) => {
+ let sym = primitive.as_sym();
+ insert_into_map(
+ ty,
+ primitives,
+ sym,
+ lastpathid,
+ crate_paths,
+ ItemType::Primitive,
+ sym,
+ );
}
+ RenderTypeId::Index(_) => {}
}
}
if let Some(search_type) = &mut item.search_type {
@@ -130,6 +163,7 @@ pub(crate) fn build_index<'tcx>(
item,
cache,
&mut itemid_to_pathid,
+ &mut primitives,
&mut lastpathid,
&mut crate_paths,
);
@@ -139,6 +173,7 @@ pub(crate) fn build_index<'tcx>(
item,
cache,
&mut itemid_to_pathid,
+ &mut primitives,
&mut lastpathid,
&mut crate_paths,
);
@@ -205,7 +240,7 @@ pub(crate) fn build_index<'tcx>(
)?;
crate_data.serialize_field(
"n",
- &self.items.iter().map(|item| &item.name).collect::<Vec<_>>(),
+ &self.items.iter().map(|item| item.name.as_str()).collect::<Vec<_>>(),
)?;
crate_data.serialize_field(
"q",
@@ -264,7 +299,7 @@ pub(crate) fn build_index<'tcx>(
)?;
crate_data.serialize_field(
"p",
- &self.paths.iter().map(|(it, s)| (it, s.to_string())).collect::<Vec<_>>(),
+ &self.paths.iter().map(|(it, s)| (it, s.as_str())).collect::<Vec<_>>(),
)?;
if has_aliases {
crate_data.serialize_field("a", &self.aliases)?;
@@ -322,8 +357,7 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> {
match *clean_type {
clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())),
clean::DynTrait(ref bounds, _) => {
- let path = &bounds[0].trait_;
- Some(RenderTypeId::DefId(path.def_id()))
+ bounds.get(0).map(|b| RenderTypeId::DefId(b.trait_.def_id()))
}
clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
@@ -539,7 +573,7 @@ fn get_fn_inputs_and_outputs<'tcx>(
let decl = &func.decl;
let combined_generics;
- let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics {
+ let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_generics {
match (impl_generics.is_empty(), func.generics.is_empty()) {
(true, _) => (Some(impl_self), &func.generics),
(_, true) => (Some(impl_self), impl_generics),
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 94d8a9fec..bc8badad3 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -1,8 +1,9 @@
+use std::cell::RefCell;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::{Component, Path};
-use std::rc::Rc;
+use std::rc::{Rc, Weak};
use itertools::Itertools;
use rustc_data_structures::flock;
@@ -184,23 +185,26 @@ pub(super) fn write_shared(
use std::ffi::OsString;
- #[derive(Debug)]
+ #[derive(Debug, Default)]
struct Hierarchy {
+ parent: Weak<Self>,
elem: OsString,
- children: FxHashMap<OsString, Hierarchy>,
- elems: FxHashSet<OsString>,
+ children: RefCell<FxHashMap<OsString, Rc<Self>>>,
+ elems: RefCell<FxHashSet<OsString>>,
}
impl Hierarchy {
- fn new(elem: OsString) -> Hierarchy {
- Hierarchy { elem, children: FxHashMap::default(), elems: FxHashSet::default() }
+ fn with_parent(elem: OsString, parent: &Rc<Self>) -> Self {
+ Self { elem, parent: Rc::downgrade(parent), ..Self::default() }
}
fn to_json_string(&self) -> String {
- let mut subs: Vec<&Hierarchy> = self.children.values().collect();
+ let borrow = self.children.borrow();
+ let mut subs: Vec<_> = borrow.values().collect();
subs.sort_unstable_by(|a, b| a.elem.cmp(&b.elem));
let mut files = self
.elems
+ .borrow()
.iter()
.map(|s| format!("\"{}\"", s.to_str().expect("invalid osstring conversion")))
.collect::<Vec<_>>();
@@ -220,36 +224,52 @@ pub(super) fn write_shared(
files = files
)
}
- }
- if cx.include_sources {
- let mut hierarchy = Hierarchy::new(OsString::new());
- for source in cx
- .shared
- .local_sources
- .iter()
- .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok())
- {
- let mut h = &mut hierarchy;
- let mut elems = source
+ fn add_path(self: &Rc<Self>, path: &Path) {
+ let mut h = Rc::clone(&self);
+ let mut elems = path
.components()
.filter_map(|s| match s {
Component::Normal(s) => Some(s.to_owned()),
+ Component::ParentDir => Some(OsString::from("..")),
_ => None,
})
.peekable();
loop {
let cur_elem = elems.next().expect("empty file path");
+ if cur_elem == ".." {
+ if let Some(parent) = h.parent.upgrade() {
+ h = parent;
+ }
+ continue;
+ }
if elems.peek().is_none() {
- h.elems.insert(cur_elem);
+ h.elems.borrow_mut().insert(cur_elem);
break;
} else {
- let e = cur_elem.clone();
- h = h.children.entry(cur_elem.clone()).or_insert_with(|| Hierarchy::new(e));
+ let entry = Rc::clone(
+ h.children
+ .borrow_mut()
+ .entry(cur_elem.clone())
+ .or_insert_with(|| Rc::new(Self::with_parent(cur_elem, &h))),
+ );
+ h = entry;
}
}
}
+ }
+ if cx.include_sources {
+ let hierarchy = Rc::new(Hierarchy::default());
+ for source in cx
+ .shared
+ .local_sources
+ .iter()
+ .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok())
+ {
+ hierarchy.add_path(source);
+ }
+ let hierarchy = Rc::try_unwrap(hierarchy).unwrap();
let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
let make_sources = || {
let (mut all_sources, _krates) =
@@ -325,7 +345,7 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
};
let content = format!(
- "<h1 class=\"fqn\">List of all crates</h1><ul class=\"all-items\">{}</ul>",
+ "<h1>List of all crates</h1><ul class=\"all-items\">{}</ul>",
krates
.iter()
.map(|s| {
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 54e296959..799c497d1 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -13,6 +13,7 @@ use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::source_map::FileName;
+use std::cell::RefCell;
use std::ffi::OsStr;
use std::fs;
use std::path::{Component, Path, PathBuf};
@@ -72,12 +73,22 @@ impl LocalSourcesCollector<'_, '_> {
return;
}
- let mut href = String::new();
- clean_path(self.src_root, &p, false, |component| {
- href.push_str(&component.to_string_lossy());
- href.push('/');
- });
+ let href = RefCell::new(PathBuf::new());
+ clean_path(
+ &self.src_root,
+ &p,
+ |component| {
+ href.borrow_mut().push(component);
+ },
+ || {
+ href.borrow_mut().pop();
+ },
+ );
+ let mut href = href.into_inner().to_string_lossy().to_string();
+ if let Some(c) = href.as_bytes().last() && *c != b'/' {
+ href.push('/');
+ }
let mut src_fname = p.file_name().expect("source has no filename").to_os_string();
src_fname.push(".html");
href.push_str(&src_fname.to_string_lossy());
@@ -180,13 +191,28 @@ impl SourceCollector<'_, '_> {
let shared = Rc::clone(&self.cx.shared);
// Create the intermediate directories
- let mut cur = self.dst.clone();
- let mut root_path = String::from("../../");
- clean_path(&shared.src_root, &p, false, |component| {
- cur.push(component);
- root_path.push_str("../");
- });
+ let cur = RefCell::new(PathBuf::new());
+ let root_path = RefCell::new(PathBuf::new());
+
+ clean_path(
+ &shared.src_root,
+ &p,
+ |component| {
+ cur.borrow_mut().push(component);
+ root_path.borrow_mut().push("..");
+ },
+ || {
+ cur.borrow_mut().pop();
+ root_path.borrow_mut().pop();
+ },
+ );
+ let root_path = PathBuf::from("../../").join(root_path.into_inner());
+ let mut root_path = root_path.to_string_lossy();
+ if let Some(c) = root_path.as_bytes().last() && *c != b'/' {
+ root_path += "/";
+ }
+ let mut cur = self.dst.join(cur.into_inner());
shared.ensure_dir(&cur)?;
let src_fname = p.file_name().expect("source has no filename").to_os_string();
@@ -232,11 +258,13 @@ impl SourceCollector<'_, '_> {
/// Takes a path to a source file and cleans the path to it. This canonicalizes
/// things like ".." to components which preserve the "top down" hierarchy of a
/// static HTML tree. Each component in the cleaned path will be passed as an
-/// argument to `f`. The very last component of the path (ie the file name) will
-/// be passed to `f` if `keep_filename` is true, and ignored otherwise.
-pub(crate) fn clean_path<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F)
+/// argument to `f`. The very last component of the path (ie the file name) is ignored.
+/// If a `..` is encountered, the `parent` closure will be called to allow the callee to
+/// handle it.
+pub(crate) fn clean_path<F, P>(src_root: &Path, p: &Path, mut f: F, mut parent: P)
where
F: FnMut(&OsStr),
+ P: FnMut(),
{
// make it relative, if possible
let p = p.strip_prefix(src_root).unwrap_or(p);
@@ -244,12 +272,12 @@ where
let mut iter = p.components().peekable();
while let Some(c) = iter.next() {
- if !keep_filename && iter.peek().is_none() {
+ if iter.peek().is_none() {
break;
}
match c {
- Component::ParentDir => f("up".as_ref()),
+ Component::ParentDir => parent(),
Component::Normal(c) => f(c),
_ => continue,
}
@@ -276,7 +304,7 @@ pub(crate) fn print_src(
let mut line_numbers = Buffer::empty_from(buf);
let extra;
line_numbers.write_str("<pre class=\"src-line-numbers\">");
- let current_href = &context
+ let current_href = context
.href_from_span(clean::Span::new(file_span), false)
.expect("only local crates should have sources emitted");
match source_context {
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index afcb40224..a93f60da2 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -76,8 +76,6 @@
}
* {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
box-sizing: border-box;
}
@@ -110,11 +108,7 @@ body {
/* Then override it with `anywhere`, which is required to make non-Safari browsers break
more aggressively when we want them to. */
overflow-wrap: anywhere;
-
- -webkit-font-feature-settings: "kern", "liga";
- -moz-font-feature-settings: "kern", "liga";
font-feature-settings: "kern", "liga";
-
background-color: var(--main-background-color);
color: var(--main-color);
}
@@ -145,7 +139,7 @@ h1, h2, h3, h4 {
.docblock > h6:first-child {
margin-top: 0;
}
-h1.fqn {
+.main-heading h1 {
margin: 0;
padding: 0;
flex-grow: 1;
@@ -212,7 +206,7 @@ pre.rust a,
.mobile-topbar h2 a,
h1 a,
.search-results a,
-.item-left .stab,
+.stab,
.result-name .primitive > i, .result-name .keyword > i {
color: var(--main-color);
}
@@ -259,6 +253,7 @@ h1 a,
a {
color: var(--link-color);
+ text-decoration: none;
}
ol, ul {
@@ -322,11 +317,7 @@ main {
margin-right: auto;
}
-.source .width-limiter {
- max-width: unset;
-}
-
-details:not(.rustdoc-toggle) summary {
+details:not(.toggle) summary {
margin-bottom: .6em;
}
@@ -342,26 +333,35 @@ code, pre, a.test-arrow, .code-header {
}
pre {
padding: 14px;
+ line-height: 1.5; /* https://github.com/rust-lang/rust/issues/105906 */
}
.item-decl pre {
overflow-x: auto;
}
+/* This rule allows to have scrolling on the X axis. */
+.item-decl .type-contents-toggle {
+ contain: initial;
+}
.source .content pre {
padding: 20px;
}
+.rustdoc.source .example-wrap > pre.src-line-numbers {
+ padding: 20px 0 20px 4px;
+}
img {
max-width: 100%;
}
-.source .content {
- overflow: visible;
-}
-
.sub-logo-container, .logo-container {
/* zero text boxes so that computed line height = image height exactly */
line-height: 0;
+ display: block;
+}
+
+.sub-logo-container {
+ margin-right: 32px;
}
.sub-logo-container > img {
@@ -374,10 +374,6 @@ img {
filter: var(--rust-logo-filter);
}
-.sidebar, .mobile-topbar, .sidebar-menu-toggle {
- background-color: var(--sidebar-background-color);
-}
-
.sidebar {
font-size: 0.875rem;
flex: 0 0 200px;
@@ -396,15 +392,16 @@ img {
overflow-y: hidden;
}
-.source .sidebar, #sidebar-toggle, #source-sidebar {
+.sidebar, .mobile-topbar, .sidebar-menu-toggle,
+#src-sidebar-toggle, #source-sidebar {
background-color: var(--sidebar-background-color);
}
-#sidebar-toggle > button:hover, #sidebar-toggle > button:focus {
+#src-sidebar-toggle > button:hover, #src-sidebar-toggle > button:focus {
background-color: var(--sidebar-background-color-hover);
}
-.source .sidebar > *:not(#sidebar-toggle) {
+.source .sidebar > *:not(#src-sidebar-toggle) {
visibility: hidden;
}
@@ -413,7 +410,7 @@ img {
flex-basis: 300px;
}
-.source-sidebar-expanded .source .sidebar > *:not(#sidebar-toggle) {
+.source-sidebar-expanded .source .sidebar > *:not(#src-sidebar-toggle) {
visibility: visible;
}
@@ -500,11 +497,11 @@ ul.block, .block li {
padding-left: 24px;
}
-.sidebar a, .sidebar .current {
+.sidebar a {
color: var(--sidebar-link-color);
}
.sidebar .current,
-.sidebar a:hover {
+.sidebar a:hover:not(.logo-container) {
background-color: var(--sidebar-current-link-background-color);
}
@@ -522,11 +519,6 @@ ul.block, .block li {
display: none;
}
-.source .content pre.rust {
- overflow: auto;
- padding-left: 0;
-}
-
.rustdoc .example-wrap {
display: flex;
position: relative;
@@ -547,29 +539,26 @@ ul.block, .block li {
.rustdoc .example-wrap > pre.example-line-numbers,
.rustdoc .example-wrap > pre.src-line-numbers {
flex-grow: 0;
+ min-width: fit-content; /* prevent collapsing into nothing in truncated scraped examples */
overflow: initial;
text-align: right;
-webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
user-select: none;
+ padding: 14px 8px;
+ color: var(--src-line-numbers-span-color);
}
-.example-line-numbers {
- border: 1px solid;
- padding: 13px 8px;
- border-top-left-radius: 5px;
- border-bottom-left-radius: 5px;
- border-color: var(--example-line-numbers-border-color);
+.rustdoc .example-wrap > pre.src-line-numbers {
+ padding: 14px 0;
}
-
.src-line-numbers a, .src-line-numbers span {
color: var(--src-line-numbers-span-color);
+ padding: 0 8px;
}
.src-line-numbers :target {
background-color: transparent;
border-right: none;
- padding-right: 0;
+ padding: 0 8px;
}
.src-line-numbers .line-highlighted {
background-color: var(--src-line-number-highlighted-background-color);
@@ -582,12 +571,10 @@ ul.block, .block li {
.docblock-short {
overflow-wrap: break-word;
overflow-wrap: anywhere;
- overflow: hidden;
- text-overflow: ellipsis;
}
/* Wrap non-pre code blocks (`text`) but not (```text```). */
-.docblock > :not(pre) > code,
-.docblock-short > code {
+.docblock :not(pre) > code,
+.docblock-short code {
white-space: pre-wrap;
}
@@ -679,13 +666,6 @@ nav.sub {
.source nav.sub {
margin: 0 0 15px 0;
}
-.source .search-form {
- margin-left: 32px;
-}
-
-a {
- text-decoration: none;
-}
.small-section-header {
/* fields use <span> tags, but should get their own lines */
@@ -693,14 +673,10 @@ a {
position: relative;
}
-.small-section-header:hover > .anchor {
+.small-section-header:hover > .anchor, .impl:hover > .anchor,
+.trait-impl:hover > .anchor, .variant:hover > .anchor {
display: initial;
}
-
-.impl:hover > .anchor, .trait-impl:hover > .anchor, .variant:hover > .anchor {
- display: inline-block;
- position: absolute;
-}
.anchor {
display: none;
position: absolute;
@@ -731,7 +707,7 @@ h2.small-section-header > .anchor {
/* In most contexts we use `overflow-wrap: anywhere` to ensure that we can wrap
as much as needed on mobile (see
- src/test/rustdoc-gui/type-declaration-overflow.goml for an example of why
+ tests/rustdoc-gui/type-declaration-overflow.goml for an example of why
this matters). The `anywhere` value means:
"Soft wrap opportunities introduced by the word break are considered when
@@ -903,10 +879,11 @@ so that we can apply CSS-filters to change the arrow color in themes */
top: 100%;
right: 0;
z-index: 2;
- display: block;
margin-top: 7px;
border-radius: 3px;
border: 1px solid var(--border-color);
+ background-color: var(--main-background-color);
+ color: var(--main-color);
--popover-arrow-offset: 11px;
}
@@ -917,16 +894,12 @@ so that we can apply CSS-filters to change the arrow color in themes */
right: var(--popover-arrow-offset);
border: solid var(--border-color);
border-width: 1px 1px 0 0;
+ background-color: var(--main-background-color);
padding: 4px;
transform: rotate(-45deg);
top: -5px;
}
-.popover, .popover::before {
- background-color: var(--main-background-color);
- color: var(--main-color);
-}
-
/* use larger max-width for help popover, but not for help.html */
#help.popover {
max-width: 600px;
@@ -960,22 +933,29 @@ so that we can apply CSS-filters to change the arrow color in themes */
}
.item-info .stab {
- width: fit-content;
/* This min-height is needed to unify the height of the stab elements because some of them
have emojis.
*/
min-height: 36px;
display: flex;
- align-items: center;
- white-space: pre-wrap;
-}
-.stab {
padding: 3px;
margin-bottom: 5px;
+}
+.item-left .stab {
+ margin-left: 0.3125em;
+}
+.stab {
+ padding: 0 2px;
font-size: 0.875rem;
font-weight: normal;
color: var(--main-color);
background-color: var(--stab-background-color);
+ width: fit-content;
+ align-items: center;
+ white-space: pre-wrap;
+ border-radius: 3px;
+ display: inline-flex;
+ vertical-align: text-bottom;
}
.stab.portability > code {
@@ -988,12 +968,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
margin-right: 0.3rem;
}
-/* This is to prevent the `.stab` elements to overflow the .docblock elements. */
-.docblock .stab {
- padding: 0 0.125em;
- margin-bottom: 0;
-}
-
/* Black one-pixel outline around emoji shapes */
.emoji {
text-shadow:
@@ -1003,16 +977,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
0 -1px 0 black;
}
-.item-left .stab {
- border-radius: 3px;
- display: inline-block;
- line-height: 1.2;
- margin-bottom: 0;
- margin-left: 0.3125em;
- padding: 2px;
- vertical-align: text-bottom;
-}
-
.module-item.unstable,
.import-item.unstable {
opacity: 0.65;
@@ -1084,6 +1048,10 @@ pre.rust .doccomment {
color: var(--code-highlight-doc-comment-color);
}
+.rustdoc.source .example-wrap pre.rust a {
+ background: var(--codeblock-link-background);
+}
+
.example-wrap.compile_fail,
.example-wrap.should_panic {
border-left: 2px solid var(--codeblock-error-color);
@@ -1127,9 +1095,7 @@ pre.rust .doccomment {
top: 5px;
}
-.example-wrap .tooltip::after {
- display: none;
- text-align: center;
+.example-wrap .tooltip:hover::after {
padding: 5px 3px 3px 3px;
border-radius: 6px;
margin-left: 5px;
@@ -1143,35 +1109,30 @@ pre.rust .doccomment {
color: var(--tooltip-color);
}
-.example-wrap .tooltip::before {
+.example-wrap .tooltip:hover::before {
content: " ";
position: absolute;
top: 50%;
left: 16px;
margin-top: -5px;
- display: none;
z-index: 1;
border: 5px solid transparent;
border-right-color: var(--tooltip-background-color);
}
-.example-wrap.ignore .tooltip::after {
+.example-wrap.ignore .tooltip:hover::after {
content: "This example is not tested";
}
-.example-wrap.compile_fail .tooltip::after {
+.example-wrap.compile_fail .tooltip:hover::after {
content: "This example deliberately fails to compile";
}
-.example-wrap.should_panic .tooltip::after {
+.example-wrap.should_panic .tooltip:hover::after {
content: "This example panics";
}
-.example-wrap.edition .tooltip::after {
+.example-wrap.edition .tooltip:hover::after {
content: "This code runs with edition " attr(data-edition);
}
-.example-wrap .tooltip:hover::before, .example-wrap .tooltip:hover::after {
- display: inline;
-}
-
.example-wrap.compile_fail .tooltip,
.example-wrap.should_panic .tooltip,
.example-wrap.ignore .tooltip {
@@ -1253,11 +1214,11 @@ a.test-arrow:hover {
content: "\00a0";
}
-.notable .docblock {
+.notable .content {
margin: 0.25em 0.5em;
}
-.notable .docblock pre, .notable .docblock code {
+.notable .content pre, .notable .content code {
background: transparent;
margin: 0;
padding: 0;
@@ -1265,6 +1226,10 @@ a.test-arrow:hover {
white-space: pre-wrap;
}
+.notable .content > h3:first-child {
+ margin: 0 0 5px 0;
+}
+
.search-failed {
text-align: center;
margin-top: 20px;
@@ -1282,14 +1247,14 @@ a.test-arrow:hover {
margin-right: auto;
}
-#titles {
+#search-tabs {
display: flex;
flex-direction: row;
gap: 1px;
margin-bottom: 4px;
}
-#titles > button {
+#search-tabs button {
text-align: center;
font-size: 1.125rem;
border: 0;
@@ -1299,12 +1264,12 @@ a.test-arrow:hover {
color: inherit;
}
-#titles > button > div.count {
- display: inline-block;
+#search-tabs .count {
font-size: 1rem;
+ color: var(--search-tab-title-count-color);
}
-#sidebar-toggle {
+#src-sidebar-toggle {
position: sticky;
top: 0;
left: 0;
@@ -1333,7 +1298,7 @@ a.test-arrow:hover {
#source-sidebar div.files > a.selected {
background-color: var(--source-sidebar-background-selected);
}
-#sidebar-toggle > button {
+#src-sidebar-toggle > button {
font-size: inherit;
font-weight: bold;
background: none;
@@ -1346,15 +1311,11 @@ a.test-arrow:hover {
-webkit-appearance: none;
opacity: 1;
}
+
#settings-menu, #help-button {
margin-left: 4px;
display: flex;
}
-
-#settings-menu > a, #help-button > a, #copy-path {
- width: 33px;
-}
-
#settings-menu > a, #help-button > a {
display: flex;
align-items: center;
@@ -1366,6 +1327,7 @@ a.test-arrow:hover {
/* Rare exception to specifying font sizes in rem. Since this is acting
as an icon, it's okay to specify their sizes in pixels. */
font-size: 20px;
+ width: 33px;
}
#settings-menu > a:hover, #settings-menu > a:focus,
@@ -1381,6 +1343,7 @@ a.test-arrow:hover {
padding: 0;
padding-left: 2px;
border: 0;
+ width: 33px;
}
#copy-path > img {
filter: var(--copy-path-img-filter);
@@ -1409,8 +1372,7 @@ kbd {
vertical-align: middle;
border: solid 1px var(--border-color);
border-radius: 3px;
- cursor: default;
- color: var(--kbd--color);
+ color: var(--kbd-color);
background-color: var(--kbd-background);
box-shadow: inset 0 -1px 0 var(--kbd-box-shadow-color);
}
@@ -1423,31 +1385,10 @@ details.dir-entry {
padding-left: 4px;
}
-details.dir-entry > summary::after {
- content: " â–º";
- position: absolute;
- left: -15px;
- top: 0px;
- font-size: 80%;
- padding: 2px 0px;
- /* set width to cover gap between arrow and text */
- width: 25px;
-}
-
-details[open].dir-entry > summary::after {
- content: " â–¼";
-}
-
-details.dir-entry > summary::-webkit-details-marker,
-details.dir-entry > summary::marker {
- display: none;
-}
-
details.dir-entry > summary {
- margin: 0 0 0 13px;
- list-style: none;
+ margin: 0 0 0 -4px;
+ padding: 0 0 0 4px;
cursor: pointer;
- position: relative;
}
details.dir-entry div.folders, details.dir-entry div.files {
@@ -1464,7 +1405,7 @@ details.dir-entry a {
Unfortunately we can't yet specify contain: content or contain: strict
because the [-]/[+] toggles extend past the boundaries of the <details>
https://developer.mozilla.org/en-US/docs/Web/CSS/contain */
-details.rustdoc-toggle {
+details.toggle {
contain: layout;
position: relative;
}
@@ -1472,26 +1413,26 @@ details.rustdoc-toggle {
/* The hideme class is used on summary tags that contain a span with
placeholder text shown only when the toggle is closed. For instance,
"Expand description" or "Show methods". */
-details.rustdoc-toggle > summary.hideme {
+details.toggle > summary.hideme {
cursor: pointer;
font-size: 1rem;
}
-details.rustdoc-toggle > summary {
+details.toggle > summary {
list-style: none;
/* focus outline is shown on `::before` instead of this */
outline: none;
}
-details.rustdoc-toggle > summary::-webkit-details-marker,
-details.rustdoc-toggle > summary::marker {
+details.toggle > summary::-webkit-details-marker,
+details.toggle > summary::marker {
display: none;
}
-details.rustdoc-toggle > summary.hideme > span {
+details.toggle > summary.hideme > span {
margin-left: 9px;
}
-details.rustdoc-toggle > summary::before {
+details.toggle > summary::before {
background: url("toggle-plus-1092eb4930d581b0.svg") no-repeat top left;
content: "";
cursor: pointer;
@@ -1503,14 +1444,14 @@ details.rustdoc-toggle > summary::before {
filter: var(--toggle-filter);
}
-details.rustdoc-toggle > summary.hideme > span,
+details.toggle > summary.hideme > span,
.more-examples-toggle summary, .more-examples-toggle .hide-more {
color: var(--toggles-color);
}
/* Screen readers see the text version at the end the line.
Visual readers see the icon at the start of the line, but small and transparent. */
-details.rustdoc-toggle > summary::after {
+details.toggle > summary::after {
content: "Expand";
overflow: hidden;
width: 0;
@@ -1518,17 +1459,17 @@ details.rustdoc-toggle > summary::after {
position: absolute;
}
-details.rustdoc-toggle > summary.hideme::after {
+details.toggle > summary.hideme::after {
/* "hideme" toggles already have a description when they're contracted */
content: "";
}
-details.rustdoc-toggle > summary:focus::before,
-details.rustdoc-toggle > summary:hover::before {
+details.toggle > summary:focus::before,
+details.toggle > summary:hover::before {
opacity: 1;
}
-details.rustdoc-toggle > summary:focus-visible::before {
+details.toggle > summary:focus-visible::before {
/* The SVG is black, and gets turned white using a filter in the dark themes.
Do the same with the outline.
The dotted 1px style is copied from Firefox's focus ring style.
@@ -1541,17 +1482,17 @@ details.non-exhaustive {
margin-bottom: 8px;
}
-details.rustdoc-toggle > summary.hideme::before {
+details.toggle > summary.hideme::before {
position: relative;
}
-details.rustdoc-toggle > summary:not(.hideme)::before {
+details.toggle > summary:not(.hideme)::before {
position: absolute;
left: -24px;
top: 4px;
}
-.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before {
+.impl-items > details.toggle > summary:not(.hideme)::before {
position: absolute;
left: -24px;
}
@@ -1561,19 +1502,19 @@ details.rustdoc-toggle > summary:not(.hideme)::before {
affect the layout of the items to its right. To do that, we use
absolute positioning. Note that we also set position: relative
on the parent <details> to make this work properly. */
-details.rustdoc-toggle[open] > summary.hideme {
+details.toggle[open] > summary.hideme {
position: absolute;
}
-details.rustdoc-toggle[open] > summary.hideme > span {
+details.toggle[open] > summary.hideme > span {
display: none;
}
-details.rustdoc-toggle[open] > summary::before {
+details.toggle[open] > summary::before {
background: url("toggle-minus-31bbd6e4c77f5c96.svg") no-repeat top left;
}
-details.rustdoc-toggle[open] > summary::after {
+details.toggle[open] > summary::after {
content: "Collapse";
}
@@ -1633,7 +1574,7 @@ in storage.js
/* Hide the logo and item name from the sidebar. Those are displayed
in the mobile-topbar instead. */
- .sidebar .sidebar-logo,
+ .sidebar .logo-container,
.sidebar .location {
display: none;
}
@@ -1662,14 +1603,10 @@ in storage.js
.sidebar.shown,
.source-sidebar-expanded .source .sidebar,
- .sidebar:focus-within {
+ .rustdoc:not(.source) .sidebar:focus-within {
left: 0;
}
- .rustdoc.source > .sidebar {
- width: 0;
- }
-
.mobile-topbar h2 {
padding-bottom: 0;
margin: auto 0.5em auto auto;
@@ -1719,30 +1656,25 @@ in storage.js
margin-top: 1em;
}
- .content {
- margin-left: 0px;
- }
-
.anchor {
display: none !important;
}
- #titles > button > div.count {
+ #search-tabs .count {
display: block;
}
- #main-content > details.rustdoc-toggle > summary::before,
- #main-content > div > details.rustdoc-toggle > summary::before {
+ #main-content > details.toggle > summary::before,
+ #main-content > div > details.toggle > summary::before {
left: -11px;
}
- #sidebar-toggle {
+ #src-sidebar-toggle {
position: fixed;
left: 1px;
top: 100px;
width: 30px;
font-size: 1.5rem;
- text-align: center;
padding: 0;
z-index: 10;
border-top-right-radius: 3px;
@@ -1751,7 +1683,7 @@ in storage.js
border-left: 0;
}
- .source-sidebar-expanded #sidebar-toggle {
+ .source-sidebar-expanded #src-sidebar-toggle {
left: unset;
top: unset;
width: unset;
@@ -1787,12 +1719,12 @@ in storage.js
}
/* Position of the "[-]" element. */
- details.rustdoc-toggle:not(.top-doc) > summary {
+ details.toggle:not(.top-doc) > summary {
margin-left: 10px;
}
- .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
- #main-content > details.rustdoc-toggle:not(.top-doc) > summary::before,
- #main-content > div > details.rustdoc-toggle > summary::before {
+ .impl-items > details.toggle > summary:not(.hideme)::before,
+ #main-content > details.toggle:not(.top-doc) > summary::before,
+ #main-content > div > details.toggle > summary::before {
left: -11px;
}
@@ -1825,8 +1757,8 @@ in storage.js
@media print {
nav.sidebar, nav.sub, .out-of-band, a.srclink, #copy-path,
- details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before,
- details.rustdoc-toggle.top-doc > summary {
+ details.toggle[open] > summary::before, details.toggle > summary::before,
+ details.toggle.top-doc > summary {
display: none;
}
@@ -1861,13 +1793,6 @@ in storage.js
height: 35px;
width: 35px;
}
-
- #sidebar-toggle {
- top: 10px;
- }
- .source-sidebar-expanded #sidebar-toggle {
- top: unset;
- }
}
.variant,
@@ -1875,23 +1800,24 @@ in storage.js
.impl,
#implementors-list > .docblock,
.impl-items > section,
-.impl-items > .rustdoc-toggle > summary,
+.impl-items > .toggle > summary,
.methods > section,
-.methods > .rustdoc-toggle > summary
+.methods > .toggle > summary
{
margin-bottom: 0.75em;
}
.variants > .docblock,
-.impl-items > .rustdoc-toggle[open]:not(:last-child),
-.methods > .rustdoc-toggle[open]:not(:last-child),
+.implementors-toggle > .docblock,
+.impl-items > .toggle[open]:not(:last-child),
+.methods > .toggle[open]:not(:last-child),
.implementors-toggle[open]:not(:last-child) {
margin-bottom: 2em;
}
-#trait-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
-#synthetic-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
-#blanket-implementations-list .impl-items > .rustdoc-toggle:not(:last-child) {
+#trait-implementations-list .impl-items > .toggle:not(:last-child),
+#synthetic-implementations-list .impl-items > .toggle:not(:last-child),
+#blanket-implementations-list .impl-items > .toggle:not(:last-child) {
margin-bottom: 1em;
}
@@ -1904,9 +1830,13 @@ in storage.js
font-size: 12px;
position: relative;
bottom: 1px;
- border-width: 1px;
- border-style: solid;
+ border: 1px solid var(--scrape-example-help-border-color);
border-radius: 50px;
+ color: var(--scrape-example-help-color);
+}
+.scraped-example-list .scrape-help:hover {
+ border-color: var(--scrape-example-help-hover-border-color);
+ color: var(--scrape-example-help-hover-color);
}
.scraped-example {
@@ -1982,21 +1912,8 @@ in storage.js
bottom: 0;
}
-.scraped-example .code-wrapper .src-line-numbers {
- margin: 0;
- padding: 14px 0;
-}
-
-.scraped-example .code-wrapper .src-line-numbers a,
-.scraped-example .code-wrapper .src-line-numbers span {
- padding: 0 14px;
-}
-
.scraped-example .code-wrapper .example-wrap {
- display: grid;
- grid-template-columns: max-content auto;
width: 100%;
- overflow-x: auto;
overflow-y: hidden;
margin-bottom: 0;
}
@@ -2005,12 +1922,12 @@ in storage.js
overflow-x: hidden;
}
-.scraped-example .code-wrapper .example-wrap pre.rust {
- overflow-x: inherit;
- width: inherit;
- overflow-y: hidden;
+.scraped-example .example-wrap .rust span.highlight {
+ background: var(--scrape-example-code-line-highlight);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: var(--scrape-example-code-line-highlight-focus);
}
-
.more-examples-toggle {
max-width: calc(100% + 25px);
@@ -2020,25 +1937,19 @@ in storage.js
.more-examples-toggle .hide-more {
margin-left: 25px;
- margin-bottom: 5px;
cursor: pointer;
}
.more-scraped-examples {
- margin-left: 5px;
- display: flex;
- flex-direction: row;
-}
-
-.more-scraped-examples-inner {
- /* 20px is width of toggle-line + toggle-line-inner */
- width: calc(100% - 20px);
+ margin-left: 25px;
+ position: relative;
}
.toggle-line {
- align-self: stretch;
- margin-right: 10px;
- margin-top: 5px;
+ position: absolute;
+ top: 5px;
+ bottom: 0;
+ right: calc(100% + 10px);
padding: 0 4px;
cursor: pointer;
}
@@ -2046,18 +1957,19 @@ in storage.js
.toggle-line-inner {
min-width: 2px;
height: 100%;
+ background: var(--scrape-example-toggle-line-background);
}
-.more-scraped-examples .scraped-example {
- margin-bottom: 20px;
+.toggle-line:hover .toggle-line-inner {
+ background: var(--scrape-example-toggle-line-hover-background);
}
-.more-scraped-examples .scraped-example:last-child {
- margin-bottom: 0;
+.more-scraped-examples .scraped-example, .example-links {
+ margin-top: 20px;
}
-.example-links a {
- margin-top: 20px;
+.more-scraped-examples .scraped-example:first-child {
+ margin-top: 5px;
}
.example-links ul {
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
index 1f6fb961e..4e9803fe2 100644
--- a/src/librustdoc/html/static/css/settings.css
+++ b/src/librustdoc/html/static/css/settings.css
@@ -1,15 +1,10 @@
.setting-line {
- margin: 0.6em 0 0.6em 0.3em;
+ margin: 1.2em 0.6em;
position: relative;
}
-.setting-line .choices {
- display: flex;
- flex-wrap: wrap;
-}
-
.setting-line .radio-line input,
-.setting-line .toggle input {
+.setting-line .settings-toggle input {
margin-right: 0.3em;
height: 1.2rem;
width: 1.2rem;
@@ -22,27 +17,23 @@
.setting-line .radio-line input {
border-radius: 50%;
}
-.setting-line .toggle input:checked {
+.setting-line .settings-toggle input:checked {
content: url('data:image/svg+xml,<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>');
}
.setting-line .radio-line input + span,
-.setting-line .toggle span {
+.setting-line .settings-toggle span {
padding-bottom: 1px;
}
-.radio-line .setting-name {
- width: 100%;
-}
-
.radio-line .choice {
margin-top: 0.1em;
margin-bottom: 0.1em;
min-width: 3.8em;
padding: 0.3em;
- display: flex;
+ display: inline-flex;
align-items: center;
cursor: pointer;
}
@@ -50,7 +41,7 @@
margin-left: 0.5em;
}
-.toggle {
+.settings-toggle {
position: relative;
width: 100%;
margin-right: 20px;
@@ -59,25 +50,15 @@
cursor: pointer;
}
-.setting-line > .sub-settings {
- padding-left: 42px;
- width: 100%;
- display: block;
-}
-
-#settings .setting-line {
- margin: 1.2em 0.6em;
-}
-
.setting-line .radio-line input:checked {
box-shadow: inset 0 0 0 3px var(--main-background-color);
background-color: var(--settings-input-color);
}
-.setting-line .toggle input:checked {
+.setting-line .settings-toggle input:checked {
background-color: var(--settings-input-color);
}
.setting-line .radio-line input:focus,
-.setting-line .toggle input:focus {
+.setting-line .settings-toggle input:focus {
box-shadow: 0 0 1px 1px var(--settings-input-color);
}
/* In here we combine both `:focus` and `:checked` properties. */
@@ -86,6 +67,6 @@
0 0 2px 2px var(--settings-input-color);
}
.setting-line .radio-line input:hover,
-.setting-line .toggle input:hover {
+.setting-line .settings-toggle input:hover {
border-color: var(--settings-input-color) !important;
}
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 0436fe013..979e7e0f9 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -45,6 +45,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--search-color: #fff;
--search-results-alias-color: #c5c5c5;
--search-results-grey-color: #999;
+ --search-tab-title-count-color: #888;
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ff7733;
@@ -61,7 +62,6 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--code-highlight-question-mark-color: #ff9011;
--code-highlight-comment-color: #788797;
--code-highlight-doc-comment-color: #a1ac88;
- --example-line-numbers-border-color: none;
--src-line-numbers-span-color: #5c6773;
--src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
--test-arrow-color: #788797;
@@ -88,6 +88,15 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--source-sidebar-background-selected: #14191f;
--source-sidebar-background-hover: #14191f;
--table-alt-row-background-color: #191f26;
+ --codeblock-link-background: #333;
+ --scrape-example-toggle-line-background: #999;
+ --scrape-example-toggle-line-hover-background: #c5c5c5;
+ --scrape-example-code-line-highlight: rgb(91, 59, 1);
+ --scrape-example-code-line-highlight-focus: rgb(124, 75, 15);
+ --scrape-example-help-border-color: #aaa;
+ --scrape-example-help-color: #eee;
+ --scrape-example-help-hover-border-color: #fff;
+ --scrape-example-help-hover-color: #fff;
}
h1, h2, h3, h4 {
@@ -130,7 +139,7 @@ pre, .rustdoc.source .example-wrap {
.src-line-numbers .line-highlighted {
color: #708090;
- padding-right: 4px;
+ padding-right: 7px;
border-right: 1px solid #ffb44c;
}
@@ -150,55 +159,37 @@ pre, .rustdoc.source .example-wrap {
color: #c5c5c5;
}
-.content .item-info::before { color: #ccc; }
-
.sidebar h2 a,
.sidebar h3 a {
color: white;
}
-body.source .example-wrap pre.rust a {
- background: #333;
-}
-
-.module-item .stab,
-.import-item .stab {
- color: #000;
-}
.result-name .primitive > i, .result-name .keyword > i {
color: #788797;
}
-#titles > button.selected {
+#search-tabs > button.selected {
background-color: #141920 !important;
border-bottom: 1px solid #ffb44c !important;
border-top: none;
}
-#titles > button:not(.selected) {
+#search-tabs > button:not(.selected) {
background-color: transparent !important;
border: none;
}
-#titles > button:hover {
+#search-tabs > button:hover {
border-bottom: 1px solid rgba(242, 151, 24, 0.3);
}
-#titles > button > div.count {
- color: #888;
-}
-
/* rules that this theme does not need to set, here to satisfy the rule checker */
/* note that a lot of these are partially set in some way (meaning they are set
individually rather than as a group) */
/* FIXME: these rules should be at the bottom of the file but currently must be
above the `@media (max-width: 700px)` rules due to a bug in the css checker */
/* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */
-pre.rust .lifetime {}
-pre.rust .kw {}
-#titles > button:hover, #titles > button.selected {}
-pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, pre.rust .attribute {}
-pre.rust .kw-2, pre.rust .prelude-ty {}
+#search-tabs > button:hover, #search-tabs > button.selected {}
#settings-menu > a img {
filter: invert(100);
@@ -213,29 +204,9 @@ pre.rust .kw-2, pre.rust .prelude-ty {}
color: #ffb44c;
}
-.scraped-example-list .scrape-help {
- border-color: #aaa;
- color: #eee;
-}
-.scraped-example-list .scrape-help:hover {
- border-color: white;
- color: white;
-}
-.scraped-example .example-wrap .rust span.highlight {
- background: rgb(91, 59, 1);
-}
-.scraped-example .example-wrap .rust span.highlight.focus {
- background: rgb(124, 75, 15);
-}
-.scraped-example:not(.expanded) .code-wrapper:before {
+.scraped-example:not(.expanded) .code-wrapper::before {
background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
}
-.scraped-example:not(.expanded) .code-wrapper:after {
+.scraped-example:not(.expanded) .code-wrapper::after {
background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
}
-.toggle-line-inner {
- background: #999;
-}
-.toggle-line:hover .toggle-line-inner {
- background: #c5c5c5;
-}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index d945e956c..fb15863b0 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -40,6 +40,7 @@
--search-color: #111;
--search-results-alias-color: #fff;
--search-results-grey-color: #ccc;
+ --search-tab-title-count-color: #888;
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ab8ac1;
@@ -56,7 +57,6 @@
--code-highlight-question-mark-color: #ff9011;
--code-highlight-comment-color: #8d8d8b;
--code-highlight-doc-comment-color: #8ca375;
- --example-line-numbers-border-color: #4a4949;
--src-line-numbers-span-color: #3b91e2;
--src-line-number-highlighted-background-color: #0a042f;
--test-arrow-color: #dedede;
@@ -83,51 +83,30 @@
--source-sidebar-background-selected: #333;
--source-sidebar-background-hover: #444;
--table-alt-row-background-color: #2A2A2A;
+ --codeblock-link-background: #333;
+ --scrape-example-toggle-line-background: #999;
+ --scrape-example-toggle-line-hover-background: #c5c5c5;
+ --scrape-example-code-line-highlight: rgb(91, 59, 1);
+ --scrape-example-code-line-highlight-focus: rgb(124, 75, 15);
+ --scrape-example-help-border-color: #aaa;
+ --scrape-example-help-color: #eee;
+ --scrape-example-help-hover-border-color: #fff;
+ --scrape-example-help-hover-color: #fff;
}
-.content .item-info::before { color: #ccc; }
-
-body.source .example-wrap pre.rust a {
- background: #333;
-}
-
-#titles > button:not(.selected) {
+#search-tabs > button:not(.selected) {
background-color: #252525;
border-top-color: #252525;
}
-#titles > button:hover, #titles > button.selected {
+#search-tabs > button:hover, #search-tabs > button.selected {
border-top-color: #0089ff;
background-color: #353535;
}
-#titles > button > div.count {
- color: #888;
-}
-
-.scraped-example-list .scrape-help {
- border-color: #aaa;
- color: #eee;
-}
-.scraped-example-list .scrape-help:hover {
- border-color: white;
- color: white;
-}
-.scraped-example .example-wrap .rust span.highlight {
- background: rgb(91, 59, 1);
-}
-.scraped-example .example-wrap .rust span.highlight.focus {
- background: rgb(124, 75, 15);
-}
-.scraped-example:not(.expanded) .code-wrapper:before {
+.scraped-example:not(.expanded) .code-wrapper::before {
background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
}
-.scraped-example:not(.expanded) .code-wrapper:after {
+.scraped-example:not(.expanded) .code-wrapper::after {
background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
}
-.toggle-line-inner {
- background: #999;
-}
-.toggle-line:hover .toggle-line-inner {
- background: #c5c5c5;
-}
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 58955a793..053fa78d1 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -40,6 +40,7 @@
--search-color: #000;
--search-results-alias-color: #000;
--search-results-grey-color: #999;
+ --search-tab-title-count-color: #888;
--stab-background-color: #fff5d6;
--stab-code-color: #000;
--code-highlight-kw-color: #8959a8;
@@ -56,7 +57,6 @@
--code-highlight-question-mark-color: #ff9011;
--code-highlight-comment-color: #8e908c;
--code-highlight-doc-comment-color: #4d4d4c;
- --example-line-numbers-border-color: #c7c7c7;
--src-line-numbers-span-color: #c67e2d;
--src-line-number-highlighted-background-color: #fdffd3;
--test-arrow-color: #f5f5f5;
@@ -80,51 +80,30 @@
--source-sidebar-background-selected: #fff;
--source-sidebar-background-hover: #e0e0e0;
--table-alt-row-background-color: #F5F5F5;
+ --codeblock-link-background: #eee;
+ --scrape-example-toggle-line-background: #ccc;
+ --scrape-example-toggle-line-hover-background: #999;
+ --scrape-example-code-line-highlight: #fcffd6;
+ --scrape-example-code-line-highlight-focus: #f6fdb0;
+ --scrape-example-help-border-color: #555;
+ --scrape-example-help-color: #333;
+ --scrape-example-help-hover-border-color: #000;
+ --scrape-example-help-hover-color: #000;
}
-.content .item-info::before { color: #ccc; }
-
-body.source .example-wrap pre.rust a {
- background: #eee;
-}
-
-#titles > button:not(.selected) {
+#search-tabs > button:not(.selected) {
background-color: #e6e6e6;
border-top-color: #e6e6e6;
}
-#titles > button:hover, #titles > button.selected {
+#search-tabs > button:hover, #search-tabs > button.selected {
background-color: #ffffff;
border-top-color: #0089ff;
}
-#titles > button > div.count {
- color: #888;
-}
-
-.scraped-example-list .scrape-help {
- border-color: #555;
- color: #333;
-}
-.scraped-example-list .scrape-help:hover {
- border-color: black;
- color: black;
-}
-.scraped-example .example-wrap .rust span.highlight {
- background: #fcffd6;
-}
-.scraped-example .example-wrap .rust span.highlight.focus {
- background: #f6fdb0;
-}
-.scraped-example:not(.expanded) .code-wrapper:before {
+.scraped-example:not(.expanded) .code-wrapper::before {
background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
}
-.scraped-example:not(.expanded) .code-wrapper:after {
+.scraped-example:not(.expanded) .code-wrapper::after {
background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
}
-.toggle-line-inner {
- background: #ccc;
-}
-.toggle-line:hover .toggle-line-inner {
- background: #999;
-}
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 152116089..604ab147f 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -184,7 +184,6 @@ function browserSupportsHistoryApi() {
function loadCss(cssUrl) {
const link = document.createElement("link");
link.href = cssUrl;
- link.type = "text/css";
link.rel = "stylesheet";
document.getElementsByTagName("head")[0].appendChild(link);
}
@@ -391,7 +390,8 @@ function loadCss(cssUrl) {
}
if (document.activeElement.tagName === "INPUT" &&
- document.activeElement.type !== "checkbox") {
+ document.activeElement.type !== "checkbox" &&
+ document.activeElement.type !== "radio") {
switch (getVirtualKey(ev)) {
case "Escape":
handleEscape(ev);
@@ -527,7 +527,7 @@ function loadCss(cssUrl) {
}
let currentNbImpls = implementors.getElementsByClassName("impl").length;
- const traitName = document.querySelector("h1.fqn > .trait").textContent;
+ const traitName = document.querySelector(".main-heading h1 > .trait").textContent;
const baseIdName = "impl-" + traitName + "-";
const libs = Object.getOwnPropertyNames(imp);
// We don't want to include impls from this JS file, when the HTML already has them.
@@ -564,7 +564,7 @@ function loadCss(cssUrl) {
onEachLazy(code.getElementsByTagName("a"), elem => {
const href = elem.getAttribute("href");
- if (href && href.indexOf("http") !== 0) {
+ if (href && !/^(?:[a-z+]+:)?\/\//.test(href)) {
elem.setAttribute("href", window.rootPath + href);
}
});
@@ -621,7 +621,7 @@ function loadCss(cssUrl) {
function expandAllDocs() {
const innerToggle = document.getElementById(toggleAllDocsId);
removeClass(innerToggle, "will-expand");
- onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+ onEachLazy(document.getElementsByClassName("toggle"), e => {
if (!hasClass(e, "type-contents-toggle") && !hasClass(e, "more-examples-toggle")) {
e.open = true;
}
@@ -633,7 +633,7 @@ function loadCss(cssUrl) {
function collapseAllDocs() {
const innerToggle = document.getElementById(toggleAllDocsId);
addClass(innerToggle, "will-expand");
- onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+ onEachLazy(document.getElementsByClassName("toggle"), e => {
if (e.parentNode.id !== "implementations-list" ||
(!hasClass(e, "implementors-toggle") &&
!hasClass(e, "type-contents-toggle"))
@@ -681,7 +681,7 @@ function loadCss(cssUrl) {
setImplementorsTogglesOpen("blanket-implementations-list", false);
}
- onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+ onEachLazy(document.getElementsByClassName("toggle"), e => {
if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) {
e.open = true;
}
@@ -804,29 +804,22 @@ function loadCss(cssUrl) {
}
});
- function handleClick(id, f) {
- const elem = document.getElementById(id);
- if (elem) {
- elem.addEventListener("click", f);
- }
+ const mainElem = document.getElementById(MAIN_ID);
+ if (mainElem) {
+ mainElem.addEventListener("click", hideSidebar);
}
- handleClick(MAIN_ID, () => {
- hideSidebar();
- });
- onEachLazy(document.getElementsByTagName("a"), el => {
+ onEachLazy(document.querySelectorAll("a[href^='#']"), el => {
// For clicks on internal links (<A> tags with a hash property), we expand the section we're
// jumping to *before* jumping there. We can't do this in onHashChange, because it changes
// the height of the document so we wind up scrolled to the wrong place.
- if (el.hash) {
- el.addEventListener("click", () => {
- expandSection(el.hash.slice(1));
- hideSidebar();
- });
- }
+ el.addEventListener("click", () => {
+ expandSection(el.hash.slice(1));
+ hideSidebar();
+ });
});
- onEachLazy(document.querySelectorAll(".rustdoc-toggle > summary:not(.hideme)"), el => {
+ onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => {
el.addEventListener("click", e => {
if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") {
e.preventDefault();
@@ -850,7 +843,7 @@ function loadCss(cssUrl) {
window.hideAllModals(false);
const ty = e.getAttribute("data-ty");
const wrapper = document.createElement("div");
- wrapper.innerHTML = "<div class=\"docblock\">" + window.NOTABLE_TRAITS[ty] + "</div>";
+ wrapper.innerHTML = "<div class=\"content\">" + window.NOTABLE_TRAITS[ty] + "</div>";
wrapper.className = "notable popover";
const focusCatcher = document.createElement("div");
focusCatcher.setAttribute("tabindex", "0");
@@ -948,7 +941,7 @@ function loadCss(cssUrl) {
return;
}
if (!this.NOTABLE_FORCE_VISIBLE &&
- !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) {
+ !elemIsInParent(ev.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) {
hideNotable(true);
}
};
@@ -1043,9 +1036,6 @@ function loadCss(cssUrl) {
help_button.appendChild(container);
container.onblur = helpBlurHandler;
- container.onclick = event => {
- event.preventDefault();
- };
help_button.onblur = helpBlurHandler;
help_button.children[0].onblur = helpBlurHandler;
}
@@ -1093,6 +1083,9 @@ function loadCss(cssUrl) {
* Show the help popup menu.
*/
function showHelp() {
+ // Prevent `blur` events from being dispatched as a result of closing
+ // other modals.
+ getHelpButton().querySelector("a").focus();
const menu = getHelpMenu(true);
if (menu.style.display === "none") {
window.hideAllModals();
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 23ae4e970..88592fa0c 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -49,7 +49,7 @@ function printTab(nb) {
let iter = 0;
let foundCurrentTab = false;
let foundCurrentResultSet = false;
- onEachLazy(document.getElementById("titles").childNodes, elem => {
+ onEachLazy(document.getElementById("search-tabs").childNodes, elem => {
if (nb === iter) {
addClass(elem, "selected");
foundCurrentTab = true;
@@ -781,7 +781,29 @@ function initSearch(rawSearchIndex) {
return a - b;
}
- // Sort by non levenshtein results and then levenshtein results by the distance
+ // sort by index of keyword in item name (no literal occurrence goes later)
+ a = (aaa.index < 0);
+ b = (bbb.index < 0);
+ if (a !== b) {
+ return a - b;
+ }
+
+ // Sort by distance in the path part, if specified
+ // (less changes required to match means higher rankings)
+ a = aaa.path_lev;
+ b = bbb.path_lev;
+ if (a !== b) {
+ return a - b;
+ }
+
+ // (later literal occurrence, if any, goes later)
+ a = aaa.index;
+ b = bbb.index;
+ if (a !== b) {
+ return a - b;
+ }
+
+ // Sort by distance in the name part, the last part of the path
// (less changes required to match means higher rankings)
a = (aaa.lev);
b = (bbb.lev);
@@ -810,19 +832,6 @@ function initSearch(rawSearchIndex) {
return (a > b ? +1 : -1);
}
- // sort by index of keyword in item name (no literal occurrence goes later)
- a = (aaa.index < 0);
- b = (bbb.index < 0);
- if (a !== b) {
- return a - b;
- }
- // (later literal occurrence, if any, goes later)
- a = aaa.index;
- b = bbb.index;
- if (a !== b) {
- return a - b;
- }
-
// special precedence for primitive and keyword pages
if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
(aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) {
@@ -1230,15 +1239,19 @@ function initSearch(rawSearchIndex) {
* * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
* * `index` is an `integer`` used to sort by the position of the word in the item's name.
* * `lev` is the main metric used to sort the search results.
+ * * `path_lev` is zero if a single-component search query is used, otherwise it's the
+ * distance computed for everything other than the last path component.
*
* @param {Results} results
* @param {string} fullId
* @param {integer} id
* @param {integer} index
* @param {integer} lev
+ * @param {integer} path_lev
*/
- function addIntoResults(results, fullId, id, index, lev) {
- if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
+ function addIntoResults(results, fullId, id, index, lev, path_lev) {
+ const inBounds = lev <= MAX_LEV_DISTANCE || index !== -1;
+ if (lev === 0 || (!parsedQuery.literalSearch && inBounds)) {
if (results[fullId] !== undefined) {
const result = results[fullId];
if (result.dontValidate || result.lev <= lev) {
@@ -1250,6 +1263,7 @@ function initSearch(rawSearchIndex) {
index: index,
dontValidate: parsedQuery.literalSearch,
lev: lev,
+ path_lev: path_lev,
};
}
}
@@ -1280,68 +1294,68 @@ function initSearch(rawSearchIndex) {
if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
return;
}
- let lev, lev_add = 0, index = -1;
+ let lev, index = -1, path_lev = 0;
const fullId = row.id;
+ const searchWord = searchWords[pos];
const in_args = findArg(row, elem, parsedQuery.typeFilter);
const returned = checkReturned(row, elem, parsedQuery.typeFilter);
- addIntoResults(results_in_args, fullId, pos, index, in_args);
- addIntoResults(results_returned, fullId, pos, index, returned);
+ // path_lev is 0 because no parent path information is currently stored
+ // in the search index
+ addIntoResults(results_in_args, fullId, pos, -1, in_args, 0);
+ addIntoResults(results_returned, fullId, pos, -1, returned, 0);
if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
return;
}
- const searchWord = searchWords[pos];
- if (parsedQuery.literalSearch) {
- if (searchWord === elem.name) {
- addIntoResults(results_others, fullId, pos, -1, 0);
- }
- return;
+ const row_index = row.normalizedName.indexOf(elem.pathLast);
+ const word_index = searchWord.indexOf(elem.pathLast);
+
+ // lower indexes are "better" matches
+ // rank based on the "best" match
+ if (row_index === -1) {
+ index = word_index;
+ } else if (word_index === -1) {
+ index = row_index;
+ } else if (word_index < row_index) {
+ index = word_index;
+ } else {
+ index = row_index;
}
// No need to check anything else if it's a "pure" generics search.
if (elem.name.length === 0) {
if (row.type !== null) {
lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
- addIntoResults(results_others, fullId, pos, index, lev);
+ // path_lev is 0 because we know it's empty
+ addIntoResults(results_others, fullId, pos, index, lev, 0);
}
return;
}
if (elem.fullPath.length > 1) {
- lev = checkPath(elem.pathWithoutLast, row);
- if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
+ path_lev = checkPath(elem.pathWithoutLast, row);
+ if (path_lev > MAX_LEV_DISTANCE) {
return;
- } else if (lev > 0) {
- lev_add = lev / 10;
}
}
- if (searchWord.indexOf(elem.pathLast) > -1 ||
- row.normalizedName.indexOf(elem.pathLast) > -1
- ) {
- index = row.normalizedName.indexOf(elem.pathLast);
- }
- lev = levenshtein(searchWord, elem.pathLast);
- if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) {
- if (elem.pathLast.length < 6) {
- lev = 1;
- } else {
- lev = 0;
+ if (parsedQuery.literalSearch) {
+ if (searchWord === elem.name) {
+ addIntoResults(results_others, fullId, pos, index, 0, path_lev);
}
- }
- lev += lev_add;
- if (lev > MAX_LEV_DISTANCE) {
return;
- } else if (index !== -1 && elem.fullPath.length < 2) {
- lev -= 1;
}
- if (lev < 0) {
- lev = 0;
+
+ lev = levenshtein(searchWord, elem.pathLast);
+
+ if (index === -1 && lev + path_lev > MAX_LEV_DISTANCE) {
+ return;
}
- addIntoResults(results_others, fullId, pos, index, lev);
+
+ addIntoResults(results_others, fullId, pos, index, lev, path_lev);
}
/**
@@ -1386,7 +1400,7 @@ function initSearch(rawSearchIndex) {
return;
}
const lev = Math.round(totalLev / nbLev);
- addIntoResults(results, row.id, pos, 0, lev);
+ addIntoResults(results, row.id, pos, 0, lev, 0);
}
function innerRunQuery() {
@@ -1490,7 +1504,7 @@ function initSearch(rawSearchIndex) {
function focusSearchResult() {
const target = searchState.focusedByTab[searchState.currentTab] ||
document.querySelectorAll(".search-results.active a").item(0) ||
- document.querySelectorAll("#titles > button").item(searchState.currentTab);
+ document.querySelectorAll("#search-tabs button").item(searchState.currentTab);
searchState.focusedByTab[searchState.currentTab] = null;
if (target) {
target.focus();
@@ -1645,9 +1659,9 @@ function initSearch(rawSearchIndex) {
function makeTabHeader(tabNb, text, nbElems) {
if (searchState.currentTab === tabNb) {
return "<button class=\"selected\">" + text +
- " <div class=\"count\">(" + nbElems + ")</div></button>";
+ " <span class=\"count\">(" + nbElems + ")</span></button>";
}
- return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
+ return "<button>" + text + " <span class=\"count\">(" + nbElems + ")</span></button>";
}
/**
@@ -1712,12 +1726,12 @@ function initSearch(rawSearchIndex) {
let output = `<h1 class="search-results-title">Results${crates}</h1>`;
if (results.query.error !== null) {
output += `<h3>Query parser error: "${results.query.error}".</h3>`;
- output += "<div id=\"titles\">" +
+ output += "<div id=\"search-tabs\">" +
makeTabHeader(0, "In Names", ret_others[1]) +
"</div>";
currentTab = 0;
} else if (results.query.foundElems <= 1 && results.query.returned.length === 0) {
- output += "<div id=\"titles\">" +
+ output += "<div id=\"search-tabs\">" +
makeTabHeader(0, "In Names", ret_others[1]) +
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
makeTabHeader(2, "In Return Types", ret_returned[1]) +
@@ -1727,7 +1741,7 @@ function initSearch(rawSearchIndex) {
results.query.elems.length === 0 ? "In Function Return Types" :
results.query.returned.length === 0 ? "In Function Parameters" :
"In Function Signatures";
- output += "<div id=\"titles\">" +
+ output += "<div id=\"search-tabs\">" +
makeTabHeader(0, signatureTabTitle, ret_others[1]) +
"</div>";
currentTab = 0;
@@ -1747,7 +1761,7 @@ function initSearch(rawSearchIndex) {
search.appendChild(resultsElem);
// Reset focused elements.
searchState.showResults(search);
- const elems = document.getElementById("titles").childNodes;
+ const elems = document.getElementById("search-tabs").childNodes;
searchState.focusedByTab = [];
let i = 0;
for (const elem of elems) {
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 589bfc793..84df1b7d3 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -135,7 +135,7 @@
// This is a select setting.
output += `\
<div class="radio-line" id="${js_data_name}">
- <span class="setting-name">${setting_name}</span>
+ <div class="setting-name">${setting_name}</div>
<div class="choices">`;
onEach(setting["options"], option => {
const checked = option === setting["default"] ? " checked" : "";
@@ -150,10 +150,10 @@
});
output += "</div></div>";
} else {
- // This is a toggle.
+ // This is a checkbox toggle.
const checked = setting["default"] === true ? " checked" : "";
output += `\
-<label class="toggle">\
+<label class="settings-toggle">\
<input type="checkbox" id="${js_data_name}"${checked}>\
<span class="label">${setting_name}</span>\
</label>`;
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index 5db768c1c..0e1c864e6 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -83,7 +83,7 @@ function toggleSidebar() {
function createSidebarToggle() {
const sidebarToggle = document.createElement("div");
- sidebarToggle.id = "sidebar-toggle";
+ sidebarToggle.id = "src-sidebar-toggle";
const inner = document.createElement("button");
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index aa3bf827d..fddda293b 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -72,34 +72,30 @@
{%- if page.css_class != "source" -%}
<nav class="mobile-topbar"> {#- -#}
<button class="sidebar-menu-toggle">&#9776;</button> {#- -#}
- <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() -%}
- <img src="{{layout.logo}}" alt="logo"> {#- -#}
- {%- else -%}
- <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
- {%- endif -%}
- </div> {#- -#}
+ <a class="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"> {#- -#}
+ {%- else -%}
+ <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
+ {%- endif -%}
</a> {#- -#}
<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() %}
- <img src="{{layout.logo}}" alt="logo"> {#- -#}
- {%- else -%}
- <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
- {%- endif -%}
- </div> {#- -#}
+ <a class="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"> {#- -#}
+ {%- else -%}
+ <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
+ {%- endif -%}
</a> {#- -#}
{%- endif -%}
{{- sidebar|safe -}}
</nav> {#- -#}
<main> {#- -#}
- <div class="width-limiter"> {#- -#}
+ {%- if page.css_class != "source" -%}<div class="width-limiter">{%- endif -%}
<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"> {#- -#}
@@ -132,7 +128,7 @@
</form> {#- -#}
</nav> {#- -#}
<section id="main-content" class="content">{{- content|safe -}}</section> {#- -#}
- </div> {#- -#}
+ {%- if page.css_class != "source" -%}</div>{%- endif -%}
</main> {#- -#}
{{- layout.external_html.after_content|safe -}}
<div id="rustdoc-vars" {# -#}
diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
index 611d124d4..ee2880bf6 100644
--- a/src/librustdoc/html/templates/print_item.html
+++ b/src/librustdoc/html/templates/print_item.html
@@ -1,5 +1,5 @@
<div class="main-heading"> {#- -#}
- <h1 class="fqn"> {#- -#}
+ <h1> {#- -#}
{{-typ-}}
{#- The breadcrumbs of the item path, like std::string -#}
{%- for component in path_components -%}