summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/html
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html')
-rw-r--r--src/librustdoc/html/format.rs98
-rw-r--r--src/librustdoc/html/highlight.rs30
-rw-r--r--src/librustdoc/html/layout.rs1
-rw-r--r--src/librustdoc/html/length_limit.rs4
-rw-r--r--src/librustdoc/html/length_limit/tests.rs2
-rw-r--r--src/librustdoc/html/markdown.rs209
-rw-r--r--src/librustdoc/html/markdown/tests.rs2
-rw-r--r--src/librustdoc/html/render/context.rs43
-rw-r--r--src/librustdoc/html/render/mod.rs166
-rw-r--r--src/librustdoc/html/render/print_item.rs672
-rw-r--r--src/librustdoc/html/render/search_index.rs11
-rw-r--r--src/librustdoc/html/render/write_shared.rs5
-rw-r--r--src/librustdoc/html/sources.rs3
-rw-r--r--src/librustdoc/html/static/.eslintrc.js1
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css148
-rw-r--r--src/librustdoc/html/static/css/settings.css30
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css77
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css26
-rw-r--r--src/librustdoc/html/static/css/themes/light.css26
-rw-r--r--src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff2bin81320 -> 81540 bytes
-rw-r--r--src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff2bin59860 -> 59716 bytes
-rw-r--r--src/librustdoc/html/static/fonts/SourceSerif4-LICENSE.md2
-rw-r--r--src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff2bin76180 -> 76260 bytes
-rw-r--r--src/librustdoc/html/static/images/down-arrow.svg1
-rw-r--r--src/librustdoc/html/static/images/toggle-minus.svg1
-rw-r--r--src/librustdoc/html/static/images/toggle-plus.svg1
-rw-r--r--src/librustdoc/html/static/images/wheel.svg2
-rw-r--r--src/librustdoc/html/static/js/main.js125
-rw-r--r--src/librustdoc/html/static/js/search.js355
-rw-r--r--src/librustdoc/html/static/js/settings.js55
-rw-r--r--src/librustdoc/html/static/js/source-script.js3
-rw-r--r--src/librustdoc/html/static/js/storage.js113
-rw-r--r--src/librustdoc/html/static_files.rs3
-rw-r--r--src/librustdoc/html/templates/page.html3
-rw-r--r--src/librustdoc/html/templates/print_item.html2
35 files changed, 1077 insertions, 1143 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index d3dc4065d..0e4c5ed68 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -34,6 +34,7 @@ use crate::clean::{
use crate::formats::item_type::ItemType;
use crate::html::escape::Escape;
use crate::html::render::Context;
+use crate::passes::collect_intra_doc_links::UrlFragment;
use super::url_parts_builder::estimate_item_path_byte_length;
use super::url_parts_builder::UrlPartsBuilder;
@@ -208,7 +209,7 @@ impl clean::GenericParamDef {
if f.alternate() {
write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
} else {
- write!(f, ": {}", print_generic_bounds(bounds, cx))?;
+ write!(f, ": {}", print_generic_bounds(bounds, cx))?;
}
}
@@ -216,7 +217,7 @@ impl clean::GenericParamDef {
if f.alternate() {
write!(f, " = {:#}", ty.print(cx))?;
} else {
- write!(f, " = {}", ty.print(cx))?;
+ write!(f, " = {}", ty.print(cx))?;
}
}
@@ -226,14 +227,14 @@ impl clean::GenericParamDef {
if f.alternate() {
write!(f, "const {}: {:#}", self.name, ty.print(cx))?;
} else {
- write!(f, "const {}: {}", self.name, ty.print(cx))?;
+ write!(f, "const {}: {}", self.name, ty.print(cx))?;
}
if let Some(default) = default {
if f.alternate() {
write!(f, " = {:#}", default)?;
} else {
- write!(f, " = {}", default)?;
+ write!(f, " = {}", default)?;
}
}
@@ -289,7 +290,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
if f.alternate() {
f.write_str(" ")?;
} else {
- f.write_str("<br>")?;
+ f.write_str("\n")?;
}
match pred {
@@ -352,23 +353,31 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
}
} else {
let mut br_with_padding = String::with_capacity(6 * indent + 28);
- br_with_padding.push_str("<br>");
- for _ in 0..indent + 4 {
- br_with_padding.push_str("&nbsp;");
+ br_with_padding.push_str("\n");
+
+ let padding_amout =
+ if ending == Ending::Newline { indent + 4 } else { indent + "fn where ".len() };
+
+ for _ in 0..padding_amout {
+ br_with_padding.push_str(" ");
}
- let where_preds = where_preds.to_string().replace("<br>", &br_with_padding);
+ let where_preds = where_preds.to_string().replace('\n', &br_with_padding);
if ending == Ending::Newline {
- let mut clause = "&nbsp;".repeat(indent.saturating_sub(1));
+ let mut clause = " ".repeat(indent.saturating_sub(1));
write!(clause, "<span class=\"where fmt-newline\">where{where_preds},</span>")?;
clause
} else {
- // insert a <br> tag after a single space but before multiple spaces at the start
+ // insert a newline after a single space but before multiple spaces at the start
if indent == 0 {
- format!("<br><span class=\"where\">where{where_preds}</span>")
+ format!("\n<span class=\"where\">where{where_preds}</span>")
} else {
+ // put the first one on the same line as the 'where' keyword
+ let where_preds = where_preds.replacen(&br_with_padding, " ", 1);
+
let mut clause = br_with_padding;
- clause.truncate(clause.len() - 4 * "&nbsp;".len());
+ clause.truncate(clause.len() - "where ".len());
+
write!(clause, "<span class=\"where\">where{where_preds}</span>")?;
clause
}
@@ -701,11 +710,9 @@ pub(crate) fn href_with_root_path(
}
}
};
- if !is_remote {
- if let Some(root_path) = root_path {
- let root = root_path.trim_end_matches('/');
- url_parts.push_front(root);
- }
+ if !is_remote && let Some(root_path) = root_path {
+ let root = root_path.trim_end_matches('/');
+ url_parts.push_front(root);
}
debug!(?url_parts);
match shortty {
@@ -760,6 +767,28 @@ pub(crate) fn href_relative_parts<'fqp>(
}
}
+pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Context<'_>) -> String {
+ let cache = cx.cache();
+ let Some((fqp, shortty)) = cache.paths.get(&did)
+ .or_else(|| cache.external_paths.get(&did))
+ else { return String::new() };
+ let mut buf = Buffer::new();
+ if let &Some(UrlFragment::Item(id)) = fragment {
+ write!(buf, "{} ", cx.tcx().def_descr(id));
+ for component in fqp {
+ write!(buf, "{component}::");
+ }
+ write!(buf, "{}", cx.tcx().item_name(id));
+ } else if !fqp.is_empty() {
+ let mut fqp_it = fqp.into_iter();
+ write!(buf, "{shortty} {}", fqp_it.next().unwrap());
+ for component in fqp_it {
+ write!(buf, "::{component}");
+ }
+ }
+ buf.into_inner()
+}
+
/// Used to render a [`clean::Path`].
fn resolved_path<'cx>(
w: &mut fmt::Formatter<'_>,
@@ -1064,14 +1093,8 @@ fn fmt_type<'cx>(
fmt_type(ty, f, use_absolute, cx)?;
write!(f, ")")
}
- clean::Generic(..) => {
- primitive_link(
- f,
- PrimitiveType::Reference,
- &format!("{}{}{}", amp, lt, m),
- cx,
- )?;
- fmt_type(ty, f, use_absolute, cx)
+ clean::Generic(name) => {
+ primitive_link(f, PrimitiveType::Reference, &format!("{amp}{lt}{m}{name}"), cx)
}
_ => {
write!(f, "{}{}{}", amp, lt, m)?;
@@ -1313,7 +1336,8 @@ impl clean::FnDecl {
/// * `header_len`: The length of the function header and name. In other words, the number of
/// characters in the function declaration up to but not including the parentheses.
- /// <br>Used to determine line-wrapping.
+ /// This is expected to go into a `<pre>`/`code-header` block, so indentation and newlines
+ /// are preserved.
/// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
/// necessary.
pub(crate) fn full_print<'a, 'tcx: 'a>(
@@ -1361,7 +1385,7 @@ impl clean::FnDecl {
}
} else {
if i > 0 {
- args.push_str("<br>");
+ args.push_str("\n");
}
if input.is_const {
args.push_str("const ");
@@ -1387,7 +1411,7 @@ impl clean::FnDecl {
let mut args = args.into_inner();
if self.c_variadic {
- args.push_str(",<br> ...");
+ args.push_str(",\n ...");
args_plain.push_str(", ...");
}
@@ -1397,24 +1421,20 @@ impl clean::FnDecl {
let declaration_len = header_len + args_plain.len() + arrow_plain.len();
let output = if declaration_len > 80 {
- let full_pad = format!("<br>{}", "&nbsp;".repeat(indent + 4));
- let close_pad = format!("<br>{}", "&nbsp;".repeat(indent));
+ let full_pad = format!("\n{}", " ".repeat(indent + 4));
+ let close_pad = format!("\n{}", " ".repeat(indent));
format!(
"({pad}{args}{close}){arrow}",
pad = if self.inputs.values.is_empty() { "" } else { &full_pad },
- args = args.replace("<br>", &full_pad),
+ args = args.replace('\n', &full_pad),
close = close_pad,
arrow = arrow
)
} else {
- format!("({args}){arrow}", args = args.replace("<br>", " "), arrow = arrow)
+ format!("({args}){arrow}", args = args.replace('\n', " "), arrow = arrow)
};
- if f.alternate() {
- write!(f, "{}", output.replace("<br>", "\n"))
- } else {
- write!(f, "{}", output)
- }
+ write!(f, "{}", output)
}
}
@@ -1617,7 +1637,7 @@ impl clean::TypeBinding {
if f.alternate() {
write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
} else {
- write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cx))?;
+ write!(f, ": {}", print_generic_bounds(bounds, cx))?;
}
}
}
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 8a9e6caf6..2c9fc4e3c 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -58,11 +58,11 @@ pub(crate) fn render_example_with_highlighting(
write_footer(out, playground_button);
}
-/// Highlights `src` as a macro, returning the HTML output.
-pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) {
- write_header(out, "macro", None, Tooltip::None);
+/// Highlights `src` as an item-decl, returning the HTML output.
+pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) {
+ write!(out, "<pre class=\"rust item-decl\">");
write_code(out, src, None, None);
- write_footer(out, None);
+ write!(out, "</pre>");
}
/// Highlights `src` as a source code page, returning the HTML output.
@@ -96,13 +96,19 @@ fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, to
);
if tooltip != Tooltip::None {
+ let edition_code;
write!(
out,
- "<div class='tooltip'{}>ⓘ</div>",
- if let Tooltip::Edition(edition_info) = tooltip {
- format!(" data-edition=\"{}\"", edition_info)
- } else {
- String::new()
+ "<a href=\"#\" class=\"tooltip\" title=\"{}\">ⓘ</a>",
+ match tooltip {
+ Tooltip::Ignore => "This example is not tested",
+ Tooltip::CompileFail => "This example deliberately fails to compile",
+ Tooltip::ShouldPanic => "This example panics",
+ Tooltip::Edition(edition) => {
+ edition_code = format!("This example runs with edition {edition}");
+ &edition_code
+ }
+ Tooltip::None => unreachable!(),
},
);
}
@@ -460,10 +466,8 @@ impl<'a> PeekIter<'a> {
}
/// Returns the next item after the current one. It doesn't interfere with `peek_next` output.
fn peek(&mut self) -> Option<&(TokenKind, &'a str)> {
- if self.stored.is_empty() {
- if let Some(next) = self.iter.next() {
- self.stored.push_back(next);
- }
+ if self.stored.is_empty() && let Some(next) = self.iter.next() {
+ self.stored.push_back(next);
}
self.stored.front()
}
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index a60e7cb10..6ab849c92 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -30,7 +30,6 @@ pub(crate) struct Page<'a> {
pub(crate) root_path: &'a str,
pub(crate) static_root_path: Option<&'a str>,
pub(crate) description: &'a str,
- pub(crate) keywords: &'a str,
pub(crate) resource_suffix: &'a str,
}
diff --git a/src/librustdoc/html/length_limit.rs b/src/librustdoc/html/length_limit.rs
index bbdc91c8d..4c8db2c67 100644
--- a/src/librustdoc/html/length_limit.rs
+++ b/src/librustdoc/html/length_limit.rs
@@ -61,14 +61,14 @@ impl HtmlWithLimit {
/// and returns [`ControlFlow::Break`].
pub(super) fn push(&mut self, text: &str) -> ControlFlow<(), ()> {
if self.len + text.len() > self.limit {
- return ControlFlow::BREAK;
+ return ControlFlow::Break(());
}
self.flush_queue();
write!(self.buf, "{}", Escape(text)).unwrap();
self.len += text.len();
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
/// Open an HTML tag.
diff --git a/src/librustdoc/html/length_limit/tests.rs b/src/librustdoc/html/length_limit/tests.rs
index 2d02b8a16..2185c0348 100644
--- a/src/librustdoc/html/length_limit/tests.rs
+++ b/src/librustdoc/html/length_limit/tests.rs
@@ -83,7 +83,7 @@ fn past_the_limit() {
buf.push("word#")?;
buf.push(&n.to_string())?;
buf.close_tag();
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
});
buf.close_tag();
assert_eq!(
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 4ff67fe15..fe446ae3c 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -27,14 +27,14 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
-use rustc_hir::HirId;
use rustc_middle::ty::TyCtxt;
+pub(crate) use rustc_resolve::rustdoc::main_body_opts;
+use rustc_resolve::rustdoc::may_be_doc_link;
use rustc_span::edition::Edition;
use rustc_span::{Span, Symbol};
use once_cell::sync::Lazy;
use std::borrow::Cow;
-use std::cell::RefCell;
use std::collections::VecDeque;
use std::default::Default;
use std::fmt::Write;
@@ -47,6 +47,7 @@ use crate::html::escape::Escape;
use crate::html::format::Buffer;
use crate::html::highlight;
use crate::html::length_limit::HtmlWithLimit;
+use crate::html::render::small_url_encode;
use crate::html::toc::TocBuilder;
use pulldown_cmark::{
@@ -58,15 +59,6 @@ mod tests;
const MAX_HEADER_LEVEL: u32 = 6;
-/// Options for rendering Markdown in the main body of documentation.
-pub(crate) fn main_body_opts() -> Options {
- Options::ENABLE_TABLES
- | Options::ENABLE_FOOTNOTES
- | Options::ENABLE_STRIKETHROUGH
- | Options::ENABLE_TASKLISTS
- | Options::ENABLE_SMART_PUNCTUATION
-}
-
/// Options for rendering Markdown in summaries (e.g., in search results).
pub(crate) fn summary_opts() -> Options {
Options::ENABLE_TABLES
@@ -103,14 +95,14 @@ pub struct Markdown<'a> {
/// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `<h2>`.
pub heading_offset: HeadingOffset,
}
-/// A tuple struct like `Markdown` that renders the markdown with a table of contents.
-pub(crate) struct MarkdownWithToc<'a>(
- pub(crate) &'a str,
- pub(crate) &'a mut IdMap,
- pub(crate) ErrorCodes,
- pub(crate) Edition,
- pub(crate) &'a Option<Playground>,
-);
+/// A struct like `Markdown` that renders the markdown with a table of contents.
+pub(crate) struct MarkdownWithToc<'a> {
+ pub(crate) content: &'a str,
+ pub(crate) ids: &'a mut IdMap,
+ pub(crate) error_codes: ErrorCodes,
+ pub(crate) edition: Edition,
+ pub(crate) playground: &'a Option<Playground>,
+}
/// A tuple struct like `Markdown` that renders the markdown escaping HTML tags
/// and includes no paragraph tags.
pub(crate) struct MarkdownItemInfo<'a>(pub(crate) &'a str, pub(crate) &'a mut IdMap);
@@ -295,30 +287,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
doctest::make_test(&test, krate, false, &Default::default(), edition, None);
let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
- // These characters don't need to be escaped in a URI.
- // FIXME: use a library function for percent encoding.
- fn dont_escape(c: u8) -> bool {
- (b'a' <= c && c <= b'z')
- || (b'A' <= c && c <= b'Z')
- || (b'0' <= c && c <= b'9')
- || c == b'-'
- || c == b'_'
- || c == b'.'
- || c == b'~'
- || c == b'!'
- || c == b'\''
- || c == b'('
- || c == b')'
- || c == b'*'
- }
- let mut test_escaped = String::new();
- for b in test.bytes() {
- if dont_escape(b) {
- test_escaped.push(char::from(b));
- } else {
- write!(test_escaped, "%{:02X}", b).unwrap();
- }
- }
+ let test_escaped = small_url_encode(test);
Some(format!(
r#"<a class="test-arrow" target="_blank" href="{}?code={}{}&amp;edition={}">Run</a>"#,
url, test_escaped, channel, edition,
@@ -391,6 +360,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
trace!("it matched");
assert!(self.shortcut_link.is_none(), "shortcut links cannot be nested");
self.shortcut_link = Some(link);
+ if title.is_empty() && !link.tooltip.is_empty() {
+ *title = CowStr::Borrowed(link.tooltip.as_ref());
+ }
}
}
// Now that we're done with the shortcut link, don't replace any more text.
@@ -441,9 +413,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
}
// If this is a link, but not a shortcut link,
// replace the URL, since the broken_link_callback was not called.
- Some(Event::Start(Tag::Link(_, dest, _))) => {
+ Some(Event::Start(Tag::Link(_, dest, title))) => {
if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) {
*dest = CowStr::Borrowed(link.href.as_ref());
+ if title.is_empty() && !link.tooltip.is_empty() {
+ *title = CowStr::Borrowed(link.tooltip.as_ref());
+ }
}
}
// Anything else couldn't have been a valid Rust path, so no need to replace the text.
@@ -577,10 +552,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> {
}
fn check_if_allowed_tag(t: &Tag<'_>) -> bool {
- matches!(
- t,
- Tag::Paragraph | Tag::Item | Tag::Emphasis | Tag::Strong | Tag::Link(..) | Tag::BlockQuote
- )
+ matches!(t, Tag::Paragraph | Tag::Emphasis | Tag::Strong | Tag::Link(..) | Tag::BlockQuote)
}
fn is_forbidden_tag(t: &Tag<'_>) -> bool {
@@ -771,11 +743,7 @@ pub(crate) fn find_testable_code<T: doctest::Tester>(
}
Event::Text(ref s) if register_header.is_some() => {
let level = register_header.unwrap();
- if s.is_empty() {
- tests.register_header("", level);
- } else {
- tests.register_header(s, level);
- }
+ tests.register_header(s, level);
register_header = None;
}
_ => {}
@@ -784,45 +752,26 @@ pub(crate) fn find_testable_code<T: doctest::Tester>(
}
pub(crate) struct ExtraInfo<'tcx> {
- id: ExtraInfoId,
+ def_id: DefId,
sp: Span,
tcx: TyCtxt<'tcx>,
}
-enum ExtraInfoId {
- Hir(HirId),
- Def(DefId),
-}
-
impl<'tcx> ExtraInfo<'tcx> {
- pub(crate) fn new(tcx: TyCtxt<'tcx>, hir_id: HirId, sp: Span) -> ExtraInfo<'tcx> {
- ExtraInfo { id: ExtraInfoId::Hir(hir_id), sp, tcx }
- }
-
- pub(crate) fn new_did(tcx: TyCtxt<'tcx>, did: DefId, sp: Span) -> ExtraInfo<'tcx> {
- ExtraInfo { id: ExtraInfoId::Def(did), sp, tcx }
+ pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: DefId, sp: Span) -> ExtraInfo<'tcx> {
+ ExtraInfo { def_id, sp, tcx }
}
fn error_invalid_codeblock_attr(&self, msg: &str, help: &str) {
- let hir_id = match self.id {
- ExtraInfoId::Hir(hir_id) => hir_id,
- ExtraInfoId::Def(item_did) => {
- match item_did.as_local() {
- Some(item_did) => self.tcx.hir().local_def_id_to_hir_id(item_did),
- None => {
- // If non-local, no need to check anything.
- return;
- }
- }
- }
- };
- self.tcx.struct_span_lint_hir(
- crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
- hir_id,
- self.sp,
- msg,
- |lint| lint.help(help),
- );
+ if let Some(def_id) = self.def_id.as_local() {
+ self.tcx.struct_span_lint_hir(
+ crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
+ self.tcx.hir().local_def_id_to_hir_id(def_id),
+ self.sp,
+ msg,
+ |lint| lint.help(help),
+ );
+ }
}
}
@@ -1029,8 +978,8 @@ impl Markdown<'_> {
let mut replacer = |broken_link: BrokenLink<'_>| {
links
.iter()
- .find(|link| link.original_text.as_str() == &*broken_link.reference)
- .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
+ .find(|link| &*link.original_text == &*broken_link.reference)
+ .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
};
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
@@ -1051,7 +1000,7 @@ impl Markdown<'_> {
impl MarkdownWithToc<'_> {
pub(crate) fn into_string(self) -> String {
- let MarkdownWithToc(md, ids, codes, edition, playground) = self;
+ let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self;
let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
@@ -1112,8 +1061,8 @@ impl MarkdownSummaryLine<'_> {
let mut replacer = |broken_link: BrokenLink<'_>| {
links
.iter()
- .find(|link| link.original_text.as_str() == &*broken_link.reference)
- .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
+ .find(|link| &*link.original_text == &*broken_link.reference)
+ .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
};
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer))
@@ -1159,8 +1108,8 @@ fn markdown_summary_with_limit(
let mut replacer = |broken_link: BrokenLink<'_>| {
link_names
.iter()
- .find(|link| link.original_text.as_str() == &*broken_link.reference)
- .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
+ .find(|link| &*link.original_text == &*broken_link.reference)
+ .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
};
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
@@ -1191,18 +1140,18 @@ fn markdown_summary_with_limit(
Event::Start(tag) => match tag {
Tag::Emphasis => buf.open_tag("em"),
Tag::Strong => buf.open_tag("strong"),
- Tag::CodeBlock(..) => return ControlFlow::BREAK,
+ Tag::CodeBlock(..) => return ControlFlow::Break(()),
_ => {}
},
Event::End(tag) => match tag {
Tag::Emphasis | Tag::Strong => buf.close_tag(),
- Tag::Paragraph | Tag::Heading(..) => return ControlFlow::BREAK,
+ Tag::Paragraph | Tag::Heading(..) => return ControlFlow::Break(()),
_ => {}
},
Event::HardBreak | Event::SoftBreak => buf.push(" ")?,
_ => {}
};
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
});
(buf.finish(), stopped_early)
@@ -1230,14 +1179,23 @@ pub(crate) fn short_markdown_summary(markdown: &str, link_names: &[RenderedLink]
/// - Headings, links, and formatting are stripped.
/// - Inline code is rendered as-is, surrounded by backticks.
/// - HTML and code blocks are ignored.
-pub(crate) fn plain_text_summary(md: &str) -> String {
+pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> String {
if md.is_empty() {
return String::new();
}
let mut s = String::with_capacity(md.len() * 3 / 2);
- for event in Parser::new_ext(md, summary_opts()) {
+ let mut replacer = |broken_link: BrokenLink<'_>| {
+ link_names
+ .iter()
+ .find(|link| &*link.original_text == &*broken_link.reference)
+ .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
+ };
+
+ let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
+
+ for event in p {
match &event {
Event::Text(text) => s.push_str(text),
Event::Code(code) => {
@@ -1265,14 +1223,12 @@ pub(crate) struct MarkdownLink {
pub(crate) fn markdown_links<R>(
md: &str,
- filter_map: impl Fn(MarkdownLink) -> Option<R>,
+ preprocess_link: impl Fn(MarkdownLink) -> Option<R>,
) -> Vec<R> {
if md.is_empty() {
return vec![];
}
- let links = RefCell::new(vec![]);
-
// FIXME: remove this function once pulldown_cmark can provide spans for link definitions.
let locate = |s: &str, fallback: Range<usize>| unsafe {
let s_start = s.as_ptr();
@@ -1304,46 +1260,23 @@ pub(crate) fn markdown_links<R>(
}
};
- let mut push = |link: BrokenLink<'_>| {
- let span = span_for_link(&link.reference, link.span);
- filter_map(MarkdownLink {
- kind: LinkType::ShortcutUnknown,
- link: link.reference.to_string(),
- range: span,
- })
- .map(|link| links.borrow_mut().push(link));
- None
- };
- let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push))
- .into_offset_iter();
-
- // There's no need to thread an IdMap through to here because
- // the IDs generated aren't going to be emitted anywhere.
- let mut ids = IdMap::new();
- let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1));
-
- for ev in iter {
- if let Event::Start(Tag::Link(
- // `<>` links cannot be intra-doc links so we skip them.
- kind @ (LinkType::Inline
- | LinkType::Reference
- | LinkType::ReferenceUnknown
- | LinkType::Collapsed
- | LinkType::CollapsedUnknown
- | LinkType::Shortcut
- | LinkType::ShortcutUnknown),
- dest,
- _,
- )) = ev.0
- {
- debug!("found link: {dest}");
- let span = span_for_link(&dest, ev.1);
- filter_map(MarkdownLink { kind, link: dest.into_string(), range: span })
- .map(|link| links.borrow_mut().push(link));
+ Parser::new_with_broken_link_callback(
+ md,
+ main_body_opts(),
+ Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))),
+ )
+ .into_offset_iter()
+ .filter_map(|(event, span)| match event {
+ Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
+ preprocess_link(MarkdownLink {
+ kind: link_type,
+ range: span_for_link(&dest, span),
+ link: dest.into_string(),
+ })
}
- }
-
- links.into_inner()
+ _ => None,
+ })
+ .collect()
}
#[derive(Debug)]
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index 5878c5826..e05635a02 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -249,7 +249,7 @@ fn test_short_markdown_summary() {
#[test]
fn test_plain_text_summary() {
fn t(input: &str, expect: &str) {
- let output = plain_text_summary(input);
+ let output = plain_text_summary(input, &[]);
assert_eq!(output, expect, "original: {}", input);
}
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 5cefe9475..5e4a59562 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -6,7 +6,7 @@ use std::rc::Rc;
use std::sync::mpsc::{channel, Receiver};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::edition::Edition;
@@ -18,7 +18,7 @@ use super::search_index::build_index;
use super::write_shared::write_shared;
use super::{
collect_spans_and_sources, print_sidebar, scrape_examples_help, sidebar_module_like, AllTypes,
- LinkFromSrc, NameDoc, StylePath, BASIC_KEYWORDS,
+ LinkFromSrc, StylePath,
};
use crate::clean::{self, types::ExternalLocation, ExternalCrate};
@@ -56,7 +56,7 @@ pub(crate) struct Context<'tcx> {
pub(super) render_redirect_pages: bool,
/// Tracks section IDs for `Deref` targets so they match in both the main
/// body and the sidebar.
- pub(super) deref_id_map: FxHashMap<DefId, String>,
+ pub(super) deref_id_map: DefIdMap<String>,
/// The map used to ensure all generated 'id=' attributes are unique.
pub(super) id_map: IdMap,
/// Shared mutable state.
@@ -182,7 +182,10 @@ impl<'tcx> Context<'tcx> {
};
title.push_str(" - Rust");
let tyname = it.type_();
- let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(doc));
+ let desc = it
+ .doc_value()
+ .as_ref()
+ .map(|doc| plain_text_summary(doc, &it.link_names(&self.cache())));
let desc = if let Some(desc) = desc {
desc
} else if it.is_crate() {
@@ -195,7 +198,6 @@ impl<'tcx> Context<'tcx> {
self.shared.layout.krate
)
};
- let keywords = make_item_keywords(it);
let name;
let tyname_s = if it.is_crate() {
name = format!("{} crate", tyname);
@@ -212,7 +214,6 @@ impl<'tcx> Context<'tcx> {
static_root_path: clone_shared.static_root_path.as_deref(),
title: &title,
description: &desc,
- keywords: &keywords,
resource_suffix: &clone_shared.resource_suffix,
};
let mut page_buffer = Buffer::html();
@@ -258,7 +259,7 @@ impl<'tcx> Context<'tcx> {
}
/// Construct a map of items shown in the sidebar to a plain-text summary of their docs.
- fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc>> {
+ fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<String>> {
// BTreeMap instead of HashMap to get a sorted output
let mut map: BTreeMap<_, Vec<_>> = BTreeMap::new();
let mut inserted: FxHashMap<ItemType, FxHashSet<Symbol>> = FxHashMap::default();
@@ -276,10 +277,7 @@ impl<'tcx> Context<'tcx> {
if inserted.entry(short).or_default().insert(myname) {
let short = short.to_string();
let myname = myname.to_string();
- map.entry(short).or_default().push((
- myname,
- Some(item.doc_value().map_or_else(String::new, |s| plain_text_summary(&s))),
- ));
+ map.entry(short).or_default().push(myname);
}
}
@@ -544,7 +542,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
dst,
render_redirect_pages: false,
id_map,
- deref_id_map: FxHashMap::default(),
+ deref_id_map: Default::default(),
shared: Rc::new(scx),
include_sources,
types_with_notable_traits: FxHashSet::default(),
@@ -572,7 +570,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
current: self.current.clone(),
dst: self.dst.clone(),
render_redirect_pages: self.render_redirect_pages,
- deref_id_map: FxHashMap::default(),
+ deref_id_map: Default::default(),
id_map: IdMap::new(),
shared: Rc::clone(&self.shared),
include_sources: self.include_sources,
@@ -598,7 +596,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
root_path: "../",
static_root_path: shared.static_root_path.as_deref(),
description: "List of all items in this crate",
- keywords: BASIC_KEYWORDS,
resource_suffix: &shared.resource_suffix,
};
let all = shared.all.replace(AllTypes::new());
@@ -708,14 +705,12 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
shared.fs.write(scrape_examples_help_file, v)?;
}
- if let Some(ref redirections) = shared.redirections {
- if !redirections.borrow().is_empty() {
- let redirect_map_path =
- self.dst.join(crate_name.as_str()).join("redirect-map.json");
- let paths = serde_json::to_string(&*redirections.borrow()).unwrap();
- shared.ensure_dir(&self.dst.join(crate_name.as_str()))?;
- shared.fs.write(redirect_map_path, paths)?;
- }
+ if let Some(ref redirections) = shared.redirections && !redirections.borrow().is_empty() {
+ let redirect_map_path =
+ self.dst.join(crate_name.as_str()).join("redirect-map.json");
+ let paths = serde_json::to_string(&*redirections.borrow()).unwrap();
+ shared.ensure_dir(&self.dst.join(crate_name.as_str()))?;
+ shared.fs.write(redirect_map_path, paths)?;
}
// No need for it anymore.
@@ -828,7 +823,3 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
&self.shared.cache
}
}
-
-fn make_item_keywords(it: &clean::Item) -> String {
- format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap())
-}
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 4fa33e890..e6a040d02 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -38,7 +38,7 @@ pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
use std::collections::VecDeque;
use std::default::Default;
-use std::fmt;
+use std::fmt::{self, Write};
use std::fs;
use std::iter::Peekable;
use std::path::PathBuf;
@@ -50,7 +50,7 @@ use rustc_ast_pretty::pprust;
use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def::CtorKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::Mutability;
use rustc_middle::middle::stability;
use rustc_middle::ty;
@@ -83,9 +83,6 @@ use crate::scrape_examples::{CallData, CallLocation};
use crate::try_none;
use crate::DOC_RUST_LANG_ORG_CHANNEL;
-/// A pair of name and its optional document.
-pub(crate) type NameDoc = (String, Option<String>);
-
pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
crate::html::format::display_fn(move |f| {
if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { f.write_str(v) }
@@ -1115,7 +1112,7 @@ fn render_assoc_items(
it: DefId,
what: AssocItemRender<'_>,
) {
- let mut derefs = FxHashSet::default();
+ let mut derefs = DefIdSet::default();
derefs.insert(it);
render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs)
}
@@ -1126,7 +1123,7 @@ fn render_assoc_items_inner(
containing_item: &clean::Item,
it: DefId,
what: AssocItemRender<'_>,
- derefs: &mut FxHashSet<DefId>,
+ derefs: &mut DefIdSet,
) {
info!("Documenting associated items of {:?}", containing_item.name);
let shared = Rc::clone(&cx.shared);
@@ -1215,7 +1212,7 @@ fn render_deref_methods(
impl_: &Impl,
container_item: &clean::Item,
deref_mut: bool,
- derefs: &mut FxHashSet<DefId>,
+ derefs: &mut DefIdSet,
) {
let cache = cx.cache();
let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
@@ -1313,7 +1310,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O
if has_notable_trait {
cx.types_with_notable_traits.insert(ty.clone());
Some(format!(
- " <a href=\"#\" class=\"notable-traits\" data-ty=\"{ty}\">ⓘ</a>",
+ " <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
ty = Escape(&format!("{:#}", ty.print(cx))),
))
} else {
@@ -1528,11 +1525,7 @@ fn render_impl(
})
})
.map(|item| format!("{}.{}", item.type_(), name));
- write!(
- w,
- "<section id=\"{}\" class=\"{}{} has-srclink\">",
- id, item_type, in_trait_class,
- );
+ write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
render_rightside(w, cx, item, containing_item, render_mode);
if trait_.is_some() {
// Anchors are only used on trait impls.
@@ -1554,11 +1547,7 @@ fn render_impl(
kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
let source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone());
- write!(
- w,
- "<section id=\"{}\" class=\"{}{} has-srclink\">",
- id, item_type, in_trait_class
- );
+ write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
render_rightside(w, cx, item, containing_item, render_mode);
if trait_.is_some() {
// Anchors are only used on trait impls.
@@ -1606,11 +1595,7 @@ fn render_impl(
clean::AssocTypeItem(tydef, _bounds) => {
let source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone());
- write!(
- w,
- "<section id=\"{}\" class=\"{}{} has-srclink\">",
- id, item_type, in_trait_class
- );
+ write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
if trait_.is_some() {
// Anchors are only used on trait impls.
write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
@@ -1844,7 +1829,7 @@ pub(crate) fn render_impl_summary(
} else {
format!(" data-aliases=\"{}\"", aliases.join(","))
};
- write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
+ write!(w, "<section id=\"{}\" class=\"impl\"{}>", id, aliases);
render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
write!(w, "<h3 class=\"code-header\">");
@@ -2032,31 +2017,60 @@ fn get_associated_constants(
.collect::<Vec<_>>()
}
-// The point is to url encode any potential character from a type with genericity.
-fn small_url_encode(s: String) -> String {
+pub(crate) fn small_url_encode(s: String) -> String {
+ // These characters don't need to be escaped in a URI.
+ // See https://url.spec.whatwg.org/#query-percent-encode-set
+ // and https://url.spec.whatwg.org/#urlencoded-parsing
+ // and https://url.spec.whatwg.org/#url-code-points
+ fn dont_escape(c: u8) -> bool {
+ (b'a' <= c && c <= b'z')
+ || (b'A' <= c && c <= b'Z')
+ || (b'0' <= c && c <= b'9')
+ || c == b'-'
+ || c == b'_'
+ || c == b'.'
+ || c == b','
+ || c == b'~'
+ || c == b'!'
+ || c == b'\''
+ || c == b'('
+ || c == b')'
+ || c == b'*'
+ || c == b'/'
+ || c == b';'
+ || c == b':'
+ || c == b'?'
+ // As described in urlencoded-parsing, the
+ // first `=` is the one that separates key from
+ // value. Following `=`s are part of the value.
+ || c == b'='
+ }
let mut st = String::new();
let mut last_match = 0;
- for (idx, c) in s.char_indices() {
- let escaped = match c {
- '<' => "%3C",
- '>' => "%3E",
- ' ' => "%20",
- '?' => "%3F",
- '\'' => "%27",
- '&' => "%26",
- ',' => "%2C",
- ':' => "%3A",
- ';' => "%3B",
- '[' => "%5B",
- ']' => "%5D",
- '"' => "%22",
- _ => continue,
- };
+ for (idx, b) in s.bytes().enumerate() {
+ if dont_escape(b) {
+ continue;
+ }
- st += &s[last_match..idx];
- st += escaped;
- // NOTE: we only expect single byte characters here - which is fine as long as we
- // only match single byte characters
+ if last_match != idx {
+ // Invariant: `idx` must be the first byte in a character at this point.
+ st += &s[last_match..idx];
+ }
+ if b == b' ' {
+ // URL queries are decoded with + replaced with SP.
+ // While the same is not true for hashes, rustdoc only needs to be
+ // consistent with itself when encoding them.
+ st += "+";
+ } else if b == b'%' {
+ st += "%%";
+ } else {
+ write!(st, "%{:02X}", b).unwrap();
+ }
+ // Invariant: if the current byte is not at the start of a multi-byte character,
+ // we need to get down here so that when the next turn of the loop comes around,
+ // last_match winds up equalling idx.
+ //
+ // In other words, dont_escape must always return `false` in multi-byte character.
last_match = idx + 1;
}
@@ -2175,7 +2189,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
if let Some(impl_) =
v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
{
- let mut derefs = FxHashSet::default();
+ let mut derefs = DefIdSet::default();
derefs.insert(did);
sidebar_deref_methods(cx, out, impl_, v, &mut derefs, &mut used_links);
}
@@ -2195,7 +2209,7 @@ fn sidebar_deref_methods(
out: &mut Buffer,
impl_: &Impl,
v: &[Impl],
- derefs: &mut FxHashSet<DefId>,
+ derefs: &mut DefIdSet,
used_links: &mut FxHashSet<String>,
) {
let c = cx.cache();
@@ -2211,14 +2225,13 @@ fn sidebar_deref_methods(
})
{
debug!("found target, real_target: {:?} {:?}", target, real_target);
- if let Some(did) = target.def_id(c) {
- if let Some(type_did) = impl_.inner_impl().for_.def_id(c) {
- // `impl Deref<Target = S> for S`
- if did == type_did || !derefs.insert(did) {
- // Avoid infinite cycles
- return;
- }
- }
+ if let Some(did) = target.def_id(c) &&
+ let Some(type_did) = impl_.inner_impl().for_.def_id(c) &&
+ // `impl Deref<Target = S> for S`
+ (did == type_did || !derefs.insert(did))
+ {
+ // Avoid infinite cycles
+ return;
}
let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
let inner_impl = target
@@ -2252,25 +2265,24 @@ fn sidebar_deref_methods(
}
// Recurse into any further impls that might exist for `target`
- if let Some(target_did) = target.def_id(c) {
- if let Some(target_impls) = c.impls.get(&target_did) {
- if let Some(target_deref_impl) = target_impls.iter().find(|i| {
- i.inner_impl()
- .trait_
- .as_ref()
- .map(|t| Some(t.def_id()) == cx.tcx().lang_items().deref_trait())
- .unwrap_or(false)
- }) {
- sidebar_deref_methods(
- cx,
- out,
- target_deref_impl,
- target_impls,
- derefs,
- used_links,
- );
- }
- }
+ if let Some(target_did) = target.def_id(c) &&
+ let Some(target_impls) = c.impls.get(&target_did) &&
+ let Some(target_deref_impl) = target_impls.iter().find(|i| {
+ i.inner_impl()
+ .trait_
+ .as_ref()
+ .map(|t| Some(t.def_id()) == cx.tcx().lang_items().deref_trait())
+ .unwrap_or(false)
+ })
+ {
+ sidebar_deref_methods(
+ cx,
+ out,
+ target_deref_impl,
+ target_impls,
+ derefs,
+ used_links,
+ );
}
}
}
@@ -2755,8 +2767,6 @@ fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
}
}
-pub(crate) const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
-
/// Returns a list of all paths used in the type.
/// This is used to help deduplicate imported impls
/// for reexported types. If any of the contained
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index f824c9e3a..2869a3961 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -10,7 +10,7 @@ use rustc_middle::ty::layout::LayoutError;
use rustc_middle::ty::{self, Adt, TyCtxt};
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_target::abi::{LayoutS, Primitive, TagEncoding, VariantIdx, Variants};
+use rustc_target::abi::{LayoutS, Primitive, TagEncoding, Variants};
use std::cmp::Ordering;
use std::fmt;
use std::rc::Rc;
@@ -39,10 +39,10 @@ use crate::html::{highlight, static_files};
use askama::Template;
use itertools::Itertools;
-const ITEM_TABLE_OPEN: &str = "<div class=\"item-table\">";
-const ITEM_TABLE_CLOSE: &str = "</div>";
-const ITEM_TABLE_ROW_OPEN: &str = "<div class=\"item-row\">";
-const ITEM_TABLE_ROW_CLOSE: &str = "</div>";
+const ITEM_TABLE_OPEN: &str = "<ul class=\"item-table\">";
+const ITEM_TABLE_CLOSE: &str = "</ul>";
+const ITEM_TABLE_ROW_OPEN: &str = "<li>";
+const ITEM_TABLE_ROW_CLOSE: &str = "</li>";
// A component in a `use` path, like `string` in std::string::ToString
struct PathComponent {
@@ -338,14 +338,14 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
match *src {
Some(src) => write!(
w,
- "<div class=\"item-left\"><code>{}extern crate {} as {};",
+ "<div class=\"item-name\"><code>{}extern crate {} as {};",
visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
anchor(myitem.item_id.expect_def_id(), src, cx),
myitem.name.unwrap(),
),
None => write!(
w,
- "<div class=\"item-left\"><code>{}extern crate {};",
+ "<div class=\"item-name\"><code>{}extern crate {};",
visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx),
),
@@ -355,7 +355,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
}
clean::ImportItem(ref import) => {
- let (stab, stab_tags) = if let Some(import_def_id) = import.source.did {
+ let stab_tags = if let Some(import_def_id) = import.source.did {
let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id);
let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs));
@@ -367,15 +367,12 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
..myitem.clone()
};
- let stab = import_item.stability_class(cx.tcx());
let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx()));
- (stab, stab_tags)
+ stab_tags
} else {
- (None, None)
+ None
};
- let add = if stab.is_some() { " " } else { "" };
-
w.write_str(ITEM_TABLE_ROW_OPEN);
let id = match import.kind {
clean::ImportKind::Simple(s) => {
@@ -387,15 +384,14 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() {
("", "")
} else {
- ("<div class=\"item-right docblock-short\">", "</div>")
+ ("<div class=\"desc docblock-short\">", "</div>")
};
write!(
w,
- "<div class=\"item-left {stab}{add}import-item\"{id}>\
+ "<div class=\"item-name\"{id}>\
<code>{vis}{imp}</code>\
</div>\
{stab_tags_before}{stab_tags}{stab_tags_after}",
- stab = stab.unwrap_or_default(),
vis = visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
imp = import.print(cx),
);
@@ -417,9 +413,6 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
_ => "",
};
- let stab = myitem.stability_class(cx.tcx());
- let add = if stab.is_some() { " " } else { "" };
-
let visibility_emoji = match myitem.visibility(tcx) {
Some(ty::Visibility::Restricted(_)) => {
"<span title=\"Restricted Visibility\">&nbsp;🔒</span> "
@@ -433,11 +426,11 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
let (docs_before, docs_after) = if docs.is_empty() {
("", "")
} else {
- ("<div class=\"item-right docblock-short\">", "</div>")
+ ("<div class=\"desc docblock-short\">", "</div>")
};
write!(
w,
- "<div class=\"item-left {stab}{add}module-item\">\
+ "<div class=\"item-name\">\
<a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\
{visibility_emoji}\
{unsafety_flag}\
@@ -448,11 +441,9 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
visibility_emoji = visibility_emoji,
stab_tags = extra_info_tags(myitem, item, cx.tcx()),
class = myitem.type_(),
- add = add,
- stab = stab.unwrap_or_default(),
unsafety_flag = unsafety_flag,
href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
- title = [full_path(cx, myitem), myitem.type_().to_string()]
+ title = [myitem.type_().to_string(), full_path(cx, myitem)]
.iter()
.filter_map(|s| if !s.is_empty() { Some(s.as_str()) } else { None })
.collect::<Vec<_>>()
@@ -530,26 +521,24 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
let notable_traits =
f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx));
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
- w.reserve(header_len);
- write!(
- w,
- "{vis}{constness}{asyncness}{unsafety}{abi}fn \
- {name}{generics}{decl}{notable_traits}{where_clause}",
- vis = visibility,
- constness = constness,
- asyncness = asyncness,
- unsafety = unsafety,
- abi = abi,
- name = name,
- generics = f.generics.print(cx),
- where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
- decl = f.decl.full_print(header_len, 0, cx),
- notable_traits = notable_traits.unwrap_or_default(),
- );
- });
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ w.reserve(header_len);
+ write!(
+ w,
+ "{vis}{constness}{asyncness}{unsafety}{abi}fn \
+ {name}{generics}{decl}{notable_traits}{where_clause}",
+ vis = visibility,
+ constness = constness,
+ asyncness = asyncness,
+ unsafety = unsafety,
+ abi = abi,
+ name = name,
+ generics = f.generics.print(cx),
+ where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
+ decl = f.decl.full_print(header_len, 0, cx),
+ notable_traits = notable_traits.unwrap_or_default(),
+ );
});
document(w, cx, it, None, HeadingOffset::H2);
}
@@ -569,145 +558,140 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone();
// Output the trait definition
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
- write!(
- w,
- "{}{}{}trait {}{}{}",
- visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
- t.unsafety(tcx).print_with_space(),
- if t.is_auto(tcx) { "auto " } else { "" },
- it.name.unwrap(),
- t.generics.print(cx),
- bounds
- );
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ write!(
+ w,
+ "{}{}{}trait {}{}{}",
+ visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+ t.unsafety(tcx).print_with_space(),
+ if t.is_auto(tcx) { "auto " } else { "" },
+ it.name.unwrap(),
+ t.generics.print(cx),
+ bounds
+ );
- if !t.generics.where_predicates.is_empty() {
- write!(w, "{}", print_where_clause(&t.generics, cx, 0, Ending::Newline));
- } else {
- w.write_str(" ");
- }
+ if !t.generics.where_predicates.is_empty() {
+ write!(w, "{}", print_where_clause(&t.generics, cx, 0, Ending::Newline));
+ } else {
+ w.write_str(" ");
+ }
- if t.items.is_empty() {
- w.write_str("{ }");
- } else {
- // FIXME: we should be using a derived_id for the Anchors here
- w.write_str("{\n");
- let mut toggle = false;
-
- // If there are too many associated types, hide _everything_
- if should_hide_fields(count_types) {
- toggle = true;
- toggle_open(
- w,
- format_args!(
- "{} associated items",
- count_types + count_consts + count_methods
- ),
- );
- }
- for types in [&required_types, &provided_types] {
- for t in types {
- render_assoc_item(
- w,
- t,
- AssocItemLink::Anchor(None),
- ItemType::Trait,
- cx,
- RenderMode::Normal,
- );
- w.write_str(";\n");
- }
- }
- // If there are too many associated constants, hide everything after them
- // We also do this if the types + consts is large because otherwise we could
- // render a bunch of types and _then_ a bunch of consts just because both were
- // _just_ under the limit
- if !toggle && should_hide_fields(count_types + count_consts) {
- toggle = true;
- toggle_open(
- w,
- format_args!(
- "{} associated constant{} and {} method{}",
- count_consts,
- pluralize(count_consts),
- count_methods,
- pluralize(count_methods),
- ),
- );
- }
- if count_types != 0 && (count_consts != 0 || count_methods != 0) {
- w.write_str("\n");
- }
- for consts in [&required_consts, &provided_consts] {
- for c in consts {
- render_assoc_item(
- w,
- c,
- AssocItemLink::Anchor(None),
- ItemType::Trait,
- cx,
- RenderMode::Normal,
- );
- w.write_str(";\n");
- }
- }
- if !toggle && should_hide_fields(count_methods) {
- toggle = true;
- toggle_open(w, format_args!("{} methods", count_methods));
- }
- if count_consts != 0 && count_methods != 0 {
- w.write_str("\n");
- }
- for (pos, m) in required_methods.iter().enumerate() {
+ if t.items.is_empty() {
+ w.write_str("{ }");
+ } else {
+ // FIXME: we should be using a derived_id for the Anchors here
+ w.write_str("{\n");
+ let mut toggle = false;
+
+ // If there are too many associated types, hide _everything_
+ if should_hide_fields(count_types) {
+ toggle = true;
+ toggle_open(
+ w,
+ format_args!("{} associated items", count_types + count_consts + count_methods),
+ );
+ }
+ for types in [&required_types, &provided_types] {
+ for t in types {
render_assoc_item(
w,
- m,
+ t,
AssocItemLink::Anchor(None),
ItemType::Trait,
cx,
RenderMode::Normal,
);
w.write_str(";\n");
-
- if pos < required_methods.len() - 1 {
- w.write_str("<span class=\"item-spacer\"></span>");
- }
- }
- if !required_methods.is_empty() && !provided_methods.is_empty() {
- w.write_str("\n");
}
- for (pos, m) in provided_methods.iter().enumerate() {
+ }
+ // If there are too many associated constants, hide everything after them
+ // We also do this if the types + consts is large because otherwise we could
+ // render a bunch of types and _then_ a bunch of consts just because both were
+ // _just_ under the limit
+ if !toggle && should_hide_fields(count_types + count_consts) {
+ toggle = true;
+ toggle_open(
+ w,
+ format_args!(
+ "{} associated constant{} and {} method{}",
+ count_consts,
+ pluralize(count_consts),
+ count_methods,
+ pluralize(count_methods),
+ ),
+ );
+ }
+ if count_types != 0 && (count_consts != 0 || count_methods != 0) {
+ w.write_str("\n");
+ }
+ for consts in [&required_consts, &provided_consts] {
+ for c in consts {
render_assoc_item(
w,
- m,
+ c,
AssocItemLink::Anchor(None),
ItemType::Trait,
cx,
RenderMode::Normal,
);
- match *m.kind {
- clean::MethodItem(ref inner, _)
- if !inner.generics.where_predicates.is_empty() =>
- {
- w.write_str(",\n { ... }\n");
- }
- _ => {
- w.write_str(" { ... }\n");
- }
- }
+ w.write_str(";\n");
+ }
+ }
+ if !toggle && should_hide_fields(count_methods) {
+ toggle = true;
+ toggle_open(w, format_args!("{} methods", count_methods));
+ }
+ if count_consts != 0 && count_methods != 0 {
+ w.write_str("\n");
+ }
- if pos < provided_methods.len() - 1 {
- w.write_str("<span class=\"item-spacer\"></span>");
- }
+ if !required_methods.is_empty() {
+ write!(w, " // Required method{}\n", pluralize(required_methods.len()));
+ }
+ for (pos, m) in required_methods.iter().enumerate() {
+ render_assoc_item(
+ w,
+ m,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
+ w.write_str(";\n");
+
+ if pos < required_methods.len() - 1 {
+ w.write_str("<span class=\"item-spacer\"></span>");
}
- if toggle {
- toggle_close(w);
+ }
+ if !required_methods.is_empty() && !provided_methods.is_empty() {
+ w.write_str("\n");
+ }
+
+ if !provided_methods.is_empty() {
+ write!(w, " // Provided method{}\n", pluralize(provided_methods.len()));
+ }
+ for (pos, m) in provided_methods.iter().enumerate() {
+ render_assoc_item(
+ w,
+ m,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
+
+ w.write_str(" { ... }\n");
+
+ if pos < provided_methods.len() - 1 {
+ w.write_str("<span class=\"item-spacer\"></span>");
}
- w.write_str("}");
}
- });
+ if toggle {
+ toggle_close(w);
+ }
+ w.write_str("}");
+ }
});
// Trait documentation
@@ -735,7 +719,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
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);
+ write!(w, "<section id=\"{}\" class=\"method\">", id);
render_rightside(w, cx, m, t, RenderMode::Normal);
write!(w, "<h4 class=\"code-header\">");
render_assoc_item(
@@ -1050,18 +1034,16 @@ 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, |w| {
- render_attributes_in_pre(w, it, "");
- write!(
- w,
- "trait {}{}{} = {};",
- it.name.unwrap(),
- t.generics.print(cx),
- print_where_clause(&t.generics, cx, 0, Ending::Newline),
- bounds(&t.bounds, true, cx)
- );
- });
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ write!(
+ w,
+ "trait {}{}{} = {};",
+ it.name.unwrap(),
+ t.generics.print(cx),
+ print_where_clause(&t.generics, cx, 0, Ending::Newline),
+ bounds(&t.bounds, true, cx)
+ );
});
document(w, cx, it, None, HeadingOffset::H2);
@@ -1074,18 +1056,16 @@ 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, |w| {
- render_attributes_in_pre(w, it, "");
- write!(
- w,
- "type {}{}{where_clause} = impl {bounds};",
- it.name.unwrap(),
- t.generics.print(cx),
- where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
- bounds = bounds(&t.bounds, false, cx),
- );
- });
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ write!(
+ w,
+ "type {}{}{where_clause} = impl {bounds};",
+ it.name.unwrap(),
+ t.generics.print(cx),
+ where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
+ bounds = bounds(&t.bounds, false, cx),
+ );
});
document(w, cx, it, None, HeadingOffset::H2);
@@ -1101,10 +1081,10 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
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!(
w,
- "type {}{}{where_clause} = {type_};",
+ "{}type {}{}{where_clause} = {type_};",
+ visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
it.name.unwrap(),
t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
@@ -1113,7 +1093,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
});
}
- wrap_into_item_decl(w, |w| write_content(w, cx, it, t));
+ write_content(w, cx, it, t);
document(w, cx, it, None, HeadingOffset::H2);
@@ -1127,11 +1107,9 @@ 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, |w| {
- render_attributes_in_pre(w, it, "");
- render_union(w, it, Some(&s.generics), &s.fields, "", cx);
- });
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ render_union(w, it, Some(&s.generics), &s.fields, cx);
});
document(w, cx, it, None, HeadingOffset::H2);
@@ -1160,13 +1138,11 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean:
<a href=\"#{id}\" class=\"anchor field\">§</a>\
<code>{name}: {ty}</code>\
</span>",
- id = id,
- name = name,
shortty = ItemType::StructField,
ty = ty.print(cx),
);
if let Some(stability_class) = field.stability_class(cx.tcx()) {
- write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
+ write!(w, "<span class=\"stab {stability_class}\"></span>");
}
document(w, cx, field, Some(it), HeadingOffset::H3);
}
@@ -1179,7 +1155,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean:
fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item]) {
for (i, ty) in s.iter().enumerate() {
if i > 0 {
- w.write_str(",&nbsp;");
+ w.write_str(", ");
}
match *ty.kind {
clean::StrippedItem(box clean::StructFieldItem(_)) => w.write_str("_"),
@@ -1192,60 +1168,58 @@ fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item]
fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) {
let tcx = cx.tcx();
let count_variants = e.variants().count();
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
- write!(
- w,
- "{}enum {}{}",
- visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
- it.name.unwrap(),
- e.generics.print(cx),
- );
- if !print_where_clause_and_check(w, &e.generics, cx) {
- // If there wasn't a `where` clause, we add a whitespace.
- w.write_str(" ");
- }
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ write!(
+ w,
+ "{}enum {}{}",
+ visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+ it.name.unwrap(),
+ e.generics.print(cx),
+ );
+ if !print_where_clause_and_check(w, &e.generics, cx) {
+ // If there wasn't a `where` clause, we add a whitespace.
+ w.write_str(" ");
+ }
- let variants_stripped = e.has_stripped_entries();
- if count_variants == 0 && !variants_stripped {
- w.write_str("{}");
- } else {
- w.write_str("{\n");
- let toggle = should_hide_fields(count_variants);
- if toggle {
- toggle_open(w, format_args!("{} variants", count_variants));
- }
- for v in e.variants() {
- w.write_str(" ");
- let name = v.name.unwrap();
- match *v.kind {
- // 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::VariantKind::Struct(ref s) => {
- render_struct(w, v, None, None, &s.fields, " ", false, cx);
- }
- },
- _ => unreachable!(),
- }
- w.write_str(",\n");
+ let variants_stripped = e.has_stripped_entries();
+ if count_variants == 0 && !variants_stripped {
+ w.write_str("{}");
+ } else {
+ w.write_str("{\n");
+ let toggle = should_hide_fields(count_variants);
+ if toggle {
+ toggle_open(w, format_args!("{} variants", count_variants));
+ }
+ for v in e.variants() {
+ w.write_str(" ");
+ let name = v.name.unwrap();
+ match *v.kind {
+ // 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::VariantKind::Struct(ref s) => {
+ render_struct(w, v, None, None, &s.fields, " ", false, cx);
+ }
+ },
+ _ => unreachable!(),
}
+ w.write_str(",\n");
+ }
- if variants_stripped {
- w.write_str(" // some variants omitted\n");
- }
- if toggle {
- toggle_close(w);
- }
- w.write_str("}");
+ if variants_stripped {
+ w.write_str(" // some variants omitted\n");
}
- });
+ if toggle {
+ toggle_close(w);
+ }
+ w.write_str("}");
+ }
});
document(w, cx, it, None, HeadingOffset::H2);
@@ -1266,7 +1240,6 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
w,
"<section id=\"{id}\" class=\"variant\">\
<a href=\"#{id}\" class=\"anchor\">§</a>",
- id = id,
);
render_stability_since_raw_with_extra(
w,
@@ -1304,8 +1277,11 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
if let Some((heading, fields)) = heading_and_fields {
let variant_id =
cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap()));
- write!(w, "<div class=\"sub-variant\" id=\"{id}\">", id = variant_id);
- write!(w, "<h4>{heading}</h4>", heading = heading);
+ write!(
+ w,
+ "<div class=\"sub-variant\" id=\"{variant_id}\">\
+ <h4>{heading}</h4>",
+ );
document_non_exhaustive(w, variant);
for field in fields {
match *field.kind {
@@ -1321,9 +1297,8 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
"<div class=\"sub-variant-field\">\
<span id=\"{id}\" class=\"small-section-header\">\
<a href=\"#{id}\" class=\"anchor field\">§</a>\
- <code>{f}:&nbsp;{t}</code>\
+ <code>{f}: {t}</code>\
</span>",
- id = id,
f = field.name.unwrap(),
t = ty.print(cx)
);
@@ -1346,38 +1321,30 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
}
fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
- wrap_into_item_decl(w, |w| {
- highlight::render_macro_with_highlighting(&t.source, w);
- });
+ highlight::render_item_decl_with_highlighting(&t.source, w);
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
- wrap_into_item_decl(w, |w| {
+ wrap_item(w, |w| {
let name = it.name.expect("proc-macros always have names");
match m.kind {
MacroKind::Bang => {
- wrap_item(w, |w| {
- write!(w, "{}!() {{ /* proc-macro */ }}", name);
- });
+ write!(w, "{}!() {{ /* proc-macro */ }}", name);
}
MacroKind::Attr => {
- wrap_item(w, |w| {
- write!(w, "#[{}]", name);
- });
+ write!(w, "#[{}]", name);
}
MacroKind::Derive => {
- wrap_item(w, |w| {
- write!(w, "#[derive({})]", name);
- if !m.helpers.is_empty() {
- w.push_str("\n{\n");
- w.push_str(" // Attributes available to this derive:\n");
- for attr in &m.helpers {
- writeln!(w, " #[{}]", attr);
- }
- w.push_str("}\n");
+ write!(w, "#[derive({})]", name);
+ if !m.helpers.is_empty() {
+ w.push_str("\n{\n");
+ w.push_str(" // Attributes available to this derive:\n");
+ for attr in &m.helpers {
+ writeln!(w, " #[{}]", attr);
}
- });
+ w.push_str("}\n");
+ }
}
}
});
@@ -1400,61 +1367,57 @@ 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, |w| {
- let tcx = cx.tcx();
- render_attributes_in_code(w, it);
+ wrap_item(w, |w| {
+ let tcx = cx.tcx();
+ render_attributes_in_code(w, it);
- write!(
- w,
- "{vis}const {name}: {typ}",
- vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
- name = it.name.unwrap(),
- typ = c.type_.print(cx),
- );
+ write!(
+ w,
+ "{vis}const {name}: {typ}",
+ vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+ name = it.name.unwrap(),
+ typ = c.type_.print(cx),
+ );
- // FIXME: The code below now prints
- // ` = _; // 100i32`
- // if the expression is
- // `50 + 50`
- // which looks just wrong.
- // Should we print
- // ` = 100i32;`
- // instead?
-
- let value = c.value(tcx);
- let is_literal = c.is_literal(tcx);
- let expr = c.expr(tcx);
- if value.is_some() || is_literal {
- write!(w, " = {expr};", expr = Escape(&expr));
- } else {
- w.write_str(";");
- }
+ // FIXME: The code below now prints
+ // ` = _; // 100i32`
+ // if the expression is
+ // `50 + 50`
+ // which looks just wrong.
+ // Should we print
+ // ` = 100i32;`
+ // instead?
+
+ let value = c.value(tcx);
+ let is_literal = c.is_literal(tcx);
+ let expr = c.expr(tcx);
+ if value.is_some() || is_literal {
+ write!(w, " = {expr};", expr = Escape(&expr));
+ } else {
+ w.write_str(";");
+ }
- if !is_literal {
- if let Some(value) = &value {
- let value_lowercase = value.to_lowercase();
- let expr_lowercase = expr.to_lowercase();
+ if !is_literal {
+ if let Some(value) = &value {
+ let value_lowercase = value.to_lowercase();
+ let expr_lowercase = expr.to_lowercase();
- if value_lowercase != expr_lowercase
- && value_lowercase.trim_end_matches("i32") != expr_lowercase
- {
- write!(w, " // {value}", value = Escape(value));
- }
+ if value_lowercase != expr_lowercase
+ && value_lowercase.trim_end_matches("i32") != expr_lowercase
+ {
+ write!(w, " // {value}", value = Escape(value));
}
}
- });
+ }
});
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
- wrap_into_item_decl(w, |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);
- });
+ wrap_item(w, |w| {
+ render_attributes_in_code(w, it);
+ render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
});
document(w, cx, it, None, HeadingOffset::H2);
@@ -1486,11 +1449,9 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
w,
"<span id=\"{id}\" class=\"{item_type} small-section-header\">\
<a href=\"#{id}\" class=\"anchor field\">§</a>\
- <code>{name}: {ty}</code>\
+ <code>{field_name}: {ty}</code>\
</span>",
item_type = ItemType::StructField,
- id = id,
- name = field_name,
ty = ty.print(cx)
);
document(w, cx, field, Some(it), HeadingOffset::H3);
@@ -1503,34 +1464,30 @@ 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, |w| {
- render_attributes_in_code(w, it);
- write!(
- w,
- "{vis}static {mutability}{name}: {typ}",
- vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
- mutability = s.mutability.print_with_space(),
- name = it.name.unwrap(),
- typ = s.type_.print(cx)
- );
- });
+ wrap_item(w, |w| {
+ render_attributes_in_code(w, it);
+ write!(
+ w,
+ "{vis}static {mutability}{name}: {typ}",
+ vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
+ mutability = s.mutability.print_with_space(),
+ name = it.name.unwrap(),
+ typ = s.type_.print(cx)
+ );
});
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- w.write_str("extern {\n");
- render_attributes_in_code(w, it);
- write!(
- w,
- " {}type {};\n}}",
- visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
- it.name.unwrap(),
- );
- });
+ wrap_item(w, |w| {
+ w.write_str("extern {\n");
+ render_attributes_in_code(w, it);
+ write!(
+ w,
+ " {}type {};\n}}",
+ visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
+ it.name.unwrap(),
+ );
});
document(w, cx, it, None, HeadingOffset::H2);
@@ -1609,20 +1566,11 @@ fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>)
bounds
}
-fn wrap_into_item_decl<F>(w: &mut Buffer, f: F)
-where
- F: FnOnce(&mut Buffer),
-{
- w.write_str("<div class=\"item-decl\">");
- f(w);
- w.write_str("</div>")
-}
-
fn wrap_item<F>(w: &mut Buffer, f: F)
where
F: FnOnce(&mut Buffer),
{
- w.write_str(r#"<pre class="rust"><code>"#);
+ w.write_str(r#"<pre class="rust item-decl"><code>"#);
f(w);
w.write_str("</code></pre>");
}
@@ -1677,7 +1625,6 @@ fn render_union(
it: &clean::Item,
g: Option<&clean::Generics>,
fields: &[clean::Item],
- tab: &str,
cx: &Context<'_>,
) {
let tcx = cx.tcx();
@@ -1700,7 +1647,7 @@ fn render_union(
w.write_str(" ");
}
- write!(w, "{{\n{}", tab);
+ write!(w, "{{\n");
let count_fields =
fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
let toggle = should_hide_fields(count_fields);
@@ -1712,17 +1659,16 @@ fn render_union(
if let clean::StructFieldItem(ref ty) = *field.kind {
write!(
w,
- " {}{}: {},\n{}",
+ " {}{}: {},\n",
visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
field.name.unwrap(),
- ty.print(cx),
- tab
+ ty.print(cx)
);
}
}
if it.has_stripped_entries().unwrap() {
- write!(w, " /* private fields */\n{}", tab);
+ write!(w, " /* private fields */\n");
}
if toggle {
toggle_close(w);
@@ -1887,12 +1833,12 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
}
fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
- fn write_size_of_layout(w: &mut Buffer, layout: &LayoutS<VariantIdx>, tag_size: u64) {
+ fn write_size_of_layout(w: &mut Buffer, layout: &LayoutS, tag_size: u64) {
if layout.abi.is_unsized() {
write!(w, "(unsized)");
} else {
- let bytes = layout.size.bytes() - tag_size;
- write!(w, "{size} byte{pl}", size = bytes, pl = if bytes == 1 { "" } else { "s" },);
+ let size = layout.size.bytes() - tag_size;
+ write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" },);
}
}
@@ -1909,7 +1855,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
let tcx = cx.tcx();
let param_env = tcx.param_env(ty_def_id);
- let ty = tcx.type_of(ty_def_id);
+ let ty = tcx.type_of(ty_def_id).subst_identity();
match tcx.layout_of(param_env.and(ty)) {
Ok(ty_layout) => {
writeln!(
@@ -1947,7 +1893,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
for (index, layout) in variants.iter_enumerated() {
let name = adt.variant(index).name;
- write!(w, "<li><code>{name}</code>: ", name = name);
+ write!(w, "<li><code>{name}</code>: ");
write_size_of_layout(w, layout, tag_size);
writeln!(w, "</li>");
}
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 5b0caac09..090ea2cb1 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -236,7 +236,16 @@ pub(crate) fn build_index<'tcx>(
crate_data.serialize_field("doc", &self.doc)?;
crate_data.serialize_field(
"t",
- &self.items.iter().map(|item| &item.ty).collect::<Vec<_>>(),
+ &self
+ .items
+ .iter()
+ .map(|item| {
+ let n = item.ty as u8;
+ let c = char::try_from(n + b'A').expect("item types must fit in ASCII");
+ assert!(c <= 'z', "item types must fit within ASCII printables");
+ c
+ })
+ .collect::<String>(),
)?;
crate_data.serialize_field(
"n",
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index bc8badad3..54749e9a3 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
-use super::{collect_paths_for_type, ensure_trailing_slash, Context, BASIC_KEYWORDS};
+use super::{collect_paths_for_type, ensure_trailing_slash, Context};
use crate::clean::Crate;
use crate::config::{EmitType, RenderOptions};
use crate::docfs::PathError;
@@ -138,7 +138,7 @@ pub(super) fn write_shared(
Ok((ret, krates))
}
- /// Read a file and return all lines that match the <code>"{crate}":{data},\</code> format,
+ /// Read a file and return all lines that match the <code>"{crate}":{data},\ </code> format,
/// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
///
/// This forms the payload of files that look like this:
@@ -340,7 +340,6 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
root_path: "./",
static_root_path: shared.static_root_path.as_deref(),
description: "List of crates",
- keywords: BASIC_KEYWORDS,
resource_suffix: &shared.resource_suffix,
};
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 799c497d1..2c90bf4fa 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -4,7 +4,7 @@ use crate::error::Error;
use crate::html::format::Buffer;
use crate::html::highlight;
use crate::html::layout;
-use crate::html::render::{Context, BASIC_KEYWORDS};
+use crate::html::render::Context;
use crate::visit::DocVisitor;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -228,7 +228,6 @@ impl SourceCollector<'_, '_> {
root_path: &root_path,
static_root_path: shared.static_root_path.as_deref(),
description: &desc,
- keywords: BASIC_KEYWORDS,
resource_suffix: &shared.resource_suffix,
};
let v = layout::render(
diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js
index fcd925bb3..1a34530c2 100644
--- a/src/librustdoc/html/static/.eslintrc.js
+++ b/src/librustdoc/html/static/.eslintrc.js
@@ -90,7 +90,6 @@ module.exports = {
"no-return-assign": "error",
"no-script-url": "error",
"no-sequences": "error",
- "no-throw-literal": "error",
"no-div-regex": "error",
}
};
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index a93f60da2..95528e70e 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1,3 +1,11 @@
+/* When static files are updated, their suffixes need to be updated.
+ 1. In the top directory run:
+ ./x.py doc --stage 1 library/core
+ 2. Find the directory containing files named with updated suffixes:
+ find build -path '*'/stage1-std/'*'/static.files
+ 3. Copy the filenames with updated suffixes from the directory.
+*/
+
/* See FiraSans-LICENSE.txt for the Fira Sans license. */
@font-face {
font-family: 'Fira Sans';
@@ -22,7 +30,7 @@
font-style: normal;
font-weight: 400;
src: local('Source Serif 4'),
- url("SourceSerif4-Regular-1f7d512b176f0f72.ttf.woff2") format("woff2");
+ url("SourceSerif4-Regular-46f98efaafac5295.ttf.woff2") format("woff2");
font-display: swap;
}
@font-face {
@@ -30,7 +38,7 @@
font-style: italic;
font-weight: 400;
src: local('Source Serif 4 Italic'),
- url("SourceSerif4-It-d034fe4ef9d0fa00.ttf.woff2") format("woff2");
+ url("SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2") format("woff2");
font-display: swap;
}
@font-face {
@@ -38,7 +46,7 @@
font-style: normal;
font-weight: 700;
src: local('Source Serif 4 Bold'),
- url("SourceSerif4-Bold-124a1ca42af929b6.ttf.woff2") format("woff2");
+ url("SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2") format("woff2");
font-display: swap;
}
@@ -166,6 +174,14 @@ h1, h2, h3, h4 {
.top-doc .docblock > h4 {
border-bottom: 1px solid var(--headings-border-bottom-color);
}
+/* while line-height 1.5 is required for any "block of text",
+ which WCAG defines as more than one sentence, it looks weird for
+ very large main headers */
+h1, h2 {
+ line-height: 1.25;
+ padding-top: 3px;
+ padding-bottom: 9px;
+}
h3.code-header {
font-size: 1.125rem; /* 18px */
}
@@ -176,6 +192,7 @@ h4.code-header {
font-weight: 600;
margin: 0;
padding: 0;
+ white-space: pre-wrap;
}
#crate-search,
@@ -184,7 +201,7 @@ h1, h2, h3, h4, h5, h6,
.mobile-topbar,
.search-input,
.search-results .result-name,
-.item-left > a,
+.item-name > a,
.out-of-band,
span.since,
a.srclink,
@@ -335,7 +352,7 @@ pre {
padding: 14px;
line-height: 1.5; /* https://github.com/rust-lang/rust/issues/105906 */
}
-.item-decl pre {
+pre.item-decl {
overflow-x: auto;
}
/* This rule allows to have scrolling on the X axis. */
@@ -533,7 +550,7 @@ ul.block, .block li {
.rustdoc .example-wrap > pre {
margin: 0;
flex-grow: 1;
- overflow-x: auto;
+ overflow: auto hidden;
}
.rustdoc .example-wrap > pre.example-line-numbers,
@@ -634,6 +651,7 @@ pre, .rustdoc.source .example-wrap {
.fn .where,
.where.fmt-newline {
display: block;
+ white-space: pre-wrap;
font-size: 0.875rem;
}
@@ -697,8 +715,8 @@ h2.small-section-header > .anchor {
.main-heading a:hover,
.example-wrap > pre.rust a:hover,
.all-items a:hover,
-.docblock a:not(.test-arrow):not(.scrape-help):hover,
-.docblock-short a:not(.test-arrow):not(.scrape-help):hover,
+.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,
+.docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,
.item-info a {
text-decoration: underline;
}
@@ -732,14 +750,16 @@ table,
.item-table {
display: table;
+ padding: 0;
+ margin: 0;
}
-.item-row {
+.item-table > li {
display: table-row;
}
-.item-left, .item-right {
+.item-table > li > div {
display: table-cell;
}
-.item-left {
+.item-table > li > .item-name {
padding-right: 1.25rem;
}
@@ -806,8 +826,11 @@ so that we can apply CSS-filters to change the arrow color in themes */
background-repeat: no-repeat;
background-size: 20px;
background-position: calc(100% - 2px) 56%;
- /* image is black color */
- background-image: url("down-arrow-927217e04c7463ac.svg");
+ /* down arrow (image is black color) */
+ background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
+ width="128" height="128" viewBox="-30 -20 176 176"><path d="M111,40.5L64,87.499L17,40.5" \
+ fill="none" stroke="black" strike-linecap="square" stroke-miterlimit="10" stroke-width="12"/> \
+ </svg>');
/* changes the arrow image color */
filter: var(--crate-search-div-filter);
}
@@ -941,7 +964,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
padding: 3px;
margin-bottom: 5px;
}
-.item-left .stab {
+.item-name .stab {
margin-left: 0.3125em;
}
.stab {
@@ -977,11 +1000,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
0 -1px 0 black;
}
-.module-item.unstable,
-.import-item.unstable {
- opacity: 0.65;
-}
-
.since {
font-weight: normal;
font-size: initial;
@@ -1093,44 +1111,8 @@ pre.rust .doccomment {
display: block;
left: -25px;
top: 5px;
-}
-
-.example-wrap .tooltip:hover::after {
- padding: 5px 3px 3px 3px;
- border-radius: 6px;
- margin-left: 5px;
- font-size: 1rem;
- border: 1px solid var(--border-color);
- position: absolute;
- width: max-content;
- top: -2px;
- z-index: 1;
- background-color: var(--tooltip-background-color);
- color: var(--tooltip-color);
-}
-
-.example-wrap .tooltip:hover::before {
- content: " ";
- position: absolute;
- top: 50%;
- left: 16px;
- margin-top: -5px;
- z-index: 1;
- border: 5px solid transparent;
- border-right-color: var(--tooltip-background-color);
-}
-
-.example-wrap.ignore .tooltip:hover::after {
- content: "This example is not tested";
-}
-.example-wrap.compile_fail .tooltip:hover::after {
- content: "This example deliberately fails to compile";
-}
-.example-wrap.should_panic .tooltip:hover::after {
- content: "This example panics";
-}
-.example-wrap.edition .tooltip:hover::after {
- content: "This code runs with edition " attr(data-edition);
+ margin: 0;
+ line-height: 1;
}
.example-wrap.compile_fail .tooltip,
@@ -1168,6 +1150,7 @@ a.test-arrow:hover {
.item-spacer {
width: 100%;
height: 12px;
+ display: block;
}
.out-of-band > span.since {
@@ -1196,7 +1179,7 @@ a.test-arrow:hover {
border-right: 3px solid var(--target-border-color);
}
-.notable-traits {
+.code-header a.tooltip {
color: inherit;
margin-right: 15px;
position: relative;
@@ -1205,7 +1188,7 @@ a.test-arrow:hover {
/* placeholder thunk so that the mouse can easily travel from "(i)" to popover
the resulting "hover tunnel" is a stepped triangle, approximating
https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown */
-.notable-traits:hover::after {
+a.tooltip:hover::after {
position: absolute;
top: calc(100% - 10px);
left: -15px;
@@ -1214,11 +1197,11 @@ a.test-arrow:hover {
content: "\00a0";
}
-.notable .content {
+.popover.tooltip .content {
margin: 0.25em 0.5em;
}
-.notable .content pre, .notable .content code {
+.popover.tooltip .content pre, .popover.tooltip .content code {
background: transparent;
margin: 0;
padding: 0;
@@ -1226,7 +1209,7 @@ a.test-arrow:hover {
white-space: pre-wrap;
}
-.notable .content > h3:first-child {
+.popover.tooltip .content > h3:first-child {
margin: 0 0 5px 0;
}
@@ -1263,12 +1246,25 @@ a.test-arrow:hover {
line-height: 1.5;
color: inherit;
}
+#search-tabs button:not(.selected) {
+ background-color: var(--search-tab-button-not-selected-background);
+ border-top-color: var(--search-tab-button-not-selected-border-top-color);
+}
+#search-tabs button:hover, #search-tabs button.selected {
+ background-color: var(--search-tab-button-selected-background);
+ border-top-color: var(--search-tab-button-selected-border-top-color);
+}
#search-tabs .count {
font-size: 1rem;
color: var(--search-tab-title-count-color);
}
+#search .error code {
+ border-radius: 3px;
+ background-color: var(--search-error-code-background-color);
+}
+
#src-sidebar-toggle {
position: sticky;
top: 0;
@@ -1433,7 +1429,10 @@ details.toggle > summary.hideme > span {
}
details.toggle > summary::before {
- background: url("toggle-plus-1092eb4930d581b0.svg") no-repeat top left;
+ /* toggle plus */
+ background: url('data:image/svg+xml,<svg width="17" height="17" \
+shape-rendering="crispEdges" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg"><path \
+d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7M8.5 12V8.625v0V5"/></svg>') no-repeat top left;
content: "";
cursor: pointer;
width: 16px;
@@ -1511,7 +1510,10 @@ details.toggle[open] > summary.hideme > span {
}
details.toggle[open] > summary::before {
- background: url("toggle-minus-31bbd6e4c77f5c96.svg") no-repeat top left;
+ /* toggle minus */
+ background: url('data:image/svg+xml,<svg width="17" height="17" \
+shape-rendering="crispEdges" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg"><path \
+d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7"/></svg>') no-repeat top left;
}
details.toggle[open] > summary::after {
@@ -1700,7 +1702,7 @@ in storage.js
}
/* Display an alternating layout on tablets and phones */
- .item-table, .item-row, .item-left, .item-right,
+ .item-table, .item-row, .item-table > li, .item-table > li > div,
.search-results > a, .search-results > a > div {
display: block;
}
@@ -1709,7 +1711,7 @@ in storage.js
.search-results > a {
padding: 5px 0px;
}
- .search-results > a > div.desc, .item-right {
+ .search-results > a > div.desc, .item-table > li > div.desc {
padding-left: 2em;
}
@@ -1897,19 +1899,25 @@ in storage.js
right: 0.25em;
}
-.scraped-example:not(.expanded) .code-wrapper:before,
-.scraped-example:not(.expanded) .code-wrapper:after {
+.scraped-example:not(.expanded) .code-wrapper::before,
+.scraped-example:not(.expanded) .code-wrapper::after {
content: " ";
width: 100%;
height: 5px;
position: absolute;
z-index: 1;
}
-.scraped-example:not(.expanded) .code-wrapper:before {
+.scraped-example:not(.expanded) .code-wrapper::before {
top: 0;
+ background: linear-gradient(to bottom,
+ var(--scrape-example-code-wrapper-background-start),
+ var(--scrape-example-code-wrapper-background-end));
}
-.scraped-example:not(.expanded) .code-wrapper:after {
+.scraped-example:not(.expanded) .code-wrapper::after {
bottom: 0;
+ background: linear-gradient(to top,
+ var(--scrape-example-code-wrapper-background-start),
+ var(--scrape-example-code-wrapper-background-end));
}
.scraped-example .code-wrapper .example-wrap {
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
index 4e9803fe2..920f45c4b 100644
--- a/src/librustdoc/html/static/css/settings.css
+++ b/src/librustdoc/html/static/css/settings.css
@@ -3,8 +3,7 @@
position: relative;
}
-.setting-line .radio-line input,
-.setting-line .settings-toggle input {
+.setting-radio input, .setting-check input {
margin-right: 0.3em;
height: 1.2rem;
width: 1.2rem;
@@ -14,21 +13,20 @@
-webkit-appearance: none;
cursor: pointer;
}
-.setting-line .radio-line input {
+.setting-radio input {
border-radius: 50%;
}
-.setting-line .settings-toggle input:checked {
+.setting-check 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 .settings-toggle span {
+.setting-radio span, .setting-check span {
padding-bottom: 1px;
}
-.radio-line .choice {
+.setting-radio {
margin-top: 0.1em;
margin-bottom: 0.1em;
min-width: 3.8em;
@@ -37,36 +35,32 @@
align-items: center;
cursor: pointer;
}
-.radio-line .choice + .choice {
+.setting-radio + .setting-radio {
margin-left: 0.5em;
}
-.settings-toggle {
- position: relative;
- width: 100%;
+.setting-check {
margin-right: 20px;
display: flex;
align-items: center;
cursor: pointer;
}
-.setting-line .radio-line input:checked {
+.setting-radio input:checked {
box-shadow: inset 0 0 0 3px var(--main-background-color);
background-color: var(--settings-input-color);
}
-.setting-line .settings-toggle input:checked {
+.setting-check input:checked {
background-color: var(--settings-input-color);
}
-.setting-line .radio-line input:focus,
-.setting-line .settings-toggle input:focus {
+.setting-radio input:focus, .setting-check input:focus {
box-shadow: 0 0 1px 1px var(--settings-input-color);
}
/* In here we combine both `:focus` and `:checked` properties. */
-.setting-line .radio-line input:checked:focus {
+.setting-radio input:checked:focus {
box-shadow: inset 0 0 0 3px var(--main-background-color),
0 0 2px 2px var(--settings-input-color);
}
-.setting-line .radio-line input:hover,
-.setting-line .settings-toggle input:hover {
+.setting-radio input:hover, .setting-check 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 979e7e0f9..90cf689ad 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -43,9 +43,14 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--search-result-link-focus-background-color: #3c3c3c;
--search-result-border-color: #aaa3;
--search-color: #fff;
+ --search-error-code-background-color: #4f4c4c;
--search-results-alias-color: #c5c5c5;
--search-results-grey-color: #999;
--search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: none;
+ --search-tab-button-not-selected-background: transparent !important;
+ --search-tab-button-selected-border-top-color: none;
+ --search-tab-button-selected-background: #141920 !important;
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ff7733;
@@ -70,8 +75,6 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
--target-background-color: rgba(255, 236, 164, 0.06);
--target-border-color: rgba(255, 180, 76, 0.85);
- --tooltip-background-color: #314559;
- --tooltip-color: #c5c5c5;
--kbd-color: #c5c5c5;
--kbd-background: #314559;
--kbd-box-shadow-color: #5c6773;
@@ -97,12 +100,13 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--scrape-example-help-color: #eee;
--scrape-example-help-hover-border-color: #fff;
--scrape-example-help-hover-color: #fff;
+ --scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1);
+ --scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
}
-h1, h2, h3, h4 {
- color: white;
-}
-h1 a {
+h1, h2, h3, h4,
+h1 a, .sidebar h2 a, .sidebar h3 a,
+#source-sidebar > .title {
color: #fff;
}
h4 {
@@ -112,24 +116,22 @@ h4 {
.docblock code {
color: #ffb454;
}
-.code-header {
- color: #e6e1cf;
-}
-.docblock pre > code, pre > code {
- color: #e6e1cf;
-}
-.item-info code {
- color: #e6e1cf;
-}
.docblock a > code {
color: #39AFD7 !important;
}
-pre, .rustdoc.source .example-wrap {
+.code-header,
+.docblock pre > code,
+pre, pre > code,
+.item-info code,
+.rustdoc.source .example-wrap {
color: #e6e1cf;
}
.sidebar .current,
-.sidebar a:hover {
+.sidebar a:hover,
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus,
+#source-sidebar div.files > a.selected {
color: #ffb44c;
}
@@ -143,15 +145,12 @@ pre, .rustdoc.source .example-wrap {
border-right: 1px solid #ffb44c;
}
-.search-results a:hover {
- color: #fff !important;
- background-color: #3c3c3c;
-}
-
+.search-results a:hover,
.search-results a:focus {
color: #fff !important;
background-color: #3c3c3c;
}
+
.search-results a {
color: #0096cf;
}
@@ -159,54 +158,22 @@ pre, .rustdoc.source .example-wrap {
color: #c5c5c5;
}
-.sidebar h2 a,
-.sidebar h3 a {
- color: white;
-}
-
.result-name .primitive > i, .result-name .keyword > i {
color: #788797;
}
#search-tabs > button.selected {
- background-color: #141920 !important;
border-bottom: 1px solid #ffb44c !important;
border-top: none;
}
-
#search-tabs > button:not(.selected) {
- background-color: transparent !important;
border: none;
+ background-color: transparent !important;
}
-
#search-tabs > button:hover {
border-bottom: 1px solid rgba(242, 151, 24, 0.3);
}
-/* 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 */
-#search-tabs > button:hover, #search-tabs > button.selected {}
-
#settings-menu > a img {
filter: invert(100);
}
-
-#source-sidebar > .title {
- color: #fff;
-}
-#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
-#source-sidebar div.files > a:focus, details.dir-entry summary:focus,
-#source-sidebar div.files > a.selected {
- color: #ffb44c;
-}
-
-.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 {
- background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
-}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index fb15863b0..e8cd06931 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -38,9 +38,14 @@
--search-result-link-focus-background-color: #616161;
--search-result-border-color: #aaa3;
--search-color: #111;
+ --search-error-code-background-color: #484848;
--search-results-alias-color: #fff;
--search-results-grey-color: #ccc;
--search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: #252525;
+ --search-tab-button-not-selected-background: #252525;
+ --search-tab-button-selected-border-top-color: #0089ff;
+ --search-tab-button-selected-background: #353535;
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ab8ac1;
@@ -65,8 +70,6 @@
--test-arrow-hover-background-color: #4e8bca;
--target-background-color: #494a3d;
--target-border-color: #bb7410;
- --tooltip-background-color: #000;
- --tooltip-color: #fff;
--kbd-color: #000;
--kbd-background: #fafbfc;
--kbd-box-shadow-color: #c6cbd1;
@@ -92,21 +95,6 @@
--scrape-example-help-color: #eee;
--scrape-example-help-hover-border-color: #fff;
--scrape-example-help-hover-color: #fff;
-}
-
-#search-tabs > button:not(.selected) {
- background-color: #252525;
- border-top-color: #252525;
-}
-
-#search-tabs > button:hover, #search-tabs > button.selected {
- border-top-color: #0089ff;
- background-color: #353535;
-}
-
-.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 {
- background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+ --scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
+ --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
}
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 053fa78d1..5e3f14e48 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -38,9 +38,14 @@
--search-result-link-focus-background-color: #ccc;
--search-result-border-color: #aaa3;
--search-color: #000;
+ --search-error-code-background-color: #d0cccc;
--search-results-alias-color: #000;
--search-results-grey-color: #999;
--search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: #e6e6e6;
+ --search-tab-button-not-selected-background: #e6e6e6;
+ --search-tab-button-selected-border-top-color: #0089ff;
+ --search-tab-button-selected-background: #ffffff;
--stab-background-color: #fff5d6;
--stab-code-color: #000;
--code-highlight-kw-color: #8959a8;
@@ -65,8 +70,6 @@
--test-arrow-hover-background-color: #4e8bca;
--target-background-color: #fdffd3;
--target-border-color: #ad7c37;
- --tooltip-background-color: #000;
- --tooltip-color: #fff;
--kbd-color: #000;
--kbd-background: #fafbfc;
--kbd-box-shadow-color: #c6cbd1;
@@ -89,21 +92,6 @@
--scrape-example-help-color: #333;
--scrape-example-help-hover-border-color: #000;
--scrape-example-help-hover-color: #000;
-}
-
-#search-tabs > button:not(.selected) {
- background-color: #e6e6e6;
- border-top-color: #e6e6e6;
-}
-
-#search-tabs > button:hover, #search-tabs > button.selected {
- background-color: #ffffff;
- border-top-color: #0089ff;
-}
-
-.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 {
- background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+ --scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
+ --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
}
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff2
index db57d2145..181a07f63 100644
--- a/src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff2
+++ b/src/librustdoc/html/static/fonts/SourceSerif4-Bold.ttf.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff2
index 1cbc021a3..2ae08a7be 100644
--- a/src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff2
+++ b/src/librustdoc/html/static/fonts/SourceSerif4-It.ttf.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-LICENSE.md b/src/librustdoc/html/static/fonts/SourceSerif4-LICENSE.md
index 68ea18924..5871e1f3d 100644
--- a/src/librustdoc/html/static/fonts/SourceSerif4-LICENSE.md
+++ b/src/librustdoc/html/static/fonts/SourceSerif4-LICENSE.md
@@ -1,4 +1,4 @@
-Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
+Copyright 2014 - 2023 Adobe (http://www.adobe.com/), with Reserved Font Name ‘Source’. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
diff --git a/src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff2
index 2db73fe2b..0263fc304 100644
--- a/src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff2
+++ b/src/librustdoc/html/static/fonts/SourceSerif4-Regular.ttf.woff2
Binary files differ
diff --git a/src/librustdoc/html/static/images/down-arrow.svg b/src/librustdoc/html/static/images/down-arrow.svg
deleted file mode 100644
index 5d76a64e9..000000000
--- a/src/librustdoc/html/static/images/down-arrow.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg> \ No newline at end of file
diff --git a/src/librustdoc/html/static/images/toggle-minus.svg b/src/librustdoc/html/static/images/toggle-minus.svg
deleted file mode 100644
index 73154788a..000000000
--- a/src/librustdoc/html/static/images/toggle-minus.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="17" height="17" shape-rendering="crispEdges" stroke="#000" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7"/></svg> \ No newline at end of file
diff --git a/src/librustdoc/html/static/images/toggle-plus.svg b/src/librustdoc/html/static/images/toggle-plus.svg
deleted file mode 100644
index 08b17033e..000000000
--- a/src/librustdoc/html/static/images/toggle-plus.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="17" height="17" shape-rendering="crispEdges" stroke="#000" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7M8.5 12V8.625v0V5"/></svg> \ No newline at end of file
diff --git a/src/librustdoc/html/static/images/wheel.svg b/src/librustdoc/html/static/images/wheel.svg
index 01da3b24c..83c07f63d 100644
--- a/src/librustdoc/html/static/images/wheel.svg
+++ b/src/librustdoc/html/static/images/wheel.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Capa_1" width="27.434" height="29.5" enable-background="new 0 0 27.434 29.5" version="1.1" viewBox="0 0 27.434 29.5" xml:space="preserve"><g><path d="M27.315,18.389c-0.165-0.604-0.509-1.113-0.981-1.459c-0.042-0.144-0.083-0.429-0.015-0.761l0.037-0.177v-0.182V14.8 c0-1.247-0.006-1.277-0.048-1.472c-0.076-0.354-0.035-0.653,0.007-0.803c0.477-0.346,0.828-0.861,0.996-1.476 c0.261-0.956,0.076-2.091-0.508-3.114l-0.591-1.032c-0.746-1.307-1.965-2.119-3.182-2.119c-0.378,0-0.75,0.081-1.085,0.235 c-0.198-0.025-0.554-0.15-0.855-0.389l-0.103-0.082l-0.114-0.065l-1.857-1.067L18.92,3.36l-0.105-0.044 c-0.376-0.154-0.658-0.41-0.768-0.556C17.918,1.172,16.349,0,14.296,0H13.14c-2.043,0-3.608,1.154-3.749,2.721 C9.277,2.862,8.999,3.104,8.633,3.25l-0.1,0.039L8.439,3.341L6.495,4.406L6.363,4.479L6.245,4.573 C5.936,4.82,5.596,4.944,5.416,4.977c-0.314-0.139-0.66-0.21-1.011-0.21c-1.198,0-2.411,0.819-3.165,2.139L0.65,7.938 c-0.412,0.72-0.642,1.521-0.644,2.258c-0.003,0.952,0.362,1.756,1.013,2.256c0.034,0.155,0.061,0.448-0.016,0.786 c-0.038,0.168-0.062,0.28-0.062,1.563c0,1.148,0,1.148,0.015,1.262l0.009,0.073l0.017,0.073c0.073,0.346,0.045,0.643,0.011,0.802 C0.348,17.512-0.01,18.314,0,19.268c0.008,0.729,0.238,1.523,0.648,2.242l0.589,1.031c0.761,1.331,1.967,2.159,3.15,2.159 c0.324,0,0.645-0.064,0.938-0.187c0.167,0.038,0.492,0.156,0.813,0.416l0.11,0.088l0.124,0.07l2.045,1.156l0.102,0.057l0.107,0.043 c0.364,0.147,0.646,0.381,0.766,0.521c0.164,1.52,1.719,2.634,3.745,2.634h1.155c2.037,0,3.598-1.134,3.747-2.675 c0.117-0.145,0.401-0.393,0.774-0.549l0.111-0.047l0.105-0.062l1.96-1.159l0.105-0.062l0.097-0.075 c0.309-0.246,0.651-0.371,0.832-0.402c0.313,0.138,0.662,0.212,1.016,0.212c1.199,0,2.412-0.82,3.166-2.139l0.59-1.032 C27.387,20.48,27.575,19.342,27.315,18.389z M25.274,20.635l-0.59,1.032c-0.438,0.765-1.104,1.251-1.639,1.251 c-0.133,0-0.258-0.029-0.369-0.094c-0.15-0.086-0.346-0.127-0.566-0.127c-0.596,0-1.383,0.295-2.01,0.796l-1.96,1.157 c-1.016,0.425-1.846,1.291-1.846,1.929s-0.898,1.159-1.998,1.159H13.14c-1.1,0-1.998-0.514-1.998-1.141s-0.834-1.477-1.854-1.888 l-2.046-1.157c-0.636-0.511-1.425-0.814-2.006-0.814c-0.202,0-0.379,0.037-0.516,0.115c-0.101,0.057-0.214,0.084-0.333,0.084 c-0.518,0-1.179-0.498-1.62-1.271l-0.591-1.032c-0.545-0.954-0.556-1.983-0.024-2.286c0.532-0.305,0.78-1.432,0.551-2.506 c0,0,0-0.003,0-1.042c0-1.088,0.021-1.18,0.021-1.18c0.238-1.072-0.01-2.203-0.552-2.513C1.631,10.8,1.634,9.765,2.18,8.812 L2.769,7.78c0.438-0.766,1.103-1.251,1.636-1.251c0.131,0,0.255,0.029,0.365,0.092C4.92,6.707,5.114,6.747,5.334,6.747 c0.596,0,1.38-0.296,2.007-0.795l1.944-1.065c1.021-0.407,1.856-1.277,1.856-1.933c0-0.656,0.898-1.192,1.998-1.192h1.156V1.761 c1.1,0,1.998,0.545,1.998,1.211c0,0.667,0.832,1.554,1.849,1.973L20,6.013c0.618,0.489,1.401,0.775,2.012,0.775 c0.24,0,0.454-0.045,0.62-0.139c0.122-0.069,0.259-0.102,0.403-0.102c0.551,0,1.221,0.476,1.653,1.231l0.59,1.032 c0.544,0.953,0.518,2.004-0.062,2.334c-0.577,0.331-0.859,1.48-0.627,2.554c0,0,0.01,0.042,0.01,1.103c0,1.012,0,1.012,0,1.012 c-0.218,1.049,0.068,2.174,0.636,2.498C25.802,18.635,25.819,19.68,25.274,20.635z"/><path d="M13.61,7.611c-3.913,0-7.084,3.173-7.084,7.085c0,3.914,3.171,7.085,7.084,7.085s7.085-3.172,7.085-7.085 C20.695,10.784,17.523,7.611,13.61,7.611z M13.61,20.02c-2.936,0-5.323-2.388-5.323-5.323c0-2.935,2.388-5.323,5.323-5.323 s5.324,2.388,5.324,5.323C18.934,17.632,16.546,20.02,13.61,20.02z"/><path d="M13.682,9.908c-2.602,0-4.718,2.116-4.718,4.718c0,2.601,2.116,4.716,4.718,4.716c2.601,0,4.717-2.115,4.717-4.716 C18.399,12.024,16.283,9.908,13.682,9.908z M13.682,17.581c-1.633,0-2.956-1.323-2.956-2.955s1.323-2.956,2.956-2.956 c1.632,0,2.956,1.324,2.956,2.956S15.314,17.581,13.682,17.581z"/></g></svg> \ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" width="27.434" height="29.5" enable-background="new 0 0 27.434 29.5" viewBox="0 0 27.434 29.5"><path d="M27.316 18.39a2.696 2.696 0 0 0-.98-1.46 1.62 1.62 0 0 1-.016-.762l.035-.176v-1.191c0-1.246-.003-1.278-.046-1.473a1.717 1.717 0 0 1 .007-.805c.477-.343.829-.859.997-1.472.257-.957.074-2.094-.508-3.117l-.594-1.032c-.746-1.304-1.965-2.117-3.18-2.117-.379 0-.75.078-1.086.235a1.958 1.958 0 0 1-.855-.391l-.102-.082-.117-.063-1.855-1.07-.094-.055-.106-.043c-.378-.156-.66-.41-.77-.554C17.919 1.172 16.349 0 14.297 0h-1.155c-2.043 0-3.61 1.152-3.75 2.723-.114.14-.391.382-.758.527l-.102.04-.094.05-1.94 1.066-.134.074-.117.094a2.019 2.019 0 0 1-.832.403 2.518 2.518 0 0 0-1.008-.211c-1.199 0-2.414.82-3.168 2.14l-.59 1.032c-.41.718-.64 1.523-.64 2.257-.004.953.36 1.758 1.012 2.258.035.152.058.445-.016.785-.04.168-.063.282-.063 1.563 0 1.148 0 1.148.016 1.261l.008.075.015.074c.075.344.047.64.012.8-.644.5-1.004 1.302-.992 2.259.008.726.238 1.52.648 2.242l.59 1.027c.758 1.332 1.965 2.16 3.149 2.16.324 0 .644-.062.937-.187.168.039.492.156.813.418l.11.086.124.07 2.047 1.156.102.059.105.043c.363.144.648.379.766.52.164 1.519 1.718 2.632 3.746 2.632h1.156c2.035 0 3.598-1.133 3.746-2.672.117-.144.402-.394.773-.55l.114-.047.101-.063 1.961-1.156.106-.063.097-.078c.309-.246.653-.37.832-.398.313.136.66.21 1.016.21 1.2 0 2.41-.82 3.164-2.14l.594-1.031c.59-1.028.777-2.164.52-3.117Zm-2.043 2.247-.59 1.031c-.437.766-1.105 1.25-1.636 1.25a.7.7 0 0 1-.371-.094 1.146 1.146 0 0 0-.567-.129c-.593 0-1.382.297-2.007.797l-1.961 1.156c-1.016.426-1.848 1.293-1.848 1.93 0 .64-.898 1.16-1.996 1.16H13.14c-1.102 0-2-.515-2-1.14 0-.63-.832-1.477-1.852-1.887l-2.047-1.16c-.637-.512-1.426-.813-2.008-.813-.199 0-.379.035-.515.114a.648.648 0 0 1-.332.085c-.52 0-1.18-.5-1.621-1.273l-.59-1.031c-.543-.953-.555-1.98-.024-2.285.532-.305.782-1.434.551-2.504V14.8c0-1.09.02-1.18.02-1.18.238-1.074-.008-2.203-.551-2.516-.54-.304-.54-1.34.008-2.293l.59-1.03c.437-.766 1.101-1.255 1.636-1.255a.73.73 0 0 1 .364.094c.152.086.343.125.566.125.594 0 1.379-.297 2.004-.793l1.945-1.066c1.02-.407 1.856-1.278 1.856-1.934 0-.656.898-1.191 2-1.191h1.156c1.098 0 1.996.543 1.996 1.21 0 .669.832 1.555 1.848 1.973L20 6.012c.617.492 1.402.777 2.012.777.242 0 .453-.047.62-.14a.79.79 0 0 1 .403-.102c.55 0 1.223.476 1.652 1.23l.59 1.032c.543.953.52 2.004-.062 2.336-.574.332-.86 1.48-.625 2.554 0 0 .008.04.008 1.102v1.011c-.215 1.051.07 2.176.636 2.5.567.325.586 1.368.04 2.325Zm0 0"/><path d="M13.61 7.61a7.084 7.084 0 0 0-7.083 7.085 7.085 7.085 0 1 0 14.168 0A7.088 7.088 0 0 0 13.61 7.61Zm0 12.41a5.33 5.33 0 0 1-5.325-5.325 5.33 5.33 0 0 1 5.324-5.32 5.327 5.327 0 0 1 5.325 5.32 5.328 5.328 0 0 1-5.325 5.325Zm0 0"/><path d="M13.684 9.906a4.722 4.722 0 0 0-4.72 4.719 4.722 4.722 0 0 0 4.72 4.719 4.724 4.724 0 0 0 4.714-4.719 4.724 4.724 0 0 0-4.714-4.719Zm0 7.676a2.954 2.954 0 1 1 0-5.91 2.953 2.953 0 0 1 2.953 2.953 2.957 2.957 0 0 1-2.953 2.957Zm0 0"/></svg> \ No newline at end of file
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 604ab147f..5e8c0e8d1 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -180,7 +180,6 @@ function browserSupportsHistoryApi() {
return window.history && typeof window.history.pushState === "function";
}
-// eslint-disable-next-line no-unused-vars
function loadCss(cssUrl) {
const link = document.createElement("link");
link.href = cssUrl;
@@ -379,7 +378,7 @@ function loadCss(cssUrl) {
}
ev.preventDefault();
searchState.defocus();
- window.hideAllModals(true); // true = reset focus for notable traits
+ window.hideAllModals(true); // true = reset focus for tooltips
}
function handleShortcut(ev) {
@@ -456,10 +455,7 @@ function loadCss(cssUrl) {
const ul = document.createElement("ul");
ul.className = "block " + shortty;
- for (const item of filtered) {
- const name = item[0];
- const desc = item[1]; // can be null
-
+ for (const name of filtered) {
let path;
if (shortty === "mod") {
path = name + "/index.html";
@@ -469,7 +465,6 @@ function loadCss(cssUrl) {
const current_page = document.location.href.split("/").pop();
const link = document.createElement("a");
link.href = path;
- link.title = desc;
if (path === current_page) {
link.className = "current";
}
@@ -789,17 +784,17 @@ function loadCss(cssUrl) {
// we need to switch away from mobile mode and make the main content area scrollable.
hideSidebar();
}
- if (window.CURRENT_NOTABLE_ELEMENT) {
- // As a workaround to the behavior of `contains: layout` used in doc togglers, the
- // notable traits popup is positioned using javascript.
+ if (window.CURRENT_TOOLTIP_ELEMENT) {
+ // As a workaround to the behavior of `contains: layout` used in doc togglers,
+ // tooltip popovers are positioned using javascript.
//
// This means when the window is resized, we need to redo the layout.
- const base = window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE;
- const force_visible = base.NOTABLE_FORCE_VISIBLE;
- hideNotable(false);
+ const base = window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;
+ const force_visible = base.TOOLTIP_FORCE_VISIBLE;
+ hideTooltip(false);
if (force_visible) {
- showNotable(base);
- base.NOTABLE_FORCE_VISIBLE = true;
+ showTooltip(base);
+ base.TOOLTIP_FORCE_VISIBLE = true;
}
}
});
@@ -827,27 +822,35 @@ function loadCss(cssUrl) {
});
});
- function showNotable(e) {
- if (!window.NOTABLE_TRAITS) {
+ function showTooltip(e) {
+ const notable_ty = e.getAttribute("data-notable-ty");
+ if (!window.NOTABLE_TRAITS && notable_ty) {
const data = document.getElementById("notable-traits-data");
if (data) {
window.NOTABLE_TRAITS = JSON.parse(data.innerText);
} else {
- throw new Error("showNotable() called on page without any notable traits!");
+ throw new Error("showTooltip() called with notable without any notable traits!");
}
}
- if (window.CURRENT_NOTABLE_ELEMENT && window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE === e) {
+ if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) {
// Make this function idempotent.
return;
}
window.hideAllModals(false);
- const ty = e.getAttribute("data-ty");
const wrapper = document.createElement("div");
- wrapper.innerHTML = "<div class=\"content\">" + window.NOTABLE_TRAITS[ty] + "</div>";
- wrapper.className = "notable popover";
+ if (notable_ty) {
+ wrapper.innerHTML = "<div class=\"content\">" +
+ window.NOTABLE_TRAITS[notable_ty] + "</div>";
+ } else if (e.getAttribute("title") !== undefined) {
+ const titleContent = document.createElement("div");
+ titleContent.className = "content";
+ titleContent.appendChild(document.createTextNode(e.getAttribute("title")));
+ wrapper.appendChild(titleContent);
+ }
+ wrapper.className = "tooltip popover";
const focusCatcher = document.createElement("div");
focusCatcher.setAttribute("tabindex", "0");
- focusCatcher.onfocus = hideNotable;
+ focusCatcher.onfocus = hideTooltip;
wrapper.appendChild(focusCatcher);
const pos = e.getBoundingClientRect();
// 5px overlap so that the mouse can easily travel from place to place
@@ -869,62 +872,62 @@ function loadCss(cssUrl) {
);
}
wrapper.style.visibility = "";
- window.CURRENT_NOTABLE_ELEMENT = wrapper;
- window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE = e;
+ window.CURRENT_TOOLTIP_ELEMENT = wrapper;
+ window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e;
wrapper.onpointerleave = function(ev) {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
- if (!e.NOTABLE_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) {
- hideNotable(true);
+ if (!e.TOOLTIP_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) {
+ hideTooltip(true);
}
};
}
- function notableBlurHandler(event) {
- if (window.CURRENT_NOTABLE_ELEMENT &&
- !elemIsInParent(document.activeElement, window.CURRENT_NOTABLE_ELEMENT) &&
- !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT) &&
- !elemIsInParent(document.activeElement, window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE) &&
- !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE)
+ function tooltipBlurHandler(event) {
+ if (window.CURRENT_TOOLTIP_ELEMENT &&
+ !elemIsInParent(document.activeElement, window.CURRENT_TOOLTIP_ELEMENT) &&
+ !elemIsInParent(event.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT) &&
+ !elemIsInParent(document.activeElement, window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE) &&
+ !elemIsInParent(event.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE)
) {
// Work around a difference in the focus behaviour between Firefox, Chrome, and Safari.
- // When I click the button on an already-opened notable trait popover, Safari
+ // When I click the button on an already-opened tooltip popover, Safari
// hides the popover and then immediately shows it again, while everyone else hides it
// and it stays hidden.
//
// To work around this, make sure the click finishes being dispatched before
- // hiding the popover. Since `hideNotable()` is idempotent, this makes Safari behave
+ // hiding the popover. Since `hideTooltip()` is idempotent, this makes Safari behave
// consistently with the other two.
- setTimeout(() => hideNotable(false), 0);
+ setTimeout(() => hideTooltip(false), 0);
}
}
- function hideNotable(focus) {
- if (window.CURRENT_NOTABLE_ELEMENT) {
- if (window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE) {
+ function hideTooltip(focus) {
+ if (window.CURRENT_TOOLTIP_ELEMENT) {
+ if (window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE) {
if (focus) {
- window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.focus();
+ window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus();
}
- window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE = false;
+ window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false;
}
const body = document.getElementsByTagName("body")[0];
- body.removeChild(window.CURRENT_NOTABLE_ELEMENT);
- window.CURRENT_NOTABLE_ELEMENT = null;
+ body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);
+ window.CURRENT_TOOLTIP_ELEMENT = null;
}
}
- onEachLazy(document.getElementsByClassName("notable-traits"), e => {
+ onEachLazy(document.getElementsByClassName("tooltip"), e => {
e.onclick = function() {
- this.NOTABLE_FORCE_VISIBLE = this.NOTABLE_FORCE_VISIBLE ? false : true;
- if (window.CURRENT_NOTABLE_ELEMENT && !this.NOTABLE_FORCE_VISIBLE) {
- hideNotable(true);
+ this.TOOLTIP_FORCE_VISIBLE = this.TOOLTIP_FORCE_VISIBLE ? false : true;
+ if (window.CURRENT_TOOLTIP_ELEMENT && !this.TOOLTIP_FORCE_VISIBLE) {
+ hideTooltip(true);
} else {
- showNotable(this);
- window.CURRENT_NOTABLE_ELEMENT.setAttribute("tabindex", "0");
- window.CURRENT_NOTABLE_ELEMENT.focus();
- window.CURRENT_NOTABLE_ELEMENT.onblur = notableBlurHandler;
+ showTooltip(this);
+ window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0");
+ window.CURRENT_TOOLTIP_ELEMENT.focus();
+ window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler;
}
return false;
};
@@ -933,16 +936,16 @@ function loadCss(cssUrl) {
if (ev.pointerType !== "mouse") {
return;
}
- showNotable(this);
+ showTooltip(this);
};
e.onpointerleave = function(ev) {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
- if (!this.NOTABLE_FORCE_VISIBLE &&
- !elemIsInParent(ev.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) {
- hideNotable(true);
+ if (!this.TOOLTIP_FORCE_VISIBLE &&
+ !elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) {
+ hideTooltip(true);
}
};
});
@@ -1044,14 +1047,14 @@ function loadCss(cssUrl) {
}
/**
- * Hide popover menus, notable trait tooltips, and the sidebar (if applicable).
+ * Hide popover menus, clickable tooltips, and the sidebar (if applicable).
*
- * Pass "true" to reset focus for notable traits.
+ * Pass "true" to reset focus for tooltip popovers.
*/
window.hideAllModals = function(switchFocus) {
hideSidebar();
window.hidePopoverMenus();
- hideNotable(switchFocus);
+ hideTooltip(switchFocus);
};
/**
@@ -1142,7 +1145,11 @@ function loadCss(cssUrl) {
(function() {
let reset_button_timeout = null;
- window.copy_path = but => {
+ const but = document.getElementById("copy-path");
+ if (!but) {
+ return;
+ }
+ but.onclick = () => {
const parent = but.parentElement;
const path = [];
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 88592fa0c..b98bced41 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -112,7 +112,6 @@ function levenshtein(s1, s2) {
}
function initSearch(rawSearchIndex) {
- const MAX_LEV_DISTANCE = 3;
const MAX_RESULTS = 200;
const NO_TYPE_FILTER = -1;
/**
@@ -143,13 +142,11 @@ function initSearch(rawSearchIndex) {
}
function itemTypeFromName(typename) {
- for (let i = 0, len = itemTypes.length; i < len; ++i) {
- if (itemTypes[i] === typename) {
- return i;
- }
+ const index = itemTypes.findIndex(i => i === typename);
+ if (index < 0) {
+ throw ["Unknown type filter ", typename];
}
-
- throw new Error("Unknown type filter `" + typename + "`");
+ return index;
}
/**
@@ -167,21 +164,21 @@ function initSearch(rawSearchIndex) {
*/
function getStringElem(query, parserState, isInGenerics) {
if (isInGenerics) {
- throw new Error("`\"` cannot be used in generics");
+ throw ["Unexpected ", "\"", " in generics"];
} else if (query.literalSearch) {
- throw new Error("Cannot have more than one literal search element");
+ throw ["Cannot have more than one literal search element"];
} else if (parserState.totalElems - parserState.genericsElems > 0) {
- throw new Error("Cannot use literal search when there is more than one element");
+ throw ["Cannot use literal search when there is more than one element"];
}
parserState.pos += 1;
const start = parserState.pos;
const end = getIdentEndPosition(parserState);
if (parserState.pos >= parserState.length) {
- throw new Error("Unclosed `\"`");
+ throw ["Unclosed ", "\""];
} else if (parserState.userQuery[end] !== "\"") {
- throw new Error(`Unexpected \`${parserState.userQuery[end]}\` in a string element`);
+ throw ["Unexpected ", parserState.userQuery[end], " in a string element"];
} else if (start === end) {
- throw new Error("Cannot have empty string element");
+ throw ["Cannot have empty string element"];
}
// To skip the quote at the end.
parserState.pos += 1;
@@ -260,7 +257,7 @@ function initSearch(rawSearchIndex) {
return;
}
if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
- throw new Error("You cannot have more than one element if you use quotes");
+ throw ["You cannot have more than one element if you use quotes"];
}
const pathSegments = name.split("::");
if (pathSegments.length > 1) {
@@ -269,17 +266,17 @@ function initSearch(rawSearchIndex) {
if (pathSegment.length === 0) {
if (i === 0) {
- throw new Error("Paths cannot start with `::`");
+ throw ["Paths cannot start with ", "::"];
} else if (i + 1 === len) {
- throw new Error("Paths cannot end with `::`");
+ throw ["Paths cannot end with ", "::"];
}
- throw new Error("Unexpected `::::`");
+ throw ["Unexpected ", "::::"];
}
}
}
// In case we only have something like `<p>`, there is no name.
if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === "")) {
- throw new Error("Found generics without a path");
+ throw ["Found generics without a path"];
}
parserState.totalElems += 1;
if (isInGenerics) {
@@ -303,22 +300,23 @@ function initSearch(rawSearchIndex) {
* @return {integer}
*/
function getIdentEndPosition(parserState) {
+ const start = parserState.pos;
let end = parserState.pos;
- let foundExclamation = false;
+ let foundExclamation = -1;
while (parserState.pos < parserState.length) {
const c = parserState.userQuery[parserState.pos];
if (!isIdentCharacter(c)) {
if (c === "!") {
- if (foundExclamation) {
- throw new Error("Cannot have more than one `!` in an ident");
+ if (foundExclamation !== -1) {
+ throw ["Cannot have more than one ", "!", " in an ident"];
} else if (parserState.pos + 1 < parserState.length &&
isIdentCharacter(parserState.userQuery[parserState.pos + 1])
) {
- throw new Error("`!` can only be at the end of an ident");
+ throw ["Unexpected ", "!", ": it can only be at the end of an ident"];
}
- foundExclamation = true;
+ foundExclamation = parserState.pos;
} else if (isErrorCharacter(c)) {
- throw new Error(`Unexpected \`${c}\``);
+ throw ["Unexpected ", c];
} else if (
isStopCharacter(c) ||
isSpecialStartCharacter(c) ||
@@ -329,16 +327,40 @@ function initSearch(rawSearchIndex) {
if (!isPathStart(parserState)) {
break;
}
+ if (foundExclamation !== -1) {
+ if (start <= (end - 2)) {
+ throw ["Cannot have associated items in macros"];
+ } else {
+ // if start == end - 1, we got the never type
+ // while the never type has no associated macros, we still
+ // can parse a path like that
+ foundExclamation = -1;
+ }
+ }
// Skip current ":".
parserState.pos += 1;
- foundExclamation = false;
} else {
- throw new Error(`Unexpected \`${c}\``);
+ throw ["Unexpected ", c];
}
}
parserState.pos += 1;
end = parserState.pos;
}
+ // if start == end - 1, we got the never type
+ if (foundExclamation !== -1 && start <= (end - 2)) {
+ if (parserState.typeFilter === null) {
+ parserState.typeFilter = "macro";
+ } else if (parserState.typeFilter !== "macro") {
+ throw [
+ "Invalid search type: macro ",
+ "!",
+ " and ",
+ parserState.typeFilter,
+ " both specified",
+ ];
+ }
+ end = foundExclamation;
+ }
return end;
}
@@ -365,9 +387,9 @@ function initSearch(rawSearchIndex) {
parserState.userQuery[parserState.pos] === "<"
) {
if (isInGenerics) {
- throw new Error("Unexpected `<` after `<`");
+ throw ["Unexpected ", "<", " after ", "<"];
} else if (start >= end) {
- throw new Error("Found generics without a path");
+ throw ["Found generics without a path"];
}
parserState.pos += 1;
getItemsBefore(query, parserState, generics, ">");
@@ -411,24 +433,51 @@ function initSearch(rawSearchIndex) {
foundStopChar = true;
continue;
} else if (c === ":" && isPathStart(parserState)) {
- throw new Error("Unexpected `::`: paths cannot start with `::`");
+ throw ["Unexpected ", "::", ": paths cannot start with ", "::"];
} else if (c === ":" || isEndCharacter(c)) {
let extra = "";
if (endChar === ">") {
- extra = "`<`";
+ extra = "<";
} else if (endChar === "") {
- extra = "`->`";
+ extra = "->";
+ } else {
+ extra = endChar;
}
- throw new Error("Unexpected `" + c + "` after " + extra);
+ throw ["Unexpected ", c, " after ", extra];
}
if (!foundStopChar) {
if (endChar !== "") {
- throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``);
+ throw [
+ "Expected ",
+ ",", // comma
+ ", ",
+ "&nbsp;", // whitespace
+ " or ",
+ endChar,
+ ", found ",
+ c,
+ ];
}
- throw new Error(`Expected \`,\` or \` \`, found \`${c}\``);
+ throw [
+ "Expected ",
+ ",", // comma
+ " or ",
+ "&nbsp;", // whitespace
+ ", found ",
+ c,
+ ];
}
const posBefore = parserState.pos;
getNextElem(query, parserState, elems, endChar === ">");
+ if (endChar !== "") {
+ if (parserState.pos >= parserState.length) {
+ throw ["Unclosed ", "<"];
+ }
+ const c2 = parserState.userQuery[parserState.pos];
+ if (!isSeparatorCharacter(c2) && c2 !== endChar) {
+ throw ["Expected ", endChar, ", found ", c2];
+ }
+ }
// This case can be encountered if `getNextElem` encountered a "stop character" right
// from the start. For example if you have `,,` or `<>`. In this case, we simply move up
// the current position to continue the parsing.
@@ -437,7 +486,10 @@ function initSearch(rawSearchIndex) {
}
foundStopChar = false;
}
- // We are either at the end of the string or on the `endChar`` character, let's move forward
+ if (parserState.pos >= parserState.length && endChar !== "") {
+ throw ["Unclosed ", "<"];
+ }
+ // We are either at the end of the string or on the `endChar` character, let's move forward
// in any case.
parserState.pos += 1;
}
@@ -453,7 +505,7 @@ function initSearch(rawSearchIndex) {
for (let pos = 0; pos < parserState.pos; ++pos) {
if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) {
- throw new Error(`Unexpected \`${query[pos]}\` in type filter`);
+ throw ["Unexpected ", query[pos], " in type filter"];
}
}
}
@@ -466,11 +518,10 @@ function initSearch(rawSearchIndex) {
* @param {ParserState} parserState
*/
function parseInput(query, parserState) {
- let c, before;
let foundStopChar = true;
while (parserState.pos < parserState.length) {
- c = parserState.userQuery[parserState.pos];
+ const c = parserState.userQuery[parserState.pos];
if (isStopCharacter(c)) {
foundStopChar = true;
if (isSeparatorCharacter(c)) {
@@ -480,19 +531,19 @@ function initSearch(rawSearchIndex) {
if (isReturnArrow(parserState)) {
break;
}
- throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`);
+ throw ["Unexpected ", c, " (did you mean ", "->", "?)"];
}
- throw new Error(`Unexpected \`${c}\``);
+ throw ["Unexpected ", c];
} else if (c === ":" && !isPathStart(parserState)) {
if (parserState.typeFilter !== null) {
- throw new Error("Unexpected `:`");
+ throw ["Unexpected ", ":"];
}
if (query.elems.length === 0) {
- throw new Error("Expected type filter before `:`");
+ throw ["Expected type filter before ", ":"];
} else if (query.elems.length !== 1 || parserState.totalElems !== 1) {
- throw new Error("Unexpected `:`");
+ throw ["Unexpected ", ":"];
} else if (query.literalSearch) {
- throw new Error("You cannot use quotes on type filter");
+ throw ["You cannot use quotes on type filter"];
}
checkExtraTypeFilterCharacters(parserState);
// The type filter doesn't count as an element since it's a modifier.
@@ -505,11 +556,31 @@ function initSearch(rawSearchIndex) {
}
if (!foundStopChar) {
if (parserState.typeFilter !== null) {
- throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``);
+ throw [
+ "Expected ",
+ ",", // comma
+ ", ",
+ "&nbsp;", // whitespace
+ " or ",
+ "->", // arrow
+ ", found ",
+ c,
+ ];
}
- throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
- }
- before = query.elems.length;
+ throw [
+ "Expected ",
+ ",", // comma
+ ", ",
+ "&nbsp;", // whitespace
+ ", ",
+ ":", // colon
+ " or ",
+ "->", // arrow
+ ", found ",
+ c,
+ ];
+ }
+ const before = query.elems.length;
getNextElem(query, parserState, query.elems, false);
if (query.elems.length === before) {
// Nothing was added, weird... Let's increase the position to not remain stuck.
@@ -518,14 +589,13 @@ function initSearch(rawSearchIndex) {
foundStopChar = false;
}
while (parserState.pos < parserState.length) {
- c = parserState.userQuery[parserState.pos];
if (isReturnArrow(parserState)) {
parserState.pos += 2;
// Get returned elements.
getItemsBefore(query, parserState, query.returned, "");
// Nothing can come afterward!
if (query.returned.length === 0) {
- throw new Error("Expected at least one item after `->`");
+ throw ["Expected at least one item after ", "->"];
}
break;
} else {
@@ -594,8 +664,8 @@ function initSearch(rawSearchIndex) {
*
* The supported syntax by this parser is as follow:
*
- * ident = *(ALPHA / DIGIT / "_") [!]
- * path = ident *(DOUBLE-COLON ident)
+ * ident = *(ALPHA / DIGIT / "_")
+ * path = ident *(DOUBLE-COLON ident) [!]
* arg = path [generics]
* arg-without-generic = path
* type-sep = COMMA/WS *(COMMA/WS)
@@ -679,7 +749,7 @@ function initSearch(rawSearchIndex) {
}
} catch (err) {
query = newParsedQuery(userQuery);
- query.error = err.message;
+ query.error = err;
query.typeFilter = -1;
return query;
}
@@ -897,13 +967,13 @@ function initSearch(rawSearchIndex) {
* @param {QueryElement} elem - The element from the parsed query.
* @param {integer} defaultLev - This is the value to return in case there are no generics.
*
- * @return {integer} - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`.
+ * @return {integer} - Returns the best match (if any) or `maxLevDistance + 1`.
*/
- function checkGenerics(row, elem, defaultLev) {
+ function checkGenerics(row, elem, defaultLev, maxLevDistance) {
if (row.generics.length === 0) {
- return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
+ return elem.generics.length === 0 ? defaultLev : maxLevDistance + 1;
} else if (row.generics.length > 0 && row.generics[0].name === null) {
- return checkGenerics(row.generics[0], elem, defaultLev);
+ return checkGenerics(row.generics[0], elem, defaultLev, maxLevDistance);
}
// The names match, but we need to be sure that all generics kinda
// match as well.
@@ -914,8 +984,8 @@ function initSearch(rawSearchIndex) {
elem_name = entry.name;
if (elem_name === "") {
// Pure generic, needs to check into it.
- if (checkGenerics(entry, elem, MAX_LEV_DISTANCE + 1) !== 0) {
- return MAX_LEV_DISTANCE + 1;
+ if (checkGenerics(entry, elem, maxLevDistance + 1, maxLevDistance) !== 0) {
+ return maxLevDistance + 1;
}
continue;
}
@@ -942,7 +1012,7 @@ function initSearch(rawSearchIndex) {
}
}
if (match === null) {
- return MAX_LEV_DISTANCE + 1;
+ return maxLevDistance + 1;
}
elems[match] -= 1;
if (elems[match] === 0) {
@@ -951,7 +1021,7 @@ function initSearch(rawSearchIndex) {
}
return 0;
}
- return MAX_LEV_DISTANCE + 1;
+ return maxLevDistance + 1;
}
/**
@@ -963,10 +1033,10 @@ function initSearch(rawSearchIndex) {
*
* @return {integer} - Returns a Levenshtein distance to the best match.
*/
- function checkIfInGenerics(row, elem) {
- let lev = MAX_LEV_DISTANCE + 1;
+ function checkIfInGenerics(row, elem, maxLevDistance) {
+ let lev = maxLevDistance + 1;
for (const entry of row.generics) {
- lev = Math.min(checkType(entry, elem, true), lev);
+ lev = Math.min(checkType(entry, elem, true, maxLevDistance), lev);
if (lev === 0) {
break;
}
@@ -983,15 +1053,15 @@ function initSearch(rawSearchIndex) {
* @param {boolean} literalSearch
*
* @return {integer} - Returns a Levenshtein distance to the best match. If there is
- * no match, returns `MAX_LEV_DISTANCE + 1`.
+ * no match, returns `maxLevDistance + 1`.
*/
- function checkType(row, elem, literalSearch) {
+ function checkType(row, elem, literalSearch, maxLevDistance) {
if (row.name === null) {
// This is a pure "generic" search, no need to run other checks.
if (row.generics.length > 0) {
- return checkIfInGenerics(row, elem);
+ return checkIfInGenerics(row, elem, maxLevDistance);
}
- return MAX_LEV_DISTANCE + 1;
+ return maxLevDistance + 1;
}
let lev = levenshtein(row.name, elem.name);
@@ -1005,9 +1075,9 @@ function initSearch(rawSearchIndex) {
return 0;
}
}
- return MAX_LEV_DISTANCE + 1;
+ return maxLevDistance + 1;
} else if (elem.generics.length > 0) {
- return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
+ return checkGenerics(row, elem, maxLevDistance + 1, maxLevDistance);
}
return 0;
} else if (row.generics.length > 0) {
@@ -1017,22 +1087,20 @@ function initSearch(rawSearchIndex) {
}
// The name didn't match so we now check if the type we're looking for is inside
// the generics!
- lev = checkIfInGenerics(row, elem);
- // Now whatever happens, the returned distance is "less good" so we should mark
- // it as such, and so we add 0.5 to the distance to make it "less good".
- return lev + 0.5;
- } else if (lev > MAX_LEV_DISTANCE) {
+ lev = Math.min(lev, checkIfInGenerics(row, elem, maxLevDistance));
+ return lev;
+ } else if (lev > maxLevDistance) {
// So our item's name doesn't match at all and has generics.
//
// Maybe it's present in a sub generic? For example "f<A<B<C>>>()", if we're
// looking for "B<C>", we'll need to go down.
- return checkIfInGenerics(row, elem);
+ return checkIfInGenerics(row, elem, maxLevDistance);
} else {
// At this point, the name kinda match and we have generics to check, so
// let's go!
- const tmp_lev = checkGenerics(row, elem, lev);
- if (tmp_lev > MAX_LEV_DISTANCE) {
- return MAX_LEV_DISTANCE + 1;
+ const tmp_lev = checkGenerics(row, elem, lev, maxLevDistance);
+ if (tmp_lev > maxLevDistance) {
+ return maxLevDistance + 1;
}
// We compute the median value of both checks and return it.
return (tmp_lev + lev) / 2;
@@ -1040,7 +1108,7 @@ function initSearch(rawSearchIndex) {
} else if (elem.generics.length > 0) {
// In this case, we were expecting generics but there isn't so we simply reject this
// one.
- return MAX_LEV_DISTANCE + 1;
+ return maxLevDistance + 1;
}
// No generics on our query or on the target type so we can return without doing
// anything else.
@@ -1055,23 +1123,26 @@ function initSearch(rawSearchIndex) {
* @param {integer} typeFilter
*
* @return {integer} - Returns a Levenshtein distance to the best match. If there is no
- * match, returns `MAX_LEV_DISTANCE + 1`.
+ * match, returns `maxLevDistance + 1`.
*/
- function findArg(row, elem, typeFilter) {
- let lev = MAX_LEV_DISTANCE + 1;
+ function findArg(row, elem, typeFilter, maxLevDistance) {
+ let lev = maxLevDistance + 1;
if (row && row.type && row.type.inputs && row.type.inputs.length > 0) {
for (const input of row.type.inputs) {
if (!typePassesFilter(typeFilter, input.ty)) {
continue;
}
- lev = Math.min(lev, checkType(input, elem, parsedQuery.literalSearch));
+ lev = Math.min(
+ lev,
+ checkType(input, elem, parsedQuery.literalSearch, maxLevDistance)
+ );
if (lev === 0) {
return 0;
}
}
}
- return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
+ return parsedQuery.literalSearch ? maxLevDistance + 1 : lev;
}
/**
@@ -1082,10 +1153,10 @@ function initSearch(rawSearchIndex) {
* @param {integer} typeFilter
*
* @return {integer} - Returns a Levenshtein distance to the best match. If there is no
- * match, returns `MAX_LEV_DISTANCE + 1`.
+ * match, returns `maxLevDistance + 1`.
*/
- function checkReturned(row, elem, typeFilter) {
- let lev = MAX_LEV_DISTANCE + 1;
+ function checkReturned(row, elem, typeFilter, maxLevDistance) {
+ let lev = maxLevDistance + 1;
if (row && row.type && row.type.output.length > 0) {
const ret = row.type.output;
@@ -1093,20 +1164,23 @@ function initSearch(rawSearchIndex) {
if (!typePassesFilter(typeFilter, ret_ty.ty)) {
continue;
}
- lev = Math.min(lev, checkType(ret_ty, elem, parsedQuery.literalSearch));
+ lev = Math.min(
+ lev,
+ checkType(ret_ty, elem, parsedQuery.literalSearch, maxLevDistance)
+ );
if (lev === 0) {
return 0;
}
}
}
- return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
+ return parsedQuery.literalSearch ? maxLevDistance + 1 : lev;
}
- function checkPath(contains, ty) {
+ function checkPath(contains, ty, maxLevDistance) {
if (contains.length === 0) {
return 0;
}
- let ret_lev = MAX_LEV_DISTANCE + 1;
+ let ret_lev = maxLevDistance + 1;
const path = ty.path.split("::");
if (ty.parent && ty.parent.name) {
@@ -1116,7 +1190,7 @@ function initSearch(rawSearchIndex) {
const length = path.length;
const clength = contains.length;
if (clength > length) {
- return MAX_LEV_DISTANCE + 1;
+ return maxLevDistance + 1;
}
for (let i = 0; i < length; ++i) {
if (i + clength > length) {
@@ -1126,7 +1200,7 @@ function initSearch(rawSearchIndex) {
let aborted = false;
for (let x = 0; x < clength; ++x) {
const lev = levenshtein(path[i + x], contains[x]);
- if (lev > MAX_LEV_DISTANCE) {
+ if (lev > maxLevDistance) {
aborted = true;
break;
}
@@ -1231,7 +1305,7 @@ function initSearch(rawSearchIndex) {
* following condition:
*
* * If it is a "literal search" (`parsedQuery.literalSearch`), then `lev` must be 0.
- * * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
+ * * If it is not a "literal search", `lev` must be <= `maxLevDistance`.
*
* The `results` map contains information which will be used to sort the search results:
*
@@ -1249,8 +1323,8 @@ function initSearch(rawSearchIndex) {
* @param {integer} lev
* @param {integer} path_lev
*/
- function addIntoResults(results, fullId, id, index, lev, path_lev) {
- const inBounds = lev <= MAX_LEV_DISTANCE || index !== -1;
+ function addIntoResults(results, fullId, id, index, lev, path_lev, maxLevDistance) {
+ const inBounds = lev <= maxLevDistance || index !== -1;
if (lev === 0 || (!parsedQuery.literalSearch && inBounds)) {
if (results[fullId] !== undefined) {
const result = results[fullId];
@@ -1289,7 +1363,8 @@ function initSearch(rawSearchIndex) {
elem,
results_others,
results_in_args,
- results_returned
+ results_returned,
+ maxLevDistance
) {
if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
return;
@@ -1298,13 +1373,13 @@ function initSearch(rawSearchIndex) {
const fullId = row.id;
const searchWord = searchWords[pos];
- const in_args = findArg(row, elem, parsedQuery.typeFilter);
- const returned = checkReturned(row, elem, parsedQuery.typeFilter);
+ const in_args = findArg(row, elem, parsedQuery.typeFilter, maxLevDistance);
+ const returned = checkReturned(row, elem, parsedQuery.typeFilter, maxLevDistance);
// 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);
+ addIntoResults(results_in_args, fullId, pos, -1, in_args, 0, maxLevDistance);
+ addIntoResults(results_returned, fullId, pos, -1, returned, 0, maxLevDistance);
if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
return;
@@ -1328,16 +1403,16 @@ function initSearch(rawSearchIndex) {
// 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);
+ lev = checkGenerics(row.type, elem, maxLevDistance + 1, maxLevDistance);
// path_lev is 0 because we know it's empty
- addIntoResults(results_others, fullId, pos, index, lev, 0);
+ addIntoResults(results_others, fullId, pos, index, lev, 0, maxLevDistance);
}
return;
}
if (elem.fullPath.length > 1) {
- path_lev = checkPath(elem.pathWithoutLast, row);
- if (path_lev > MAX_LEV_DISTANCE) {
+ path_lev = checkPath(elem.pathWithoutLast, row, maxLevDistance);
+ if (path_lev > maxLevDistance) {
return;
}
}
@@ -1351,11 +1426,11 @@ function initSearch(rawSearchIndex) {
lev = levenshtein(searchWord, elem.pathLast);
- if (index === -1 && lev + path_lev > MAX_LEV_DISTANCE) {
+ if (index === -1 && lev + path_lev > maxLevDistance) {
return;
}
- addIntoResults(results_others, fullId, pos, index, lev, path_lev);
+ addIntoResults(results_others, fullId, pos, index, lev, path_lev, maxLevDistance);
}
/**
@@ -1367,7 +1442,7 @@ function initSearch(rawSearchIndex) {
* @param {integer} pos - Position in the `searchIndex`.
* @param {Object} results
*/
- function handleArgs(row, pos, results) {
+ function handleArgs(row, pos, results, maxLevDistance) {
if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
return;
}
@@ -1379,7 +1454,7 @@ function initSearch(rawSearchIndex) {
function checkArgs(elems, callback) {
for (const elem of elems) {
// There is more than one parameter to the query so all checks should be "exact"
- const lev = callback(row, elem, NO_TYPE_FILTER);
+ const lev = callback(row, elem, NO_TYPE_FILTER, maxLevDistance);
if (lev <= 1) {
nbLev += 1;
totalLev += lev;
@@ -1400,12 +1475,21 @@ function initSearch(rawSearchIndex) {
return;
}
const lev = Math.round(totalLev / nbLev);
- addIntoResults(results, row.id, pos, 0, lev, 0);
+ addIntoResults(results, row.id, pos, 0, lev, 0, maxLevDistance);
}
function innerRunQuery() {
let elem, i, nSearchWords, in_returned, row;
+ let queryLen = 0;
+ for (const elem of parsedQuery.elems) {
+ queryLen += elem.name.length;
+ }
+ for (const elem of parsedQuery.returned) {
+ queryLen += elem.name.length;
+ }
+ const maxLevDistance = Math.floor(queryLen / 3);
+
if (parsedQuery.foundElems === 1) {
if (parsedQuery.elems.length === 1) {
elem = parsedQuery.elems[0];
@@ -1418,7 +1502,8 @@ function initSearch(rawSearchIndex) {
elem,
results_others,
results_in_args,
- results_returned
+ results_returned,
+ maxLevDistance
);
}
} else if (parsedQuery.returned.length === 1) {
@@ -1426,13 +1511,18 @@ function initSearch(rawSearchIndex) {
elem = parsedQuery.returned[0];
for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
row = searchIndex[i];
- in_returned = checkReturned(row, elem, parsedQuery.typeFilter);
- addIntoResults(results_others, row.id, i, -1, in_returned);
+ in_returned = checkReturned(
+ row,
+ elem,
+ parsedQuery.typeFilter,
+ maxLevDistance
+ );
+ addIntoResults(results_others, row.id, i, -1, in_returned, maxLevDistance);
}
}
} else if (parsedQuery.foundElems > 0) {
for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
- handleArgs(searchIndex[i], i, results_others);
+ handleArgs(searchIndex[i], i, results_others, maxLevDistance);
}
}
}
@@ -1470,7 +1560,7 @@ function initSearch(rawSearchIndex) {
*
* @return {boolean} - Whether the result is valid or not
*/
- function validateResult(name, path, keys, parent) {
+ function validateResult(name, path, keys, parent, maxLevDistance) {
if (!keys || !keys.length) {
return true;
}
@@ -1485,7 +1575,7 @@ function initSearch(rawSearchIndex) {
(parent !== undefined && parent.name !== undefined &&
parent.name.toLowerCase().indexOf(key) > -1) ||
// lastly check to see if the name was a levenshtein match
- levenshtein(name, key) <= MAX_LEV_DISTANCE)) {
+ levenshtein(name, key) <= maxLevDistance)) {
return false;
}
}
@@ -1725,7 +1815,16 @@ 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>`;
+ const error = results.query.error;
+ error.forEach((value, index) => {
+ value = value.split("<").join("&lt;").split(">").join("&gt;");
+ if (index % 2 !== 0) {
+ error[index] = `<code>${value}</code>`;
+ } else {
+ error[index] = value;
+ }
+ });
+ output += `<h3 class="error">Query parser error: "${error.join("")}".</h3>`;
output += "<div id=\"search-tabs\">" +
makeTabHeader(0, "In Names", ret_others[1]) +
"</div>";
@@ -1922,7 +2021,7 @@ function initSearch(rawSearchIndex) {
* @type {Array<string>}
*/
const searchWords = [];
- let i, word;
+ const charA = "A".charCodeAt(0);
let currentIndex = 0;
let id = 0;
@@ -1936,7 +2035,7 @@ function initSearch(rawSearchIndex) {
/**
* The raw search data for a given crate. `n`, `t`, `d`, and `q`, `i`, and `f`
* are arrays with the same length. n[i] contains the name of an item.
- * t[i] contains the type of that item (as a small integer that represents an
+ * t[i] contains the type of that item (as a string of characters that represent an
* offset in `itemTypes`). d[i] contains the description of that item.
*
* q[i] contains the full path of the item, or an empty string indicating
@@ -1963,7 +2062,7 @@ function initSearch(rawSearchIndex) {
* doc: string,
* a: Object,
* n: Array<string>,
- * t: Array<Number>,
+ * t: String,
* d: Array<string>,
* q: Array<string>,
* i: Array<Number>,
@@ -1992,7 +2091,7 @@ function initSearch(rawSearchIndex) {
searchIndex.push(crateRow);
currentIndex += 1;
- // an array of (Number) item types
+ // a String of one character item type codes
const itemTypes = crateCorpus.t;
// an array of (String) item names
const itemNames = crateCorpus.n;
@@ -2017,7 +2116,7 @@ function initSearch(rawSearchIndex) {
// convert `rawPaths` entries into object form
// generate normalizedPaths for function search mode
let len = paths.length;
- for (i = 0; i < len; ++i) {
+ for (let i = 0; i < len; ++i) {
lowercasePaths.push({ty: paths[i][0], name: paths[i][1].toLowerCase()});
paths[i] = {ty: paths[i][0], name: paths[i][1]};
}
@@ -2031,19 +2130,17 @@ function initSearch(rawSearchIndex) {
// faster analysis operations
len = itemTypes.length;
let lastPath = "";
- for (i = 0; i < len; ++i) {
+ for (let i = 0; i < len; ++i) {
+ let word = "";
// This object should have exactly the same set of fields as the "crateRow"
// object defined above.
if (typeof itemNames[i] === "string") {
word = itemNames[i].toLowerCase();
- searchWords.push(word);
- } else {
- word = "";
- searchWords.push("");
}
+ searchWords.push(word);
const row = {
crate: crate,
- ty: itemTypes[i],
+ ty: itemTypes.charCodeAt(i) - charA,
name: itemNames[i],
path: itemPaths[i] ? itemPaths[i] : lastPath,
desc: itemDescs[i],
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 84df1b7d3..1cd552e7f 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -1,5 +1,5 @@
// Local js definitions:
-/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */
+/* global getSettingValue, getVirtualKey, updateLocalStorage, updateTheme */
/* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */
/* global MAIN_ID, getVar, getSettingsButton */
@@ -19,7 +19,7 @@
case "theme":
case "preferred-dark-theme":
case "preferred-light-theme":
- updateSystemTheme();
+ updateTheme();
updateLightAndDark();
break;
case "line-numbers":
@@ -48,13 +48,13 @@
}
function showLightAndDark() {
- removeClass(document.getElementById("preferred-light-theme").parentElement, "hidden");
- removeClass(document.getElementById("preferred-dark-theme").parentElement, "hidden");
+ removeClass(document.getElementById("preferred-light-theme"), "hidden");
+ removeClass(document.getElementById("preferred-dark-theme"), "hidden");
}
function hideLightAndDark() {
- addClass(document.getElementById("preferred-light-theme").parentElement, "hidden");
- addClass(document.getElementById("preferred-dark-theme").parentElement, "hidden");
+ addClass(document.getElementById("preferred-light-theme"), "hidden");
+ addClass(document.getElementById("preferred-dark-theme"), "hidden");
}
function updateLightAndDark() {
@@ -80,17 +80,6 @@
toggle.onkeyup = handleKey;
toggle.onkeyrelease = handleKey;
});
- onEachLazy(settingsElement.getElementsByClassName("select-wrapper"), elem => {
- const select = elem.getElementsByTagName("select")[0];
- const settingId = select.id;
- const settingValue = getSettingValue(settingId);
- if (settingValue !== null) {
- select.value = settingValue;
- }
- select.onchange = function() {
- changeSetting(this.id, this.value);
- };
- });
onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => {
const settingId = elem.name;
let settingValue = getSettingValue(settingId);
@@ -127,38 +116,40 @@
let output = "";
for (const setting of settings) {
- output += "<div class=\"setting-line\">";
const js_data_name = setting["js_name"];
const setting_name = setting["name"];
if (setting["options"] !== undefined) {
// This is a select setting.
output += `\
-<div class="radio-line" id="${js_data_name}">
- <div class="setting-name">${setting_name}</div>
-<div class="choices">`;
+<div class="setting-line" id="${js_data_name}">
+ <div class="setting-radio-name">${setting_name}</div>
+ <div class="setting-radio-choices">`;
onEach(setting["options"], option => {
const checked = option === setting["default"] ? " checked" : "";
const full = `${js_data_name}-${option.replace(/ /g,"-")}`;
output += `\
-<label for="${full}" class="choice">
- <input type="radio" name="${js_data_name}"
- id="${full}" value="${option}"${checked}>
- <span>${option}</span>
-</label>`;
+ <label for="${full}" class="setting-radio">
+ <input type="radio" name="${js_data_name}"
+ id="${full}" value="${option}"${checked}>
+ <span>${option}</span>
+ </label>`;
});
- output += "</div></div>";
+ output += `\
+ </div>
+</div>`;
} else {
// This is a checkbox toggle.
const checked = setting["default"] === true ? " checked" : "";
output += `\
-<label class="settings-toggle">\
- <input type="checkbox" id="${js_data_name}"${checked}>\
- <span class="label">${setting_name}</span>\
-</label>`;
+<div class="setting-line">\
+ <label class="setting-check">\
+ <input type="checkbox" id="${js_data_name}"${checked}>\
+ <span>${setting_name}</span>\
+ </label>\
+</div>`;
}
- output += "</div>";
}
return output;
}
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index 0e1c864e6..6c0f03b5b 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -117,8 +117,7 @@ function createSourceSidebar() {
sidebar.appendChild(title);
Object.keys(sourcesIndex).forEach(key => {
sourcesIndex[key][NAME_OFFSET] = key;
- hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "",
- hasFoundFile);
+ hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "", hasFoundFile);
});
container.appendChild(sidebar);
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index db2db83ca..c72ac254f 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -51,7 +51,6 @@ function hasClass(elem, className) {
return elem && elem.classList && elem.classList.contains(className);
}
-// eslint-disable-next-line no-unused-vars
function addClass(elem, className) {
if (!elem || !elem.classList) {
return;
@@ -153,79 +152,74 @@ function switchTheme(styleElem, mainStyleElem, newThemeName, saveTheme) {
}
}
-// This function is called from "main.js".
-// eslint-disable-next-line no-unused-vars
-function useSystemTheme(value) {
- if (value === undefined) {
- value = true;
- }
-
- updateLocalStorage("use-system-theme", value);
-
- // update the toggle if we're on the settings page
- const toggle = document.getElementById("use-system-theme");
- if (toggle && toggle instanceof HTMLInputElement) {
- toggle.checked = value;
- }
-}
-
-const updateSystemTheme = (function() {
- if (!window.matchMedia) {
- // fallback to the CSS computed value
- return () => {
- const cssTheme = getComputedStyle(document.documentElement)
- .getPropertyValue("content");
-
- switchTheme(
- window.currentTheme,
- window.mainTheme,
- JSON.parse(cssTheme) || "light",
- true
- );
+const updateTheme = (function() {
+ /**
+ * Update the current theme to match whatever the current combination of
+ * * the preference for using the system theme
+ * (if this is the case, the value of preferred-light-theme, if the
+ * system theme is light, otherwise if dark, the value of
+ * preferred-dark-theme.)
+ * * the preferred theme
+ * … dictates that it should be.
+ */
+ function updateTheme() {
+ const use = (theme, saveTheme) => {
+ switchTheme(window.currentTheme, window.mainTheme, theme, saveTheme);
};
- }
-
- // only listen to (prefers-color-scheme: dark) because light is the default
- const mql = window.matchMedia("(prefers-color-scheme: dark)");
- function handlePreferenceChange(mql) {
- const use = theme => {
- switchTheme(window.currentTheme, window.mainTheme, theme, true);
- };
// maybe the user has disabled the setting in the meantime!
if (getSettingValue("use-system-theme") !== "false") {
const lightTheme = getSettingValue("preferred-light-theme") || "light";
const darkTheme = getSettingValue("preferred-dark-theme") || "dark";
- if (mql.matches) {
- use(darkTheme);
+ if (isDarkMode()) {
+ use(darkTheme, true);
} else {
// prefers a light theme, or has no preference
- use(lightTheme);
+ use(lightTheme, true);
}
// note: we save the theme so that it doesn't suddenly change when
// the user disables "use-system-theme" and reloads the page or
// navigates to another page
} else {
- use(getSettingValue("theme"));
+ use(getSettingValue("theme"), false);
}
}
- mql.addListener(handlePreferenceChange);
+ // This is always updated below to a function () => bool.
+ let isDarkMode;
- return () => {
- handlePreferenceChange(mql);
- };
-})();
+ // Determine the function for isDarkMode, and if we have
+ // `window.matchMedia`, set up an event listener on the preferred color
+ // scheme.
+ //
+ // Otherwise, fall back to the prefers-color-scheme value CSS captured in
+ // the "content" property.
+ if (window.matchMedia) {
+ // only listen to (prefers-color-scheme: dark) because light is the default
+ const mql = window.matchMedia("(prefers-color-scheme: dark)");
-function switchToSavedTheme() {
- switchTheme(
- window.currentTheme,
- window.mainTheme,
- getSettingValue("theme") || "light",
- false
- );
-}
+ isDarkMode = () => mql.matches;
+
+ if (mql.addEventListener) {
+ mql.addEventListener("change", updateTheme);
+ } else {
+ // This is deprecated, see:
+ // https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/addListener
+ mql.addListener(updateTheme);
+ }
+ } else {
+ // fallback to the CSS computed value
+ const cssContent = getComputedStyle(document.documentElement)
+ .getPropertyValue("content");
+ // (Note: the double-quotes come from that this is a CSS value, which
+ // might be a length, string, etc.)
+ const cssColorScheme = cssContent || "\"light\"";
+ isDarkMode = () => (cssColorScheme === "\"dark\"");
+ }
+
+ return updateTheme;
+})();
if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
// update the preferred dark theme if the user is already using a dark theme
@@ -235,13 +229,10 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
&& darkThemes.indexOf(localStoredTheme) >= 0) {
updateLocalStorage("preferred-dark-theme", localStoredTheme);
}
-
- // call the function to initialize the theme at least once!
- updateSystemTheme();
-} else {
- switchToSavedTheme();
}
+updateTheme();
+
if (getSettingValue("source-sidebar-show") === "true") {
// At this point in page load, `document.body` is not available yet.
// Set a class on the `<html>` element instead.
@@ -259,6 +250,6 @@ if (getSettingValue("source-sidebar-show") === "true") {
// specifically when talking to a remote website with no caching.
window.addEventListener("pageshow", ev => {
if (ev.persisted) {
- setTimeout(switchToSavedTheme, 0);
+ setTimeout(updateTheme, 0);
}
});
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index b48b82307..767b974cc 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -102,9 +102,6 @@ static_files! {
scrape_examples_js => "static/js/scrape-examples.js",
wheel_svg => "static/images/wheel.svg",
clipboard_svg => "static/images/clipboard.svg",
- down_arrow_svg => "static/images/down-arrow.svg",
- toggle_minus_png => "static/images/toggle-minus.svg",
- toggle_plus_png => "static/images/toggle-plus.svg",
copyright => "static/COPYRIGHT.txt",
license_apache => "static/LICENSE-APACHE.txt",
license_mit => "static/LICENSE-MIT.txt",
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index fddda293b..7690d8f25 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -5,7 +5,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> {#- -#}
<meta name="generator" content="rustdoc"> {#- -#}
<meta name="description" content="{{page.description}}"> {#- -#}
- <meta name="keywords" content="{{page.keywords}}"> {#- -#}
<title>{{page.title}}</title> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_regular}}"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_regular}}"> {#- -#}
@@ -24,11 +23,13 @@
{%- for theme in themes -%}
<link rel="stylesheet" disabled href="{{page.root_path|safe}}{{theme}}{{page.resource_suffix}}.css"> {#- -#}
{%- endfor -%}
+ {%- if !layout.default_settings.is_empty() -%}
<script id="default-settings" {# -#}
{% for (k, v) in layout.default_settings %}
data-{{k}}="{{v}}"
{%- endfor -%}
></script> {#- -#}
+ {%- endif -%}
<script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {#- -#}
{%- if page.css_class.contains("crate") -%}
<script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
index ee2880bf6..3a1867b7f 100644
--- a/src/librustdoc/html/templates/print_item.html
+++ b/src/librustdoc/html/templates/print_item.html
@@ -6,7 +6,7 @@
<a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr>
{%- endfor -%}
<a class="{{item_type}}" href="#">{{name}}</a> {#- -#}
- <button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#}
+ <button id="copy-path" title="Copy item path to clipboard"> {#- -#}
<img src="{{static_root_path|safe}}{{clipboard_svg}}" {# -#}
width="19" height="18" {# -#}
alt="Copy item path"> {#- -#}