summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/html
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html')
-rw-r--r--src/librustdoc/html/format.rs45
-rw-r--r--src/librustdoc/html/highlight.rs355
-rw-r--r--src/librustdoc/html/highlight/fixtures/decorations.html6
-rw-r--r--src/librustdoc/html/highlight/fixtures/dos_line.html2
-rw-r--r--src/librustdoc/html/highlight/fixtures/highlight.html8
-rw-r--r--src/librustdoc/html/highlight/fixtures/sample.html39
-rw-r--r--src/librustdoc/html/highlight/fixtures/sample.rs1
-rw-r--r--src/librustdoc/html/highlight/fixtures/union.html10
-rw-r--r--src/librustdoc/html/highlight/tests.rs18
-rw-r--r--src/librustdoc/html/markdown.rs32
-rw-r--r--src/librustdoc/html/render/context.rs37
-rw-r--r--src/librustdoc/html/render/mod.rs399
-rw-r--r--src/librustdoc/html/render/print_item.rs95
-rw-r--r--src/librustdoc/html/render/search_index.rs13
-rw-r--r--src/librustdoc/html/render/span_map.rs34
-rw-r--r--src/librustdoc/html/render/write_shared.rs79
-rw-r--r--src/librustdoc/html/sources.rs22
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css597
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css279
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css216
-rw-r--r--src/librustdoc/html/static/css/themes/light.css214
-rw-r--r--src/librustdoc/html/static/images/down-arrow.svg2
-rw-r--r--src/librustdoc/html/static/js/main.js89
-rw-r--r--src/librustdoc/html/static/js/search.js31
-rw-r--r--src/librustdoc/html/static/js/source-script.js20
-rw-r--r--src/librustdoc/html/templates/page.html8
26 files changed, 1243 insertions, 1408 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 36a47b05c..b499e186c 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -152,7 +152,7 @@ impl Buffer {
}
}
-fn comma_sep<T: fmt::Display>(
+pub(crate) fn comma_sep<T: fmt::Display>(
items: impl Iterator<Item = T>,
space_after_comma: bool,
) -> impl fmt::Display {
@@ -349,8 +349,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
let where_preds = comma_sep(where_predicates, false);
let clause = if f.alternate() {
if ending == Ending::Newline {
- // add a space so stripping <br> tags and breaking spaces still renders properly
- format!(" where{where_preds}, ")
+ format!(" where{where_preds},")
} else {
format!(" where{where_preds}")
}
@@ -364,20 +363,16 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
if ending == Ending::Newline {
let mut clause = "&nbsp;".repeat(indent.saturating_sub(1));
- // add a space so stripping <br> tags and breaking spaces still renders properly
- write!(
- clause,
- " <span class=\"where fmt-newline\">where{where_preds},&nbsp;</span>"
- )?;
+ 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
if indent == 0 {
- format!(" <br><span class=\"where\">where{where_preds}</span>")
+ format!("<br><span class=\"where\">where{where_preds}</span>")
} else {
let mut clause = br_with_padding;
- clause.truncate(clause.len() - 5 * "&nbsp;".len());
- write!(clause, " <span class=\"where\">where{where_preds}</span>")?;
+ clause.truncate(clause.len() - 4 * "&nbsp;".len());
+ write!(clause, "<span class=\"where\">where{where_preds}</span>")?;
clause
}
}
@@ -592,7 +587,7 @@ fn generate_macro_def_id_path(
}
})
.collect();
- let relative = fqp.iter().map(|elem| elem.to_string());
+ let mut relative = fqp.iter().map(|elem| elem.to_string());
let cstore = CStore::from_tcx(tcx);
// We need this to prevent a `panic` when this function is used from intra doc links...
if !cstore.has_crate_data(def_id.krate) {
@@ -612,7 +607,7 @@ fn generate_macro_def_id_path(
let mut path = if is_macro_2 {
once(crate_name.clone()).chain(relative).collect()
} else {
- vec![crate_name.clone(), relative.last().unwrap()]
+ vec![crate_name.clone(), relative.next_back().unwrap()]
};
if path.len() < 2 {
// The minimum we can have is the crate name followed by the macro name. If shorter, then
@@ -1079,7 +1074,12 @@ fn fmt_type<'cx>(
write!(f, "impl {}", print_generic_bounds(bounds, cx))
}
}
- clean::QPath { ref assoc, ref self_type, ref trait_, should_show_cast } => {
+ clean::QPath(box clean::QPathData {
+ ref assoc,
+ ref self_type,
+ ref trait_,
+ should_show_cast,
+ }) => {
if f.alternate() {
if should_show_cast {
write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))?
@@ -1305,22 +1305,19 @@ impl clean::FnDecl {
/// <br>Used to determine line-wrapping.
/// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
/// necessary.
- /// * `asyncness`: Whether the function is async or not.
pub(crate) fn full_print<'a, 'tcx: 'a>(
&'a self,
header_len: usize,
indent: usize,
- asyncness: hir::IsAsync,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
- display_fn(move |f| self.inner_full_print(header_len, indent, asyncness, f, cx))
+ display_fn(move |f| self.inner_full_print(header_len, indent, f, cx))
}
fn inner_full_print(
&self,
header_len: usize,
indent: usize,
- asyncness: hir::IsAsync,
f: &mut fmt::Formatter<'_>,
cx: &Context<'_>,
) -> fmt::Result {
@@ -1385,15 +1382,9 @@ impl clean::FnDecl {
args_plain.push_str(", ...");
}
- let arrow_plain;
- let arrow = if let hir::IsAsync::Async = asyncness {
- let output = self.sugared_async_return_type();
- arrow_plain = format!("{:#}", output.print(cx));
- if f.alternate() { arrow_plain.clone() } else { format!("{}", output.print(cx)) }
- } else {
- arrow_plain = format!("{:#}", self.output.print(cx));
- if f.alternate() { arrow_plain.clone() } else { format!("{}", self.output.print(cx)) }
- };
+ let arrow_plain = format!("{:#}", self.output.print(cx));
+ let arrow =
+ if f.alternate() { arrow_plain.clone() } else { format!("{}", self.output.print(cx)) };
let declaration_len = header_len + args_plain.len() + arrow_plain.len();
let output = if declaration_len > 80 {
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 05547ea15..8922bf377 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -29,31 +29,74 @@ pub(crate) struct HrefContext<'a, 'b, 'c> {
/// This field is used to know "how far" from the top of the directory we are to link to either
/// documentation pages or other source pages.
pub(crate) root_path: &'c str,
+ /// This field is used to calculate precise local URLs.
+ pub(crate) current_href: &'c str,
}
/// Decorations are represented as a map from CSS class to vector of character ranges.
/// Each range will be wrapped in a span with that class.
+#[derive(Default)]
pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>);
-/// Highlights `src`, returning the HTML output.
-pub(crate) fn render_with_highlighting(
+#[derive(Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Tooltip {
+ Ignore,
+ CompileFail,
+ ShouldPanic,
+ Edition(Edition),
+ None,
+}
+
+/// Highlights `src` as an inline example, returning the HTML output.
+pub(crate) fn render_example_with_highlighting(
src: &str,
out: &mut Buffer,
- class: Option<&str>,
+ tooltip: Tooltip,
playground_button: Option<&str>,
- tooltip: Option<(Option<Edition>, &str)>,
- edition: Edition,
- extra_content: Option<Buffer>,
- href_context: Option<HrefContext<'_, '_, '_>>,
- decoration_info: Option<DecorationInfo>,
) {
- debug!("highlighting: ================\n{}\n==============", src);
- if let Some((edition_info, class)) = tooltip {
+ write_header(out, "rust-example-rendered", None, tooltip);
+ write_code(out, src, None, None);
+ 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);
+ write_code(out, src, None, None);
+ write_footer(out, None);
+}
+
+/// Highlights `src` as a source code page, returning the HTML output.
+pub(crate) fn render_source_with_highlighting(
+ src: &str,
+ out: &mut Buffer,
+ line_numbers: Buffer,
+ href_context: HrefContext<'_, '_, '_>,
+ decoration_info: DecorationInfo,
+) {
+ write_header(out, "", Some(line_numbers), Tooltip::None);
+ write_code(out, src, Some(href_context), Some(decoration_info));
+ write_footer(out, None);
+}
+
+fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, tooltip: Tooltip) {
+ write!(
+ out,
+ "<div class=\"example-wrap{}\">",
+ match tooltip {
+ Tooltip::Ignore => " ignore",
+ Tooltip::CompileFail => " compile_fail",
+ Tooltip::ShouldPanic => " should_panic",
+ Tooltip::Edition(_) => " edition",
+ Tooltip::None => "",
+ },
+ );
+
+ if tooltip != Tooltip::None {
write!(
out,
- "<div class='information'><div class='tooltip {}'{}>ⓘ</div></div>",
- class,
- if let Some(edition_info) = edition_info {
+ "<div class='tooltip'{}>ⓘ</div>",
+ if let Tooltip::Edition(edition_info) = tooltip {
format!(" data-edition=\"{}\"", edition_info)
} else {
String::new()
@@ -61,24 +104,115 @@ pub(crate) fn render_with_highlighting(
);
}
- write_header(out, class, extra_content);
- write_code(out, src, edition, href_context, decoration_info);
- write_footer(out, playground_button);
-}
-
-fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buffer>) {
- write!(out, "<div class=\"example-wrap\">");
if let Some(extra) = extra_content {
out.push_buffer(extra);
}
- if let Some(class) = class {
- write!(out, "<pre class=\"rust {}\">", class);
- } else {
+ if class.is_empty() {
write!(out, "<pre class=\"rust\">");
+ } else {
+ write!(out, "<pre class=\"rust {class}\">");
}
write!(out, "<code>");
}
+/// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
+/// basically (since it's `Option<Class>`). The following rules apply:
+///
+/// * If two `Class` have the same variant, then they can be merged.
+/// * If the other `Class` is unclassified and only contains white characters (backline,
+/// whitespace, etc), it can be merged.
+/// * `Class::Ident` is considered the same as unclassified (because it doesn't have an associated
+/// CSS class).
+fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool {
+ match (class1, class2) {
+ (Some(c1), Some(c2)) => c1.is_equal_to(c2),
+ (Some(Class::Ident(_)), None) | (None, Some(Class::Ident(_))) => true,
+ (Some(_), None) | (None, Some(_)) => text.trim().is_empty(),
+ (None, None) => true,
+ }
+}
+
+/// This type is used as a conveniency to prevent having to pass all its fields as arguments into
+/// the various functions (which became its methods).
+struct TokenHandler<'a, 'b, 'c, 'd, 'e> {
+ out: &'a mut Buffer,
+ /// It contains the closing tag and the associated `Class`.
+ closing_tags: Vec<(&'static str, Class)>,
+ /// This is used because we don't automatically generate the closing tag on `ExitSpan` in
+ /// case an `EnterSpan` event with the same class follows.
+ pending_exit_span: Option<Class>,
+ /// `current_class` and `pending_elems` are used to group HTML elements with same `class`
+ /// attributes to reduce the DOM size.
+ current_class: Option<Class>,
+ /// We need to keep the `Class` for each element because it could contain a `Span` which is
+ /// used to generate links.
+ pending_elems: Vec<(&'b str, Option<Class>)>,
+ href_context: Option<HrefContext<'c, 'd, 'e>>,
+}
+
+impl<'a, 'b, 'c, 'd, 'e> TokenHandler<'a, 'b, 'c, 'd, 'e> {
+ fn handle_exit_span(&mut self) {
+ // We can't get the last `closing_tags` element using `pop()` because `closing_tags` is
+ // being used in `write_pending_elems`.
+ let class = self.closing_tags.last().expect("ExitSpan without EnterSpan").1;
+ // We flush everything just in case...
+ self.write_pending_elems(Some(class));
+
+ exit_span(self.out, self.closing_tags.pop().expect("ExitSpan without EnterSpan").0);
+ self.pending_exit_span = None;
+ }
+
+ /// Write all the pending elements sharing a same (or at mergeable) `Class`.
+ ///
+ /// If there is a "parent" (if a `EnterSpan` event was encountered) and the parent can be merged
+ /// with the elements' class, then we simply write the elements since the `ExitSpan` event will
+ /// close the tag.
+ ///
+ /// Otherwise, if there is only one pending element, we let the `string` function handle both
+ /// opening and closing the tag, otherwise we do it into this function.
+ ///
+ /// It returns `true` if `current_class` must be set to `None` afterwards.
+ fn write_pending_elems(&mut self, current_class: Option<Class>) -> bool {
+ if self.pending_elems.is_empty() {
+ return false;
+ }
+ if let Some((_, parent_class)) = self.closing_tags.last() &&
+ can_merge(current_class, Some(*parent_class), "")
+ {
+ for (text, class) in self.pending_elems.iter() {
+ string(self.out, Escape(text), *class, &self.href_context, false);
+ }
+ } else {
+ // We only want to "open" the tag ourselves if we have more than one pending and if the
+ // current parent tag is not the same as our pending content.
+ let close_tag = if self.pending_elems.len() > 1 && current_class.is_some() {
+ Some(enter_span(self.out, current_class.unwrap(), &self.href_context))
+ } else {
+ None
+ };
+ for (text, class) in self.pending_elems.iter() {
+ string(self.out, Escape(text), *class, &self.href_context, close_tag.is_none());
+ }
+ if let Some(close_tag) = close_tag {
+ exit_span(self.out, close_tag);
+ }
+ }
+ self.pending_elems.clear();
+ true
+ }
+}
+
+impl<'a, 'b, 'c, 'd, 'e> Drop for TokenHandler<'a, 'b, 'c, 'd, 'e> {
+ /// When leaving, we need to flush all pending data to not have missing content.
+ fn drop(&mut self) {
+ if self.pending_exit_span.is_some() {
+ self.handle_exit_span();
+ } else {
+ self.write_pending_elems(self.current_class);
+ }
+ }
+}
+
/// Convert the given `src` source code into HTML by adding classes for highlighting.
///
/// This code is used to render code blocks (in the documentation) as well as the source code pages.
@@ -93,27 +227,74 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
fn write_code(
out: &mut Buffer,
src: &str,
- edition: Edition,
href_context: Option<HrefContext<'_, '_, '_>>,
decoration_info: Option<DecorationInfo>,
) {
// This replace allows to fix how the code source with DOS backline characters is displayed.
let src = src.replace("\r\n", "\n");
- let mut closing_tags: Vec<&'static str> = Vec::new();
+ let mut token_handler = TokenHandler {
+ out,
+ closing_tags: Vec::new(),
+ pending_exit_span: None,
+ current_class: None,
+ pending_elems: Vec::new(),
+ href_context,
+ };
+
Classifier::new(
&src,
- edition,
- href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
+ token_handler.href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
decoration_info,
)
.highlight(&mut |highlight| {
match highlight {
- Highlight::Token { text, class } => string(out, Escape(text), class, &href_context),
+ Highlight::Token { text, class } => {
+ // If we received a `ExitSpan` event and then have a non-compatible `Class`, we
+ // need to close the `<span>`.
+ let need_current_class_update = if let Some(pending) = token_handler.pending_exit_span &&
+ !can_merge(Some(pending), class, text) {
+ token_handler.handle_exit_span();
+ true
+ // If the two `Class` are different, time to flush the current content and start
+ // a new one.
+ } else if !can_merge(token_handler.current_class, class, text) {
+ token_handler.write_pending_elems(token_handler.current_class);
+ true
+ } else {
+ token_handler.current_class.is_none()
+ };
+
+ if need_current_class_update {
+ token_handler.current_class = class.map(Class::dummy);
+ }
+ token_handler.pending_elems.push((text, class));
+ }
Highlight::EnterSpan { class } => {
- closing_tags.push(enter_span(out, class, &href_context))
+ let mut should_add = true;
+ if let Some(pending_exit_span) = token_handler.pending_exit_span {
+ if class.is_equal_to(pending_exit_span) {
+ should_add = false;
+ } else {
+ token_handler.handle_exit_span();
+ }
+ } else {
+ // We flush everything just in case...
+ if token_handler.write_pending_elems(token_handler.current_class) {
+ token_handler.current_class = None;
+ }
+ }
+ if should_add {
+ let closing_tag = enter_span(token_handler.out, class, &token_handler.href_context);
+ token_handler.closing_tags.push((closing_tag, class));
+ }
+
+ token_handler.current_class = None;
+ token_handler.pending_exit_span = None;
}
Highlight::ExitSpan => {
- exit_span(out, closing_tags.pop().expect("ExitSpan without EnterSpan"))
+ token_handler.current_class = None;
+ token_handler.pending_exit_span =
+ Some(token_handler.closing_tags.last().as_ref().expect("ExitSpan without EnterSpan").1);
}
};
});
@@ -130,15 +311,15 @@ enum Class {
DocComment,
Attribute,
KeyWord,
- // Keywords that do pointer/reference stuff.
+ /// Keywords that do pointer/reference stuff.
RefKeyWord,
Self_(Span),
- Op,
Macro(Span),
MacroNonTerminal,
String,
Number,
Bool,
+ /// `Ident` isn't rendered in the HTML but we still need it for the `Span` it contains.
Ident(Span),
Lifetime,
PreludeTy,
@@ -148,6 +329,31 @@ enum Class {
}
impl Class {
+ /// It is only looking at the variant, not the variant content.
+ ///
+ /// It is used mostly to group multiple similar HTML elements into one `<span>` instead of
+ /// multiple ones.
+ fn is_equal_to(self, other: Self) -> bool {
+ match (self, other) {
+ (Self::Self_(_), Self::Self_(_))
+ | (Self::Macro(_), Self::Macro(_))
+ | (Self::Ident(_), Self::Ident(_)) => true,
+ (Self::Decoration(c1), Self::Decoration(c2)) => c1 == c2,
+ (x, y) => x == y,
+ }
+ }
+
+ /// If `self` contains a `Span`, it'll be replaced with `DUMMY_SP` to prevent creating links
+ /// on "empty content" (because of the attributes merge).
+ fn dummy(self) -> Self {
+ match self {
+ Self::Self_(_) => Self::Self_(DUMMY_SP),
+ Self::Macro(_) => Self::Macro(DUMMY_SP),
+ Self::Ident(_) => Self::Ident(DUMMY_SP),
+ s => s,
+ }
+ }
+
/// Returns the css class expected by rustdoc for each `Class`.
fn as_html(self) -> &'static str {
match self {
@@ -157,13 +363,12 @@ impl Class {
Class::KeyWord => "kw",
Class::RefKeyWord => "kw-2",
Class::Self_(_) => "self",
- Class::Op => "op",
Class::Macro(_) => "macro",
Class::MacroNonTerminal => "macro-nonterminal",
Class::String => "string",
Class::Number => "number",
Class::Bool => "bool-val",
- Class::Ident(_) => "ident",
+ Class::Ident(_) => "",
Class::Lifetime => "lifetime",
Class::PreludeTy => "prelude-ty",
Class::PreludeVal => "prelude-val",
@@ -182,7 +387,6 @@ impl Class {
| Self::Attribute
| Self::KeyWord
| Self::RefKeyWord
- | Self::Op
| Self::MacroNonTerminal
| Self::String
| Self::Number
@@ -220,7 +424,7 @@ impl<'a> Iterator for TokenIter<'a> {
}
/// Classifies into identifier class; returns `None` if this is a non-keyword identifier.
-fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option<Class> {
+fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option<Class> {
let ignore: &[&str] =
if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] };
if ignore.iter().any(|k| *k == text) {
@@ -229,7 +433,7 @@ fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool)
Some(match text {
"ref" | "mut" => Class::RefKeyWord,
"false" | "true" => Class::Bool,
- _ if Symbol::intern(text).is_reserved(|| edition) => Class::KeyWord,
+ _ if Symbol::intern(text).is_reserved(|| Edition::Edition2021) => Class::KeyWord,
_ => return None,
})
}
@@ -250,7 +454,7 @@ impl<'a> PeekIter<'a> {
fn new(iter: TokenIter<'a>) -> Self {
Self { stored: VecDeque::new(), peek_pos: 0, iter }
}
- /// Returns the next item after the current one. It doesn't interfer with `peek_next` output.
+ /// 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() {
@@ -259,7 +463,7 @@ impl<'a> PeekIter<'a> {
}
self.stored.front()
}
- /// Returns the next item after the last one peeked. It doesn't interfer with `peek` output.
+ /// Returns the next item after the last one peeked. It doesn't interfere with `peek` output.
fn peek_next(&mut self) -> Option<&(TokenKind, &'a str)> {
self.peek_pos += 1;
if self.peek_pos - 1 < self.stored.len() {
@@ -311,7 +515,6 @@ struct Classifier<'a> {
in_attribute: bool,
in_macro: bool,
in_macro_nonterminal: bool,
- edition: Edition,
byte_pos: u32,
file_span: Span,
src: &'a str,
@@ -321,12 +524,7 @@ struct Classifier<'a> {
impl<'a> Classifier<'a> {
/// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
/// file span which will be used later on by the `span_correspondance_map`.
- fn new(
- src: &str,
- edition: Edition,
- file_span: Span,
- decoration_info: Option<DecorationInfo>,
- ) -> Classifier<'_> {
+ fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> {
let tokens = PeekIter::new(TokenIter { src });
let decorations = decoration_info.map(Decorations::new);
Classifier {
@@ -334,7 +532,6 @@ impl<'a> Classifier<'a> {
in_attribute: false,
in_macro: false,
in_macro_nonterminal: false,
- edition,
byte_pos: 0,
file_span,
src,
@@ -354,7 +551,6 @@ impl<'a> Classifier<'a> {
let start = self.byte_pos as usize;
let mut pos = start;
let mut has_ident = false;
- let edition = self.edition;
loop {
let mut nb = 0;
@@ -376,7 +572,7 @@ impl<'a> Classifier<'a> {
if let Some((None, text)) = self.tokens.peek().map(|(token, text)| {
if *token == TokenKind::Ident {
- let class = get_real_ident_class(text, edition, true);
+ let class = get_real_ident_class(text, true);
(class, text)
} else {
// Doesn't matter which Class we put in here...
@@ -494,7 +690,7 @@ impl<'a> Classifier<'a> {
// or a reference or pointer type. Unless, of course, it looks like
// a logical and or a multiplication operator: `&&` or `* `.
TokenKind::Star => match self.tokens.peek() {
- Some((TokenKind::Whitespace, _)) => Class::Op,
+ Some((TokenKind::Whitespace, _)) => return no_highlight(sink),
Some((TokenKind::Ident, "mut")) => {
self.next();
sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) });
@@ -510,15 +706,15 @@ impl<'a> Classifier<'a> {
TokenKind::And => match self.tokens.peek() {
Some((TokenKind::And, _)) => {
self.next();
- sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
+ sink(Highlight::Token { text: "&&", class: None });
return;
}
Some((TokenKind::Eq, _)) => {
self.next();
- sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
+ sink(Highlight::Token { text: "&=", class: None });
return;
}
- Some((TokenKind::Whitespace, _)) => Class::Op,
+ Some((TokenKind::Whitespace, _)) => return no_highlight(sink),
Some((TokenKind::Ident, "mut")) => {
self.next();
sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) });
@@ -531,7 +727,7 @@ impl<'a> Classifier<'a> {
TokenKind::Eq => match lookahead {
Some(TokenKind::Eq) => {
self.next();
- sink(Highlight::Token { text: "==", class: Some(Class::Op) });
+ sink(Highlight::Token { text: "==", class: None });
return;
}
Some(TokenKind::Gt) => {
@@ -539,7 +735,7 @@ impl<'a> Classifier<'a> {
sink(Highlight::Token { text: "=>", class: None });
return;
}
- _ => Class::Op,
+ _ => return no_highlight(sink),
},
TokenKind::Minus if lookahead == Some(TokenKind::Gt) => {
self.next();
@@ -556,7 +752,7 @@ impl<'a> Classifier<'a> {
| TokenKind::Percent
| TokenKind::Bang
| TokenKind::Lt
- | TokenKind::Gt => Class::Op,
+ | TokenKind::Gt => return no_highlight(sink),
// Miscellaneous, no highlighting.
TokenKind::Dot
@@ -634,7 +830,7 @@ impl<'a> Classifier<'a> {
sink(Highlight::Token { text, class: None });
return;
}
- TokenKind::Ident => match get_real_ident_class(text, self.edition, false) {
+ TokenKind::Ident => match get_real_ident_class(text, false) {
None => match text {
"Option" | "Result" => Class::PreludeTy,
"Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
@@ -682,7 +878,7 @@ fn enter_span(
klass: Class,
href_context: &Option<HrefContext<'_, '_, '_>>,
) -> &'static str {
- string_without_closing_tag(out, "", Some(klass), href_context).expect(
+ string_without_closing_tag(out, "", Some(klass), href_context, true).expect(
"internal error: enter_span was called with Some(klass) but did not return a \
closing HTML tag",
)
@@ -714,8 +910,10 @@ fn string<T: Display>(
text: T,
klass: Option<Class>,
href_context: &Option<HrefContext<'_, '_, '_>>,
+ open_tag: bool,
) {
- if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context) {
+ if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag)
+ {
out.write_str(closing_tag);
}
}
@@ -734,6 +932,7 @@ fn string_without_closing_tag<T: Display>(
text: T,
klass: Option<Class>,
href_context: &Option<HrefContext<'_, '_, '_>>,
+ open_tag: bool,
) -> Option<&'static str> {
let Some(klass) = klass
else {
@@ -742,6 +941,10 @@ fn string_without_closing_tag<T: Display>(
};
let Some(def_span) = klass.get_span()
else {
+ if !open_tag {
+ write!(out, "{}", text);
+ return None;
+ }
write!(out, "<span class=\"{}\">{}", klass.as_html(), text);
return Some("</span>");
};
@@ -765,6 +968,7 @@ fn string_without_closing_tag<T: Display>(
path
});
}
+
if let Some(href_context) = href_context {
if let Some(href) =
href_context.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
@@ -775,9 +979,9 @@ fn string_without_closing_tag<T: Display>(
// a link to their definition can be generated using this:
// https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
match href {
- LinkFromSrc::Local(span) => context
- .href_from_span(*span, true)
- .map(|s| format!("{}{}", href_context.root_path, s)),
+ LinkFromSrc::Local(span) => {
+ context.href_from_span_relative(*span, href_context.current_href)
+ }
LinkFromSrc::External(def_id) => {
format::href_with_root_path(*def_id, context, Some(href_context.root_path))
.ok()
@@ -793,12 +997,33 @@ fn string_without_closing_tag<T: Display>(
}
})
{
- write!(out, "<a class=\"{}\" href=\"{}\">{}", klass.as_html(), href, text_s);
+ if !open_tag {
+ // We're already inside an element which has the same klass, no need to give it
+ // again.
+ write!(out, "<a href=\"{}\">{}", href, text_s);
+ } else {
+ let klass_s = klass.as_html();
+ if klass_s.is_empty() {
+ write!(out, "<a href=\"{}\">{}", href, text_s);
+ } else {
+ write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s);
+ }
+ }
return Some("</a>");
}
}
- write!(out, "<span class=\"{}\">{}", klass.as_html(), text_s);
- Some("</span>")
+ if !open_tag {
+ write!(out, "{}", text_s);
+ return None;
+ }
+ let klass_s = klass.as_html();
+ if klass_s.is_empty() {
+ write!(out, "{}", text_s);
+ Some("")
+ } else {
+ write!(out, "<span class=\"{}\">{}", klass_s, text_s);
+ Some("</span>")
+ }
}
#[cfg(test)]
diff --git a/src/librustdoc/html/highlight/fixtures/decorations.html b/src/librustdoc/html/highlight/fixtures/decorations.html
index 45f567880..ebf29f9cb 100644
--- a/src/librustdoc/html/highlight/fixtures/decorations.html
+++ b/src/librustdoc/html/highlight/fixtures/decorations.html
@@ -1,2 +1,4 @@
-<span class="example"><span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="number">1</span>;</span>
-<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="number">2</span>; \ No newline at end of file
+<span class="example"><span class="kw">let </span>x = <span class="number">1</span>;
+<span class="kw">let </span>y = <span class="number">2</span>;
+</span><span class="example2"><span class="kw">let </span>z = <span class="number">3</span>;
+</span><span class="kw">let </span>a = <span class="number">4</span>; \ No newline at end of file
diff --git a/src/librustdoc/html/highlight/fixtures/dos_line.html b/src/librustdoc/html/highlight/fixtures/dos_line.html
index 1c8dbffe7..30b50ca7c 100644
--- a/src/librustdoc/html/highlight/fixtures/dos_line.html
+++ b/src/librustdoc/html/highlight/fixtures/dos_line.html
@@ -1,3 +1,3 @@
-<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">foo</span>() {
+<span class="kw">pub fn </span>foo() {
<span class="macro">println!</span>(<span class="string">&quot;foo&quot;</span>);
}
diff --git a/src/librustdoc/html/highlight/fixtures/highlight.html b/src/librustdoc/html/highlight/fixtures/highlight.html
index abc2db179..9f73e03f9 100644
--- a/src/librustdoc/html/highlight/fixtures/highlight.html
+++ b/src/librustdoc/html/highlight/fixtures/highlight.html
@@ -1,4 +1,4 @@
-<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::a::foo</span>;
-<span class="kw">use</span> <span class="ident"><span class="self">self</span>::whatever</span>;
-<span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="ident"><span class="kw">super</span>::b::foo</span>;
-<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="ident"><span class="self">Self</span>::whatever</span>; \ No newline at end of file
+<span class="kw">use </span><span class="kw">crate</span>::a::foo;
+<span class="kw">use </span><span class="self">self</span>::whatever;
+<span class="kw">let </span>x = <span class="kw">super</span>::b::foo;
+<span class="kw">let </span>y = <span class="self">Self</span>::whatever; \ No newline at end of file
diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html
index b117a12e3..4a5a3cf60 100644
--- a/src/librustdoc/html/highlight/fixtures/sample.html
+++ b/src/librustdoc/html/highlight/fixtures/sample.html
@@ -8,30 +8,31 @@
.lifetime { color: #B76514; }
.question-mark { color: #ff9011; }
</style>
-<pre><code><span class="attribute">#![<span class="ident">crate_type</span> <span class="op">=</span> <span class="string">&quot;lib&quot;</span>]</span>
+<pre><code><span class="attribute">#![crate_type = <span class="string">&quot;lib&quot;</span>]
-<span class="kw">use</span> <span class="ident">std::path</span>::{<span class="ident">Path</span>, <span class="ident">PathBuf</span>};
+</span><span class="kw">use </span>std::path::{Path, PathBuf};
-<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> <span class="op">=</span> <span class="string">&quot;linux&quot;</span>)]</span>
-<span class="kw">fn</span> <span class="ident">main</span>() -&gt; () {
- <span class="kw">let</span> <span class="ident">foo</span> <span class="op">=</span> <span class="bool-val">true</span> <span class="op">&amp;&amp;</span> <span class="bool-val">false</span> <span class="op">|</span><span class="op">|</span> <span class="bool-val">true</span>;
- <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*const</span> () <span class="op">=</span> <span class="number">0</span>;
- <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="ident">foo</span>;
- <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="op">&amp;&amp;</span><span class="ident">foo</span>;
- <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">*</span><span class="ident">foo</span>;
- <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&amp;mut</span> <span class="ident">bar</span>);
- <span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op">&lt;</span> <span class="ident">N</span> <span class="op">&amp;&amp;</span> <span class="ident">index</span> <span class="op">&lt;</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
- <span class="ident">::std::env::var</span>(<span class="string">&quot;gateau&quot;</span>).<span class="ident">is_ok</span>();
- <span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span>
- <span class="kw">let</span> <span class="ident">s</span>:<span class="ident">std::path::PathBuf</span> <span class="op">=</span> <span class="ident">std::path::PathBuf::new</span>();
- <span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">s</span> <span class="op">=</span> <span class="ident">String::new</span>();
+<span class="attribute">#[cfg(target_os = <span class="string">&quot;linux&quot;</span>)]
+#[cfg(target_os = <span class="string">&quot;windows&quot;</span>)]
+</span><span class="kw">fn </span>main() -&gt; () {
+ <span class="kw">let </span>foo = <span class="bool-val">true </span>&amp;&amp; <span class="bool-val">false </span>|| <span class="bool-val">true</span>;
+ <span class="kw">let _</span>: <span class="kw-2">*const </span>() = <span class="number">0</span>;
+ <span class="kw">let _ </span>= <span class="kw-2">&amp;</span>foo;
+ <span class="kw">let _ </span>= &amp;&amp;foo;
+ <span class="kw">let _ </span>= <span class="kw-2">*</span>foo;
+ <span class="macro">mac!</span>(foo, <span class="kw-2">&amp;mut </span>bar);
+ <span class="macro">assert!</span>(<span class="self">self</span>.length &lt; N &amp;&amp; index &lt;= <span class="self">self</span>.length);
+ ::std::env::var(<span class="string">&quot;gateau&quot;</span>).is_ok();
+ <span class="attribute">#[rustfmt::skip]
+ </span><span class="kw">let </span>s:std::path::PathBuf = std::path::PathBuf::new();
+ <span class="kw">let </span><span class="kw-2">mut </span>s = String::new();
- <span class="kw">match</span> <span class="kw-2">&amp;</span><span class="ident">s</span> {
- <span class="kw-2">ref</span> <span class="kw-2">mut</span> <span class="ident">x</span> =&gt; {}
+ <span class="kw">match </span><span class="kw-2">&amp;</span>s {
+ <span class="kw-2">ref mut </span>x =&gt; {}
}
}
-<span class="macro">macro_rules!</span> <span class="ident">bar</span> {
- (<span class="macro-nonterminal">$</span><span class="macro-nonterminal">foo</span>:<span class="ident">tt</span>) =&gt; {};
+<span class="macro">macro_rules! </span>bar {
+ (<span class="macro-nonterminal">$foo</span>:tt) =&gt; {};
}
</code></pre>
diff --git a/src/librustdoc/html/highlight/fixtures/sample.rs b/src/librustdoc/html/highlight/fixtures/sample.rs
index fbfdc6767..ef85b566c 100644
--- a/src/librustdoc/html/highlight/fixtures/sample.rs
+++ b/src/librustdoc/html/highlight/fixtures/sample.rs
@@ -3,6 +3,7 @@
use std::path::{Path, PathBuf};
#[cfg(target_os = "linux")]
+#[cfg(target_os = "windows")]
fn main() -> () {
let foo = true && false || true;
let _: *const () = 0;
diff --git a/src/librustdoc/html/highlight/fixtures/union.html b/src/librustdoc/html/highlight/fixtures/union.html
index c0acf31a0..9f8915282 100644
--- a/src/librustdoc/html/highlight/fixtures/union.html
+++ b/src/librustdoc/html/highlight/fixtures/union.html
@@ -1,8 +1,8 @@
-<span class="kw">union</span> <span class="ident">Foo</span> {
- <span class="ident">i</span>: <span class="ident">i8</span>,
- <span class="ident">u</span>: <span class="ident">i8</span>,
+<span class="kw">union </span>Foo {
+ i: i8,
+ u: i8,
}
-<span class="kw">fn</span> <span class="ident">main</span>() {
- <span class="kw">let</span> <span class="ident">union</span> <span class="op">=</span> <span class="number">0</span>;
+<span class="kw">fn </span>main() {
+ <span class="kw">let </span>union = <span class="number">0</span>;
}
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 1fea7e983..a5e633df4 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -3,7 +3,6 @@ use crate::html::format::Buffer;
use expect_test::expect_file;
use rustc_data_structures::fx::FxHashMap;
use rustc_span::create_default_session_globals_then;
-use rustc_span::edition::Edition;
const STYLE: &str = r#"
<style>
@@ -23,7 +22,7 @@ fn test_html_highlighting() {
let src = include_str!("fixtures/sample.rs");
let html = {
let mut out = Buffer::new();
- write_code(&mut out, src, Edition::Edition2018, None, None);
+ write_code(&mut out, src, None, None);
format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
};
expect_file!["fixtures/sample.html"].assert_eq(&html);
@@ -37,7 +36,7 @@ fn test_dos_backline() {
println!(\"foo\");\r\n\
}\r\n";
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None, None);
+ write_code(&mut html, src, None, None);
expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
});
}
@@ -51,7 +50,7 @@ let x = super::b::foo;
let y = Self::whatever;";
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None, None);
+ write_code(&mut html, src, None, None);
expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
});
}
@@ -61,7 +60,7 @@ fn test_union_highlighting() {
create_default_session_globals_then(|| {
let src = include_str!("fixtures/union.rs");
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None, None);
+ write_code(&mut html, src, None, None);
expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
});
}
@@ -70,12 +69,15 @@ fn test_union_highlighting() {
fn test_decorations() {
create_default_session_globals_then(|| {
let src = "let x = 1;
-let y = 2;";
+let y = 2;
+let z = 3;
+let a = 4;";
let mut decorations = FxHashMap::default();
- decorations.insert("example", vec![(0, 10)]);
+ decorations.insert("example", vec![(0, 10), (11, 21)]);
+ decorations.insert("example2", vec![(22, 32)]);
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations)));
+ write_code(&mut html, src, None, Some(DecorationInfo(decorations)));
expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
});
}
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 52a2effca..43d07d4a5 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -330,34 +330,27 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
});
let tooltip = if ignore != Ignore::None {
- Some((None, "ignore"))
+ highlight::Tooltip::Ignore
} else if compile_fail {
- Some((None, "compile_fail"))
+ highlight::Tooltip::CompileFail
} else if should_panic {
- Some((None, "should_panic"))
+ highlight::Tooltip::ShouldPanic
} else if explicit_edition {
- Some((Some(edition), "edition"))
+ highlight::Tooltip::Edition(edition)
} else {
- None
+ highlight::Tooltip::None
};
// insert newline to clearly separate it from the
// previous block so we can shorten the html output
let mut s = Buffer::new();
s.push_str("\n");
- highlight::render_with_highlighting(
+
+ highlight::render_example_with_highlighting(
&text,
&mut s,
- Some(&format!(
- "rust-example-rendered{}",
- if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() }
- )),
- playground_button.as_deref(),
tooltip,
- edition,
- None,
- None,
- None,
+ playground_button.as_deref(),
);
Some(Event::Html(s.into_inner().into()))
}
@@ -1126,7 +1119,11 @@ impl MarkdownSummaryLine<'_> {
let mut s = String::new();
- html::push_html(&mut s, LinkReplacer::new(SummaryLine::new(p), links));
+ let without_paragraphs = LinkReplacer::new(SummaryLine::new(p), links).filter(|event| {
+ !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph))
+ });
+
+ html::push_html(&mut s, without_paragraphs);
s
}
@@ -1446,6 +1443,8 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
map.insert("not-displayed".into(), 1);
map.insert("alternative-display".into(), 1);
map.insert("search".into(), 1);
+ map.insert("crate-search".into(), 1);
+ map.insert("crate-search-div".into(), 1);
// This is the list of IDs used in HTML generated in Rust (including the ones
// used in tera template files).
map.insert("mainThemeStyle".into(), 1);
@@ -1453,7 +1452,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
map.insert("settings-menu".into(), 1);
map.insert("help-button".into(), 1);
map.insert("main-content".into(), 1);
- map.insert("crate-search".into(), 1);
map.insert("toggle-all-docs".into(), 1);
map.insert("all-types".into(), 1);
map.insert("default-settings".into(), 1);
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 2ed7a6f1b..62def4a94 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -31,6 +31,7 @@ use crate::formats::FormatRenderer;
use crate::html::escape::Escape;
use crate::html::format::{join_with_double_colon, Buffer};
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
+use crate::html::url_parts_builder::UrlPartsBuilder;
use crate::html::{layout, sources};
use crate::scrape_examples::AllCallLocations;
use crate::try_err;
@@ -71,7 +72,7 @@ pub(crate) struct Context<'tcx> {
}
// `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(not(windows), target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Context<'_>, 128);
/// Shared mutable state used in [`Context`] and elsewhere.
@@ -301,13 +302,10 @@ impl<'tcx> Context<'tcx> {
/// may happen, for example, with externally inlined items where the source
/// of their crate documentation isn't known.
pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
- self.href_from_span(item.span(self.tcx()), true)
+ self.href_from_span(item.span(self.tcx())?, true)
}
pub(crate) fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option<String> {
- if span.is_dummy() {
- return None;
- }
let mut root = self.root_path();
let mut path = String::new();
let cnum = span.cnum(self.sess());
@@ -373,6 +371,35 @@ impl<'tcx> Context<'tcx> {
anchor = anchor
))
}
+
+ pub(crate) fn href_from_span_relative(
+ &self,
+ span: clean::Span,
+ relative_to: &str,
+ ) -> Option<String> {
+ self.href_from_span(span, false).map(|s| {
+ let mut url = UrlPartsBuilder::new();
+ let mut dest_href_parts = s.split('/');
+ let mut cur_href_parts = relative_to.split('/');
+ for (cur_href_part, dest_href_part) in (&mut cur_href_parts).zip(&mut dest_href_parts) {
+ if cur_href_part != dest_href_part {
+ url.push(dest_href_part);
+ break;
+ }
+ }
+ for dest_href_part in dest_href_parts {
+ url.push(dest_href_part);
+ }
+ let loline = span.lo(self.sess()).line;
+ let hiline = span.hi(self.sess()).line;
+ format!(
+ "{}{}#{}",
+ "../".repeat(cur_href_parts.count()),
+ url.finish(),
+ if loline == hiline { loline.to_string() } else { format!("{loline}-{hiline}") }
+ )
+ })
+ }
}
/// Generates the documentation for `crate` into the directory `dst`
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index a262c8f7d..1e6f20d2b 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -191,12 +191,6 @@ impl StylePath {
}
}
-fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
- if let Some(l) = cx.src_href(item) {
- write!(buf, "<a class=\"srclink\" href=\"{}\">source</a>", l)
- }
-}
-
#[derive(Debug, Eq, PartialEq, Hash)]
struct ItemEntry {
url: String,
@@ -522,7 +516,14 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<Strin
(cfg, _) => cfg.as_deref().cloned(),
};
- debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.and_then(|p| p.cfg.as_ref()), cfg);
+ debug!(
+ "Portability {:?} {:?} (parent: {:?}) - {:?} = {:?}",
+ item.name,
+ item.cfg,
+ parent,
+ parent.and_then(|p| p.cfg.as_ref()),
+ cfg
+ );
Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html()))
}
@@ -569,7 +570,10 @@ fn short_item_info(
message.push_str(&format!(": {}", html.into_string()));
}
extra_info.push(format!(
- "<div class=\"stab deprecated\"><span class=\"emoji\">👎</span> {}</div>",
+ "<div class=\"stab deprecated\">\
+ <span class=\"emoji\">👎</span>\
+ <span>{}</span>\
+ </div>",
message,
));
}
@@ -582,8 +586,9 @@ fn short_item_info(
.filter(|stab| stab.feature != sym::rustc_private)
.map(|stab| (stab.level, stab.feature))
{
- let mut message =
- "<span class=\"emoji\">🔬</span> This is a nightly-only experimental API.".to_owned();
+ let mut message = "<span class=\"emoji\">🔬</span>\
+ <span>This is a nightly-only experimental API."
+ .to_owned();
let mut feature = format!("<code>{}</code>", Escape(feature.as_str()));
if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
@@ -594,7 +599,7 @@ fn short_item_info(
));
}
- message.push_str(&format!(" ({})", feature));
+ message.push_str(&format!(" ({})</span>", feature));
extra_info.push(format!("<div class=\"stab unstable\">{}</div>", message));
}
@@ -608,10 +613,10 @@ fn short_item_info(
// Render the list of items inside one of the sections "Trait Implementations",
// "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
-fn render_impls(
+pub(crate) fn render_impls(
cx: &mut Context<'_>,
w: &mut Buffer,
- impls: &[&&Impl],
+ impls: &[&Impl],
containing_item: &clean::Item,
toggle_open_by_default: bool,
) {
@@ -816,7 +821,7 @@ fn assoc_method(
href = href,
name = name,
generics = g.print(cx),
- decl = d.full_print(header_len, indent, header.asyncness, cx),
+ decl = d.full_print(header_len, indent, cx),
notable_traits = notable_traits_decl(d, cx),
where_clause = print_where_clause(g, cx, indent, end_newline),
)
@@ -836,12 +841,13 @@ fn assoc_method(
/// Note that it is possible for an unstable function to be const-stable. In that case, the span
/// will include the const-stable version, but no stable version will be emitted, as a natural
/// consequence of the above rules.
-fn render_stability_since_raw(
+fn render_stability_since_raw_with_extra(
w: &mut Buffer,
ver: Option<Symbol>,
const_stability: Option<ConstStability>,
containing_ver: Option<Symbol>,
containing_const_ver: Option<Symbol>,
+ extra_class: &str,
) -> bool {
let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver);
@@ -889,12 +895,30 @@ fn render_stability_since_raw(
}
if !stability.is_empty() {
- write!(w, r#"<span class="since" title="{}">{}</span>"#, title, stability);
+ write!(w, r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#);
}
!stability.is_empty()
}
+#[inline]
+fn render_stability_since_raw(
+ w: &mut Buffer,
+ ver: Option<Symbol>,
+ const_stability: Option<ConstStability>,
+ containing_ver: Option<Symbol>,
+ containing_const_ver: Option<Symbol>,
+) -> bool {
+ render_stability_since_raw_with_extra(
+ w,
+ ver,
+ const_stability,
+ containing_ver,
+ containing_const_ver,
+ "",
+ )
+}
+
fn render_assoc_item(
w: &mut Buffer,
item: &clean::Item,
@@ -1001,6 +1025,47 @@ impl<'a> AssocItemLink<'a> {
}
}
+fn write_impl_section_heading(w: &mut Buffer, title: &str, id: &str) {
+ write!(
+ w,
+ "<h2 id=\"{id}\" class=\"small-section-header\">\
+ {title}\
+ <a href=\"#{id}\" class=\"anchor\"></a>\
+ </h2>"
+ );
+}
+
+pub(crate) fn render_all_impls(
+ w: &mut Buffer,
+ cx: &mut Context<'_>,
+ containing_item: &clean::Item,
+ concrete: &[&Impl],
+ synthetic: &[&Impl],
+ blanket_impl: &[&Impl],
+) {
+ let mut impls = Buffer::empty_from(w);
+ render_impls(cx, &mut impls, concrete, containing_item, true);
+ let impls = impls.into_inner();
+ if !impls.is_empty() {
+ write_impl_section_heading(w, "Trait Implementations", "trait-implementations");
+ write!(w, "<div id=\"trait-implementations-list\">{}</div>", impls);
+ }
+
+ if !synthetic.is_empty() {
+ write_impl_section_heading(w, "Auto Trait Implementations", "synthetic-implementations");
+ w.write_str("<div id=\"synthetic-implementations-list\">");
+ render_impls(cx, w, synthetic, containing_item, false);
+ w.write_str("</div>");
+ }
+
+ if !blanket_impl.is_empty() {
+ write_impl_section_heading(w, "Blanket Implementations", "blanket-implementations");
+ w.write_str("<div id=\"blanket-implementations-list\">");
+ render_impls(cx, w, blanket_impl, containing_item, false);
+ w.write_str("</div>");
+ }
+}
+
fn render_assoc_items(
w: &mut Buffer,
cx: &mut Context<'_>,
@@ -1030,12 +1095,7 @@ fn render_assoc_items_inner(
let mut tmp_buf = Buffer::empty_from(w);
let (render_mode, id) = match what {
AssocItemRender::All => {
- tmp_buf.write_str(
- "<h2 id=\"implementations\" class=\"small-section-header\">\
- Implementations\
- <a href=\"#implementations\" class=\"anchor\"></a>\
- </h2>",
- );
+ write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations");
(RenderMode::Normal, "implementations-list".to_owned())
}
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
@@ -1044,15 +1104,14 @@ fn render_assoc_items_inner(
if let Some(def_id) = type_.def_id(cx.cache()) {
cx.deref_id_map.insert(def_id, id.clone());
}
- write!(
- tmp_buf,
- "<h2 id=\"{id}\" class=\"small-section-header\">\
- <span>Methods from {trait_}&lt;Target = {type_}&gt;</span>\
- <a href=\"#{id}\" class=\"anchor\"></a>\
- </h2>",
- id = id,
- trait_ = trait_.print(cx),
- type_ = type_.print(cx),
+ write_impl_section_heading(
+ &mut tmp_buf,
+ &format!(
+ "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
+ trait_ = trait_.print(cx),
+ type_ = type_.print(cx),
+ ),
+ &id,
);
(RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id))
}
@@ -1099,49 +1158,12 @@ fn render_assoc_items_inner(
return;
}
- let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
- traits.iter().partition(|t| t.inner_impl().kind.is_auto());
- let (blanket_impl, concrete): (Vec<&&Impl>, _) =
+ let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
+ traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
+ let (blanket_impl, concrete): (Vec<&Impl>, _) =
concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
- let mut impls = Buffer::empty_from(w);
- render_impls(cx, &mut impls, &concrete, containing_item, true);
- let impls = impls.into_inner();
- if !impls.is_empty() {
- write!(
- w,
- "<h2 id=\"trait-implementations\" class=\"small-section-header\">\
- Trait Implementations\
- <a href=\"#trait-implementations\" class=\"anchor\"></a>\
- </h2>\
- <div id=\"trait-implementations-list\">{}</div>",
- impls
- );
- }
-
- if !synthetic.is_empty() {
- w.write_str(
- "<h2 id=\"synthetic-implementations\" class=\"small-section-header\">\
- Auto Trait Implementations\
- <a href=\"#synthetic-implementations\" class=\"anchor\"></a>\
- </h2>\
- <div id=\"synthetic-implementations-list\">",
- );
- render_impls(cx, w, &synthetic, containing_item, false);
- w.write_str("</div>");
- }
-
- if !blanket_impl.is_empty() {
- w.write_str(
- "<h2 id=\"blanket-implementations\" class=\"small-section-header\">\
- Blanket Implementations\
- <a href=\"#blanket-implementations\" class=\"anchor\"></a>\
- </h2>\
- <div id=\"blanket-implementations-list\">",
- );
- render_impls(cx, w, &blanket_impl, containing_item, false);
- w.write_str("</div>");
- }
+ render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl);
}
}
@@ -1550,6 +1572,15 @@ fn render_impl(
rendering_params: ImplRenderingParameters,
) {
for trait_item in &t.items {
+ // Skip over any default trait items that are impossible to call
+ // (e.g. if it has a `Self: Sized` bound on an unsized type).
+ if let Some(impl_def_id) = parent.item_id.as_def_id()
+ && let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
+ && cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
+ {
+ continue;
+ }
+
let n = trait_item.name;
if i.items.iter().any(|m| m.name == n) {
continue;
@@ -1668,23 +1699,29 @@ fn render_rightside(
RenderMode::Normal => (item.const_stability(tcx), containing_item.const_stable_since(tcx)),
RenderMode::ForDeref { .. } => (None, None),
};
+ let src_href = cx.src_href(item);
+ let has_src_ref = src_href.is_some();
let mut rightside = Buffer::new();
- let has_stability = render_stability_since_raw(
+ let has_stability = render_stability_since_raw_with_extra(
&mut rightside,
item.stable_since(tcx),
const_stability,
containing_item.stable_since(tcx),
const_stable_since,
+ if has_src_ref { "" } else { " rightside" },
);
- let mut srclink = Buffer::empty_from(w);
- write_srclink(cx, item, &mut srclink);
- if has_stability && !srclink.is_empty() {
- rightside.write_str(" · ");
+ if let Some(l) = src_href {
+ if has_stability {
+ write!(rightside, " · <a class=\"srclink\" href=\"{}\">source</a>", l)
+ } else {
+ write!(rightside, "<a class=\"srclink rightside\" href=\"{}\">source</a>", l)
+ }
}
- rightside.push_buffer(srclink);
- if !rightside.is_empty() {
+ if has_stability && has_src_ref {
write!(w, "<span class=\"rightside\">{}</span>", rightside.into_inner());
+ } else {
+ w.push_buffer(rightside);
}
}
@@ -1700,8 +1737,8 @@ pub(crate) fn render_impl_summary(
// in documentation pages for trait with automatic implementations like "Send" and "Sync".
aliases: &[String],
) {
- let id =
- cx.derive_id(get_id_for_impl(&i.inner_impl().for_, i.inner_impl().trait_.as_ref(), cx));
+ let inner_impl = i.inner_impl();
+ let id = cx.derive_id(get_id_for_impl(&inner_impl.for_, inner_impl.trait_.as_ref(), cx));
let aliases = if aliases.is_empty() {
String::new()
} else {
@@ -1713,9 +1750,9 @@ pub(crate) fn render_impl_summary(
write!(w, "<h3 class=\"code-header in-band\">");
if let Some(use_absolute) = use_absolute {
- write!(w, "{}", i.inner_impl().print(use_absolute, cx));
+ write!(w, "{}", inner_impl.print(use_absolute, cx));
if show_def_docs {
- for it in &i.inner_impl().items {
+ for it in &inner_impl.items {
if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
w.write_str("<span class=\"where fmt-newline\"> ");
assoc_type(
@@ -1733,11 +1770,11 @@ pub(crate) fn render_impl_summary(
}
}
} else {
- write!(w, "{}", i.inner_impl().print(false, cx));
+ write!(w, "{}", inner_impl.print(false, cx));
}
write!(w, "</h3>");
- let is_trait = i.inner_impl().trait_.is_some();
+ let is_trait = inner_impl.trait_.is_some();
if is_trait {
if let Some(portability) = portability(&i.impl_item, Some(parent)) {
write!(w, "<span class=\"item-info\">{}</span>", portability);
@@ -1931,6 +1968,70 @@ fn small_url_encode(s: String) -> String {
}
}
+pub(crate) fn sidebar_render_assoc_items(
+ cx: &Context<'_>,
+ out: &mut Buffer,
+ id_map: &mut IdMap,
+ concrete: Vec<&Impl>,
+ synthetic: Vec<&Impl>,
+ blanket_impl: Vec<&Impl>,
+) {
+ let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| {
+ let mut links = FxHashSet::default();
+
+ let mut ret = impls
+ .iter()
+ .filter_map(|it| {
+ let trait_ = it.inner_impl().trait_.as_ref()?;
+ let encoded =
+ id_map.derive(get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx));
+
+ let i_display = format!("{:#}", trait_.print(cx));
+ let out = Escape(&i_display);
+ let prefix = match it.inner_impl().polarity {
+ ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
+ ty::ImplPolarity::Negative => "!",
+ };
+ let generated = format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out);
+ if links.insert(generated.clone()) { Some(generated) } else { None }
+ })
+ .collect::<Vec<String>>();
+ ret.sort();
+ ret
+ };
+
+ let concrete_format = format_impls(concrete, id_map);
+ let synthetic_format = format_impls(synthetic, id_map);
+ let blanket_format = format_impls(blanket_impl, id_map);
+
+ if !concrete_format.is_empty() {
+ print_sidebar_block(
+ out,
+ "trait-implementations",
+ "Trait Implementations",
+ concrete_format.iter(),
+ );
+ }
+
+ if !synthetic_format.is_empty() {
+ print_sidebar_block(
+ out,
+ "synthetic-implementations",
+ "Auto Trait Implementations",
+ synthetic_format.iter(),
+ );
+ }
+
+ if !blanket_format.is_empty() {
+ print_sidebar_block(
+ out,
+ "blanket-implementations",
+ "Blanket Implementations",
+ blanket_format.iter(),
+ );
+ }
+}
+
fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
let did = it.item_id.expect_def_id();
let cache = cx.cache();
@@ -1976,68 +2077,15 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
{
let mut derefs = FxHashSet::default();
derefs.insert(did);
- sidebar_deref_methods(cx, out, impl_, v, &mut derefs);
+ sidebar_deref_methods(cx, out, impl_, v, &mut derefs, &mut used_links);
}
- let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| {
- let mut links = FxHashSet::default();
-
- let mut ret = impls
- .iter()
- .filter_map(|it| {
- let trait_ = it.inner_impl().trait_.as_ref()?;
- let encoded =
- id_map.derive(get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx));
-
- let i_display = format!("{:#}", trait_.print(cx));
- let out = Escape(&i_display);
- let prefix = match it.inner_impl().polarity {
- ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
- ty::ImplPolarity::Negative => "!",
- };
- let generated = format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out);
- if links.insert(generated.clone()) { Some(generated) } else { None }
- })
- .collect::<Vec<String>>();
- ret.sort();
- ret
- };
-
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
concrete.into_iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_blanket());
- let concrete_format = format_impls(concrete, &mut id_map);
- let synthetic_format = format_impls(synthetic, &mut id_map);
- let blanket_format = format_impls(blanket_impl, &mut id_map);
-
- if !concrete_format.is_empty() {
- print_sidebar_block(
- out,
- "trait-implementations",
- "Trait Implementations",
- concrete_format.iter(),
- );
- }
-
- if !synthetic_format.is_empty() {
- print_sidebar_block(
- out,
- "synthetic-implementations",
- "Auto Trait Implementations",
- synthetic_format.iter(),
- );
- }
-
- if !blanket_format.is_empty() {
- print_sidebar_block(
- out,
- "blanket-implementations",
- "Blanket Implementations",
- blanket_format.iter(),
- );
- }
+ sidebar_render_assoc_items(cx, out, &mut id_map, concrete, synthetic, blanket_impl);
}
}
}
@@ -2048,6 +2096,7 @@ fn sidebar_deref_methods(
impl_: &Impl,
v: &[Impl],
derefs: &mut FxHashSet<DefId>,
+ used_links: &mut FxHashSet<String>,
) {
let c = cx.cache();
@@ -2080,13 +2129,10 @@ fn sidebar_deref_methods(
.and_then(|did| c.impls.get(&did));
if let Some(impls) = inner_impl {
debug!("found inner_impl: {:?}", impls);
- let mut used_links = FxHashSet::default();
let mut ret = impls
.iter()
.filter(|i| i.inner_impl().trait_.is_none())
- .flat_map(|i| {
- get_methods(i.inner_impl(), true, &mut used_links, deref_mut, cx.tcx())
- })
+ .flat_map(|i| get_methods(i.inner_impl(), true, used_links, deref_mut, cx.tcx()))
.collect::<Vec<_>>();
if !ret.is_empty() {
let id = if let Some(target_def_id) = real_target.def_id(c) {
@@ -2115,7 +2161,14 @@ fn sidebar_deref_methods(
.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);
+ sidebar_deref_methods(
+ cx,
+ out,
+ target_deref_impl,
+ target_impls,
+ derefs,
+ used_links,
+ );
}
}
}
@@ -2302,9 +2355,54 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
buf.push_str("</section>")
}
+/// Returns the list of implementations for the primitive reference type, filtering out any
+/// implementations that are on concrete or partially generic types, only keeping implementations
+/// of the form `impl<T> Trait for &T`.
+pub(crate) fn get_filtered_impls_for_reference<'a>(
+ shared: &'a Rc<SharedContext<'_>>,
+ it: &clean::Item,
+) -> (Vec<&'a Impl>, Vec<&'a Impl>, Vec<&'a Impl>) {
+ let def_id = it.item_id.expect_def_id();
+ // If the reference primitive is somehow not defined, exit early.
+ let Some(v) = shared.cache.impls.get(&def_id) else { return (Vec::new(), Vec::new(), Vec::new()) };
+ // Since there is no "direct implementation" on the reference primitive type, we filter out
+ // every implementation which isn't a trait implementation.
+ let traits = v.iter().filter(|i| i.inner_impl().trait_.is_some());
+ let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
+ traits.partition(|t| t.inner_impl().kind.is_auto());
+
+ let (blanket_impl, concrete): (Vec<&Impl>, _) =
+ concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
+ // Now we keep only references over full generic types.
+ let concrete: Vec<_> = concrete
+ .into_iter()
+ .filter(|t| match t.inner_impl().for_ {
+ clean::Type::BorrowedRef { ref type_, .. } => type_.is_full_generic(),
+ _ => false,
+ })
+ .collect();
+
+ (concrete, synthetic, blanket_impl)
+}
+
fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
let mut sidebar = Buffer::new();
- sidebar_assoc_items(cx, &mut sidebar, it);
+
+ if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
+ sidebar_assoc_items(cx, &mut sidebar, it);
+ } else {
+ let shared = Rc::clone(&cx.shared);
+ let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&shared, it);
+
+ sidebar_render_assoc_items(
+ cx,
+ &mut sidebar,
+ &mut IdMap::new(),
+ concrete,
+ synthetic,
+ blanket_impl,
+ );
+ }
if !sidebar.is_empty() {
write!(buf, "<section>{}</section>", sidebar.into_inner());
@@ -2614,8 +2712,8 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
clean::Type::BorrowedRef { type_, .. } => {
work.push_back(*type_);
}
- clean::Type::QPath { self_type, trait_, .. } => {
- work.push_back(*self_type);
+ clean::Type::QPath(box clean::QPathData { self_type, trait_, .. }) => {
+ work.push_back(self_type);
process_path(trait_.def_id());
}
_ => {}
@@ -2668,7 +2766,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
let contents = match fs::read_to_string(&path) {
Ok(contents) => contents,
Err(err) => {
- let span = item.span(tcx).inner();
+ let span = item.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner());
tcx.sess
.span_err(span, &format!("failed to read file {}: {}", path.display(), err));
return false;
@@ -2764,11 +2862,10 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
sources::print_src(
w,
contents_subset,
- call_data.edition,
file_span,
cx,
&root_path,
- Some(highlight::DecorationInfo(decoration_info)),
+ highlight::DecorationInfo(decoration_info),
sources::SourceContext::Embedded { offset: line_min },
);
write!(w, "</div></div>");
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 99cf42919..cfa450942 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -16,10 +16,10 @@ use std::fmt;
use std::rc::Rc;
use super::{
- collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_section,
- notable_traits_decl, render_assoc_item, render_assoc_items, render_attributes_in_code,
- render_attributes_in_pre, render_impl, render_stability_since_raw, write_srclink,
- AssocItemLink, Context, ImplRenderingParameters,
+ collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
+ item_ty_to_section, notable_traits_decl, render_all_impls, render_assoc_item,
+ render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl,
+ render_rightside, render_stability_since_raw, AssocItemLink, Context, ImplRenderingParameters,
};
use crate::clean;
use crate::config::ModuleSorting;
@@ -371,16 +371,21 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
}
clean::ImportKind::Glob => String::new(),
};
+ let stab_tags = stab_tags.unwrap_or_default();
+ let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() {
+ ("", "")
+ } else {
+ ("<div class=\"item-right docblock-short\">", "</div>")
+ };
write!(
w,
"<div class=\"item-left {stab}{add}import-item\"{id}>\
<code>{vis}{imp}</code>\
</div>\
- <div class=\"item-right docblock-short\">{stab_tags}</div>",
+ {stab_tags_before}{stab_tags}{stab_tags_after}",
stab = stab.unwrap_or_default(),
vis = myitem.visibility.print_with_space(myitem.item_id, cx),
imp = import.print(cx),
- stab_tags = stab_tags.unwrap_or_default(),
);
w.write_str(ITEM_TABLE_ROW_CLOSE);
}
@@ -412,6 +417,12 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
let doc_value = myitem.doc_value().unwrap_or_default();
w.write_str(ITEM_TABLE_ROW_OPEN);
+ let docs = MarkdownSummaryLine(&doc_value, &myitem.links(cx)).into_string();
+ let (docs_before, docs_after) = if docs.is_empty() {
+ ("", "")
+ } else {
+ ("<div class=\"item-right docblock-short\">", "</div>")
+ };
write!(
w,
"<div class=\"item-left {stab}{add}module-item\">\
@@ -420,11 +431,10 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
{unsafety_flag}\
{stab_tags}\
</div>\
- <div class=\"item-right docblock-short\">{docs}</div>",
+ {docs_before}{docs}{docs_after}",
name = myitem.name.unwrap(),
visibility_emoji = visibility_emoji,
stab_tags = extra_info_tags(myitem, item, cx.tcx()),
- docs = MarkdownSummaryLine(&doc_value, &myitem.links(cx)).into_string(),
class = myitem.type_(),
add = add,
stab = stab.unwrap_or_default(),
@@ -477,7 +487,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) ->
(cfg, _) => cfg.as_deref().cloned(),
};
- debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.cfg, cfg);
+ debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg);
if let Some(ref cfg) = cfg {
tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
}
@@ -520,7 +530,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
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, header.asyncness, cx),
+ decl = f.decl.full_print(header_len, 0, cx),
notable_traits = notable_traits_decl(&f.decl, cx),
);
});
@@ -709,14 +719,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
}
write!(w, "<div id=\"{}\" class=\"method has-srclink\">", id);
- write!(w, "<div class=\"rightside\">");
-
- let has_stability = render_stability_since(w, m, t, cx.tcx());
- if has_stability {
- w.write_str(" · ");
- }
- write_srclink(cx, m, w);
- write!(w, "</div>");
+ render_rightside(w, cx, m, t, RenderMode::Normal);
write!(w, "<h4 class=\"code-header\">");
render_assoc_item(
w,
@@ -994,7 +997,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
// So C's HTML will have something like this:
//
// ```html
- // <script type="text/javascript" src="/implementors/A/trait.Foo.js"
+ // <script src="/implementors/A/trait.Foo.js"
// data-ignore-extern-crates="A,B" async></script>
// ```
//
@@ -1020,9 +1023,11 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
.map(|cnum| cx.shared.tcx.crate_name(cnum).to_string())
.collect::<Vec<_>>()
.join(",");
+ let (extern_before, extern_after) =
+ if extern_crates.is_empty() { ("", "") } else { (" data-ignore-extern-crates=\"", "\"") };
write!(
w,
- "<script type=\"text/javascript\" src=\"{src}\" data-ignore-extern-crates=\"{extern_crates}\" async></script>",
+ "<script src=\"{src}\"{extern_before}{extern_crates}{extern_after} async></script>",
src = js_src_path.finish(),
);
}
@@ -1198,7 +1203,8 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
let name = v.name.unwrap();
match *v.kind {
clean::VariantItem(ref var) => match var {
- clean::Variant::CLike => write!(w, "{}", name),
+ // FIXME(#101337): Show discriminant
+ clean::Variant::CLike(..) => write!(w, "{}", name),
clean::Variant::Tuple(ref s) => {
write!(w, "{}(", name);
print_tuple_struct_fields(w, cx, s);
@@ -1260,7 +1266,13 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
w.write_str(")");
}
w.write_str("</code>");
- render_stability_since(w, variant, it, cx.tcx());
+ render_stability_since_raw(
+ w,
+ variant.stable_since(cx.tcx()),
+ variant.const_stability(cx.tcx()),
+ it.stable_since(cx.tcx()),
+ it.const_stable_since(cx.tcx()),
+ );
w.write_str("</h3>");
use crate::clean::Variant;
@@ -1322,17 +1334,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
wrap_into_docblock(w, |w| {
- highlight::render_with_highlighting(
- &t.source,
- w,
- Some("macro"),
- None,
- None,
- it.span(cx.tcx()).inner().edition(),
- None,
- None,
- None,
- );
+ highlight::render_macro_with_highlighting(&t.source, w);
});
document(w, cx, it, None, HeadingOffset::H2)
}
@@ -1370,8 +1372,18 @@ fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &c
}
fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
+ let def_id = it.item_id.expect_def_id();
document(w, cx, it, None, HeadingOffset::H2);
- render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
+ if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
+ render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
+ } else {
+ // We handle the "reference" primitive type on its own because we only want to list
+ // implementations on generic types.
+ let shared = Rc::clone(&cx.shared);
+ let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&shared, it);
+
+ render_all_impls(w, cx, it, &concrete, &synthetic, &blanket_impl);
+ }
}
fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
@@ -1601,21 +1613,6 @@ where
w.write_str("</code></pre>");
}
-fn render_stability_since(
- w: &mut Buffer,
- item: &clean::Item,
- containing_item: &clean::Item,
- tcx: TyCtxt<'_>,
-) -> bool {
- render_stability_since_raw(
- w,
- item.stable_since(tcx),
- item.const_stability(tcx),
- containing_item.stable_since(tcx),
- containing_item.const_stable_since(tcx),
- )
-}
-
fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cx: &Context<'_>) -> Ordering {
let lhss = format!("{}", lhs.inner_impl().print(false, cx));
let rhss = format!("{}", rhs.inner_impl().print(false, cx));
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index d672f0bb5..8eb9c07f8 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -544,10 +544,15 @@ fn get_fn_inputs_and_outputs<'tcx>(
(true, _) => (Some(impl_self), &func.generics),
(_, true) => (Some(impl_self), impl_generics),
(false, false) => {
- let mut params = func.generics.params.clone();
- params.extend(impl_generics.params.clone());
- let mut where_predicates = func.generics.where_predicates.clone();
- where_predicates.extend(impl_generics.where_predicates.clone());
+ let params =
+ func.generics.params.iter().chain(&impl_generics.params).cloned().collect();
+ let where_predicates = func
+ .generics
+ .where_predicates
+ .iter()
+ .chain(&impl_generics.where_predicates)
+ .cloned()
+ .collect();
combined_generics = clean::Generics { params, where_predicates };
(Some(impl_self), &combined_generics)
}
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 34d590fb2..151ec2b28 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -166,25 +166,23 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
if let ExprKind::MethodCall(segment, ..) = expr.kind {
- if let Some(hir_id) = segment.hir_id {
- let hir = self.tcx.hir();
- let body_id = hir.enclosing_body_owner(hir_id);
- // FIXME: this is showing error messages for parts of the code that are not
- // compiled (because of cfg)!
- //
- // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
- let typeck_results = self.tcx.typeck_body(
- hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
+ let hir = self.tcx.hir();
+ let body_id = hir.enclosing_body_owner(segment.hir_id);
+ // FIXME: this is showing error messages for parts of the code that are not
+ // compiled (because of cfg)!
+ //
+ // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
+ let typeck_results = self
+ .tcx
+ .typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"));
+ if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
+ self.matches.insert(
+ segment.ident.span,
+ match hir.span_if_local(def_id) {
+ Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
+ None => LinkFromSrc::External(def_id),
+ },
);
- if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
- self.matches.insert(
- segment.ident.span,
- match hir.span_if_local(def_id) {
- Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
- None => LinkFromSrc::External(def_id),
- },
- );
- }
}
} else if self.handle_macro(expr.span) {
// We don't want to go deeper into the macro.
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 6fb41ff32..fc4d46fe6 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -1,5 +1,4 @@
use std::ffi::OsStr;
-use std::fmt::Write;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, BufReader};
@@ -10,7 +9,8 @@ use std::sync::LazyLock as Lazy;
use itertools::Itertools;
use rustc_data_structures::flock;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use serde::Serialize;
+use serde::ser::SerializeSeq;
+use serde::{Serialize, Serializer};
use super::{collect_paths_for_type, ensure_trailing_slash, Context, BASIC_KEYWORDS};
use crate::clean::Crate;
@@ -284,25 +284,43 @@ pub(super) fn write_shared(
cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?;
}
- fn collect(path: &Path, krate: &str, key: &str) -> io::Result<(Vec<String>, Vec<String>)> {
+ /// Read a file and return all lines that match the `"{crate}":{data},` format,
+ /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
+ ///
+ /// This forms the payload of files that look like this:
+ ///
+ /// ```javascript
+ /// var data = {
+ /// "{crate1}":{data},
+ /// "{crate2}":{data}
+ /// };
+ /// use_data(data);
+ /// ```
+ ///
+ /// The file needs to be formatted so that *only crate data lines start with `"`*.
+ fn collect(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> {
let mut ret = Vec::new();
let mut krates = Vec::new();
if path.exists() {
- let prefix = format!(r#"{}["{}"]"#, key, krate);
+ let prefix = format!("\"{}\"", krate);
for line in BufReader::new(File::open(path)?).lines() {
let line = line?;
- if !line.starts_with(key) {
+ if !line.starts_with('"') {
continue;
}
if line.starts_with(&prefix) {
continue;
}
- ret.push(line.to_string());
+ if line.ends_with(',') {
+ ret.push(line[..line.len() - 1].to_string());
+ } else {
+ // No comma (it's the case for the last added crate line)
+ ret.push(line.to_string());
+ }
krates.push(
- line[key.len() + 2..]
- .split('"')
- .next()
+ line.split('"')
+ .find(|s| !s.is_empty())
.map(|s| s.to_owned())
.unwrap_or_else(String::new),
);
@@ -311,6 +329,20 @@ pub(super) fn write_shared(
Ok((ret, krates))
}
+ /// 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:
+ ///
+ /// ```javascript
+ /// var data = JSON.parse('{\
+ /// "{crate1}":{data},\
+ /// "{crate2}":{data}\
+ /// }');
+ /// use_data(data);
+ /// ```
+ ///
+ /// The file needs to be formatted so that *only crate data lines start with `"`*.
fn collect_json(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> {
let mut ret = Vec::new();
let mut krates = Vec::new();
@@ -526,13 +558,27 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
},
};
- #[derive(Serialize)]
struct Implementor {
text: String,
synthetic: bool,
types: Vec<String>,
}
+ impl Serialize for Implementor {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let mut seq = serializer.serialize_seq(None)?;
+ seq.serialize_element(&self.text)?;
+ if self.synthetic {
+ seq.serialize_element(&1)?;
+ seq.serialize_element(&self.types)?;
+ }
+ seq.end()
+ }
+ }
+
let implementors = imps
.iter()
.filter_map(|imp| {
@@ -563,9 +609,9 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
}
let implementors = format!(
- r#"implementors["{}"] = {};"#,
+ r#""{}":{}"#,
krate.name(cx.tcx()),
- serde_json::to_string(&implementors).unwrap()
+ serde_json::to_string(&implementors).expect("failed serde conversion"),
);
let mut mydst = dst.clone();
@@ -576,16 +622,15 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1]));
let (mut all_implementors, _) =
- try_err!(collect(&mydst, krate.name(cx.tcx()).as_str(), "implementors"), &mydst);
+ try_err!(collect(&mydst, krate.name(cx.tcx()).as_str()), &mydst);
all_implementors.push(implementors);
// Sort the implementors by crate so the file will be generated
// identically even with rustdoc running in parallel.
all_implementors.sort();
- let mut v = String::from("(function() {var implementors = {};\n");
- for implementor in &all_implementors {
- writeln!(v, "{}", *implementor).unwrap();
- }
+ let mut v = String::from("(function() {var implementors = {\n");
+ v.push_str(&all_implementors.join(",\n"));
+ v.push_str("\n};");
v.push_str(
"if (window.register_implementors) {\
window.register_implementors(implementors);\
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index d0fd637ba..2e2bee78b 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -11,7 +11,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
-use rustc_span::edition::Edition;
use rustc_span::source_map::FileName;
use std::ffi::OsStr;
@@ -54,6 +53,7 @@ impl LocalSourcesCollector<'_, '_> {
fn add_local_source(&mut self, item: &clean::Item) {
let sess = self.tcx.sess;
let span = item.span(self.tcx);
+ let Some(span) = span else { return };
// skip all synthetic "files"
if !is_real_and_local(span, sess) {
return;
@@ -110,6 +110,7 @@ impl DocVisitor for SourceCollector<'_, '_> {
let tcx = self.cx.tcx();
let span = item.span(tcx);
+ let Some(span) = span else { return };
let sess = tcx.sess;
// If we're not rendering sources, there's nothing to do.
@@ -213,11 +214,10 @@ impl SourceCollector<'_, '_> {
print_src(
buf,
contents,
- cx.shared.edition(),
file_span,
cx,
&root_path,
- None,
+ highlight::DecorationInfo::default(),
SourceContext::Standalone,
)
},
@@ -266,11 +266,10 @@ pub(crate) enum SourceContext {
pub(crate) fn print_src(
buf: &mut Buffer,
s: &str,
- edition: Edition,
file_span: rustc_span::Span,
context: &Context<'_>,
root_path: &str,
- decoration_info: Option<highlight::DecorationInfo>,
+ decoration_info: highlight::DecorationInfo,
source_context: SourceContext,
) {
let lines = s.lines().count();
@@ -289,15 +288,14 @@ pub(crate) fn print_src(
}
}
line_numbers.write_str("</pre>");
- highlight::render_with_highlighting(
+ let current_href = &context
+ .href_from_span(clean::Span::new(file_span), false)
+ .expect("only local crates should have sources emitted");
+ highlight::render_source_with_highlighting(
s,
buf,
- None,
- None,
- None,
- edition,
- Some(line_numbers),
- Some(highlight::HrefContext { context, file_span, root_path }),
+ line_numbers,
+ highlight::HrefContext { context, file_span, root_path, current_href },
decoration_info,
);
}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 83fe14550..bb35970eb 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -197,26 +197,18 @@ h4.code-header {
position: relative;
}
-div.impl-items > div {
- padding-left: 0;
-}
-
h1, h2, h3, h4, h5, h6,
.sidebar,
.mobile-topbar,
a.source,
.search-input,
.search-results .result-name,
-.content table td:first-child > a,
.item-left > a,
.out-of-band,
span.since,
-#source-sidebar, #sidebar-toggle,
details.rustdoc-toggle > summary::before,
-div.impl-items > div:not(.docblock):not(.item-info),
.content ul.crate a.crate,
a.srclink,
-#main-content > .since,
#help-button > button,
details.rustdoc-toggle.top-doc > summary,
details.rustdoc-toggle.top-doc > summary::before,
@@ -230,7 +222,6 @@ details.rustdoc-toggle.non-exhaustive > summary::before,
font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
}
-h1, h2, h3, h4,
a#toggle-all-docs,
a.anchor,
.small-section-header a,
@@ -250,6 +241,51 @@ pre.rust a,
color: var(--main-color);
}
+.content span.enum, .content a.enum,
+.content span.struct, .content a.struct,
+.content span.union, .content a.union,
+.content span.primitive, .content a.primitive,
+.content span.type, .content a.type,
+.content span.foreigntype, .content a.foreigntype {
+ color: var(--type-link-color);
+}
+
+.content span.trait, .content a.trait,
+.content span.traitalias, .content a.traitalias {
+ color: var(--trait-link-color);
+}
+
+.content span.associatedtype, .content a.associatedtype,
+.content span.constant, .content a.constant,
+.content span.static, .content a.static {
+ color: var(--assoc-item-link-color);
+}
+
+.content span.fn, .content a.fn,
+.content .fnname,
+.content span.method, .content a.method,
+.content span.tymethod, .content a.tymethod {
+ color: var(--function-link-color);
+}
+
+.content span.attr, .content a.attr,
+.content span.derive, .content a.derive,
+.content span.macro, .content a.macro {
+ color: var(--macro-link-color);
+}
+
+.content span.mod, .content a.mod, .block a.current.mod {
+ color: var(--mod-link-color);
+}
+
+.content span.keyword, .content a.keyword {
+ color: var(--keyword-link-color);
+}
+
+a {
+ color: var(--link-color);
+}
+
ol, ul {
padding-left: 24px;
}
@@ -354,19 +390,8 @@ img {
max-width: 100%;
}
-li {
- position: relative;
-}
-
.source .content {
- max-width: none;
overflow: visible;
- margin-left: 0px;
-}
-
-nav.sub {
- position: relative;
- font-size: 1rem;
}
.sub-container {
@@ -515,9 +540,6 @@ nav.sub {
font-weight: 500;
}
-.block {
- padding: 0;
-}
.block ul, .block li {
padding: 0;
margin: 0;
@@ -608,19 +630,10 @@ h2.location a {
margin: 0;
}
-#search {
- position: relative;
-}
-
.search-loading {
text-align: center;
}
-#results > table {
- width: 100%;
- table-layout: fixed;
-}
-
.content > .example-wrap pre.line-numbers {
position: relative;
-webkit-user-select: none;
@@ -635,19 +648,12 @@ h2.location a {
.docblock-short {
overflow-wrap: break-word;
overflow-wrap: anywhere;
-}
-.docblock-short p {
- display: inline;
-}
-
-.docblock-short p {
overflow: hidden;
text-overflow: ellipsis;
- margin: 0;
}
/* Wrap non-pre code blocks (`text`) but not (```text```). */
.docblock > :not(pre) > code,
-.docblock-short > :not(pre) > code {
+.docblock-short > code {
white-space: pre-wrap;
}
@@ -672,7 +678,7 @@ h2.location a {
position: relative;
}
-.docblock > :not(.information):not(.more-examples-toggle) {
+.docblock > :not(.more-examples-toggle):not(.example-wrap) {
max-width: 100%;
overflow-x: auto;
}
@@ -693,8 +699,13 @@ h2.location a {
flex-grow: 1;
margin: 0px;
padding: 0px;
+ /* We use overflow-wrap: break-word for Safari, which doesn't recognize
+ `anywhere`: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap */
overflow-wrap: break-word;
+ /* Then override it with `anywhere`, which is required to make non-Safari browsers break
+ more aggressively when we want them to. */
overflow-wrap: anywhere;
+ background-color: var(--main-background-color);
}
.in-band > code, .in-band > .code-header {
@@ -709,18 +720,6 @@ pre, .rustdoc.source .example-wrap {
#main-content {
position: relative;
}
-#main-content > .since {
- top: inherit;
-}
-
-.content table:not(.table-display) {
- border-spacing: 0 5px;
-}
-.content td { vertical-align: top; }
-.content td:first-child { padding-right: 20px; }
-.content td p:first-child { margin-top: 0; }
-.content td h1, .content td h2 { margin-left: 0; font-size: 1.125rem; }
-.content tr:first-child td { border-top: 0; }
.docblock table {
margin: .5em 0;
@@ -731,17 +730,14 @@ pre, .rustdoc.source .example-wrap {
.docblock table td {
padding: .5em;
- border: 1px dashed;
+ border: 1px dashed var(--border-color);
+ vertical-align: top;
}
.docblock table th {
padding: .5em;
text-align: left;
- border: 1px solid;
-}
-
-.fields + table {
- margin-bottom: 1em;
+ border: 1px solid var(--border-color);
}
.content .item-list {
@@ -749,16 +745,6 @@ pre, .rustdoc.source .example-wrap {
padding: 0;
}
-.content .multi-column {
- -moz-column-count: 5;
- -moz-column-gap: 2.5em;
- -webkit-column-count: 5;
- -webkit-column-gap: 2.5em;
- column-count: 5;
- column-gap: 2.5em;
-}
-.content .multi-column li { width: 100%; display: inline-block; }
-
.content > .methods > .method {
font-size: 1rem;
position: relative;
@@ -771,25 +757,6 @@ pre, .rustdoc.source .example-wrap {
font-size: 0.875rem;
}
-.content .methods > div:not(.notable-traits):not(.method) {
- margin-left: 40px;
- margin-bottom: 15px;
-}
-
-.content .docblock > .impl-items {
- margin-left: 20px;
- margin-top: -34px;
-}
-.content .docblock >.impl-items .table-display {
- margin: 0;
-}
-.content .docblock >.impl-items table td {
- padding: 0;
-}
-.content .docblock > .impl-items .table-display, .impl-items table td {
- border: none;
-}
-
.item-info {
display: block;
}
@@ -803,58 +770,29 @@ pre, .rustdoc.source .example-wrap {
margin-left: 24px;
}
-.sub-variant > div > .item-info {
- margin-top: initial;
-}
-
.content .impl-items .docblock, .content .impl-items .item-info {
margin-bottom: .6em;
}
-.content .impl-items > .item-info {
- margin-left: 40px;
-}
-
-.methods > .item-info, .content .impl-items > .item-info {
- margin-top: -8px;
-}
-
-.impl-items {
- flex-basis: 100%;
-}
-
#main-content > .item-info {
margin-top: 0;
margin-left: 0;
}
nav.sub {
+ position: relative;
+ font-size: 1rem;
flex-grow: 1;
margin-bottom: 25px;
}
.source nav.sub {
margin-left: 32px;
}
-nav.main {
- padding: 20px 0;
- text-align: center;
-}
-nav.main .current {
- border-top: 1px solid;
- border-bottom: 1px solid;
-}
-nav.main .separator {
- border: 1px solid;
- display: inline-block;
- height: 23px;
- margin: 0 20px;
-}
nav.sum { text-align: right; }
nav.sub form { display: inline; }
a {
text-decoration: none;
- background: transparent;
}
.small-section-header {
@@ -942,40 +880,77 @@ table,
position: relative;
display: flex;
height: 34px;
+ margin-top: 4px;
}
.search-container > * {
height: 100%;
}
.search-results-title {
- display: inline;
+ margin-top: 0;
+ white-space: nowrap;
+ /* flex layout allows shrinking the <select> appropriately if it becomes too large */
+ display: inline-flex;
+ max-width: 100%;
+ /* make things look like in a line, despite the fact that we're using a layout
+ with boxes (i.e. from the flex layout) */
+ align-items: baseline;
}
-#search-settings {
- font-size: 1.5rem;
- font-weight: 500;
- margin-bottom: 20px;
+#crate-search-div {
+ display: inline-block;
+ /* ensures that 100% in properties of #crate-search-div:after
+ are relative to the size of this div */
+ position: relative;
+ /* allows this div (and with it the <select>-element "#crate-search") to be shrunk */
+ min-width: 5em;
}
#crate-search {
min-width: 115px;
- margin-top: 5px;
- padding-left: 0.15em;
+ padding: 0;
+ /* keep these two in sync with "@-moz-document url-prefix()" below */
+ padding-left: 4px;
padding-right: 23px;
- border: 1px solid;
+ /* prevents the <select> from overflowing the containing div in case it's shrunk */
+ max-width: 100%;
+ /* contents can overflow because of max-width limit, then show ellipsis */
+ text-overflow: ellipsis;
+ border: 1px solid var(--border-color);
border-radius: 4px;
outline: none;
cursor: pointer;
-moz-appearance: none;
-webkit-appearance: none;
/* Removes default arrow from firefox */
+ text-indent: 0.01px;
+ background-color: var(--main-background-color);
+}
+/* cancel stylistic differences in padding in firefox
+for "appearance: none"-style (or equivalent) <select>s */
+@-moz-document url-prefix() {
+ #crate-search {
+ padding-left: 0px; /* == 4px - 4px */
+ padding-right: 19px; /* == 23px - 4px */
+ }
+}
+/* pseudo-element for holding the dropdown-arrow image; needs to be a separate thing
+so that we can apply CSS-filters to change the arrow color in themes */
+#crate-search-div::after {
+ /* lets clicks through! */
+ pointer-events: none;
+ /* completely covers the underlying div */
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ content: "";
background-repeat: no-repeat;
- background-color: transparent;
background-size: 20px;
- background-position: calc(100% - 1px) 56%;
+ background-position: calc(100% - 2px) 56%;
+ /* image is black color, themes should apply a "filter" property to change the color */
background-image: /* AUTOREPLACE: */url("down-arrow.svg");
- max-width: 100%;
- text-overflow: ellipsis;
}
-.search-container {
- margin-top: 4px;
+#crate-search > option {
+ font-size: 1rem;
}
.search-input {
/* Override Normalize.css: it has a rule that sets
@@ -988,11 +963,15 @@ table,
-moz-box-sizing: border-box !important;
box-sizing: border-box !important;
outline: none;
- border: 1px solid;
+ border: 1px solid var(--border-color);
border-radius: 2px;
padding: 8px;
font-size: 1rem;
width: 100%;
+ background-color: var(--button-background-color);
+}
+.search-input:focus {
+ border-color: var(--search-input-focused-border-color);
}
.search-results {
@@ -1015,7 +994,6 @@ table,
.search-results > a {
display: block;
- width: 100%;
/* A little margin ensures the browser's outlining of focused links has room to display. */
margin-left: 2px;
margin-right: 2px;
@@ -1034,12 +1012,6 @@ table,
padding-right: 1em;
}
-.search-results .result-name > span {
- display: inline-block;
- margin: 0;
- font-weight: normal;
-}
-
.popover {
font-size: 1rem;
position: absolute;
@@ -1048,7 +1020,7 @@ table,
display: block;
margin-top: 7px;
border-radius: 3px;
- border: 1px solid;
+ border: 1px solid var(--border-color);
font-size: 1rem;
}
@@ -1057,7 +1029,7 @@ table,
content: '';
position: absolute;
right: 11px;
- border: solid;
+ border: solid var(--border-color);
border-width: 1px 1px 0 0;
display: inline-block;
padding: 4px;
@@ -1093,13 +1065,13 @@ table,
text-align: center;
display: block;
margin: 10px 0;
- border-bottom: 1px solid;
+ border-bottom: 1px solid var(--border-color);
padding-bottom: 4px;
margin-bottom: 6px;
}
#help-button span.bottom {
clear: both;
- border-top: 1px solid;
+ border-top: 1px solid var(--border-color);
}
.side-by-side {
text-align: initial;
@@ -1133,6 +1105,7 @@ table,
.stab .emoji {
font-size: 1.25rem;
+ margin-right: 0.3rem;
}
/* Black one-pixel outline around emoji shapes */
@@ -1170,36 +1143,125 @@ table,
padding-left: 12px;
padding-right: 2px;
position: initial;
+ float: right;
+}
+
+.rightside:not(a),
+.out-of-band {
+ color: var(--right-side-color);
}
+
.impl-items .srclink, .impl .srclink, .methods .srclink {
/* Override header settings otherwise it's too bold */
font-weight: normal;
font-size: 1rem;
}
-.rightside {
- float: right;
+td.summary-column {
+ width: 100%;
}
-.variants_table {
- width: 100%;
+.summary {
+ padding-right: 0px;
}
-.variants_table tbody tr td:first-child {
- width: 1%; /* make the variant name as small as possible */
+pre.rust .question-mark {
+ font-weight: bold;
}
-td.summary-column {
- width: 100%;
+.example-wrap.compile_fail,
+.example-wrap.should_panic {
+ border-left: 2px solid var(--codeblock-error-color);
}
-.summary {
- padding-right: 0px;
+.ignore.example-wrap {
+ border-left: 2px solid var(--codeblock-ignore-color);
}
-pre.rust .question-mark {
+.example-wrap.compile_fail:hover,
+.example-wrap.should_panic:hover {
+ border-left: 2px solid var(--codeblock-error-hover-color);
+}
+
+.example-wrap.ignore:hover {
+ border-left: 2px solid var(--codeblock-ignore-hover-color);
+}
+
+.example-wrap.compile_fail .tooltip,
+.example-wrap.should_panic .tooltip {
+ color: var(--codeblock-error-color);
+}
+
+.example-wrap.ignore .tooltip {
+ color: var(--codeblock-ignore-color);
+}
+
+.example-wrap.compile_fail:hover .tooltip,
+.example-wrap.should_panic:hover .tooltip {
+ color: var(--codeblock-error-hover-color);
+}
+
+.example-wrap.ignore:hover .tooltip {
+ color: var(--codeblock-ignore-hover-color);
+}
+
+.example-wrap .tooltip {
+ position: absolute;
+ display: block;
+ cursor: pointer;
+ left: -25px;
+ top: 5px;
+}
+
+.example-wrap .tooltip::after {
+ display: none;
+ text-align: center;
+ 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;
+}
+
+.example-wrap .tooltip::before {
+ content: " ";
+ position: absolute;
+ top: 50%;
+ left: 16px;
+ margin-top: -5px;
+ border-width: 5px;
+ border-style: solid;
+ display: none;
+ z-index: 1;
+}
+
+.example-wrap.ignore .tooltip::after {
+ content: "This example is not tested";
+}
+.example-wrap.compile_fail .tooltip::after {
+ content: "This example deliberately fails to compile";
+}
+.example-wrap.should_panic .tooltip::after {
+ content: "This example panics";
+}
+.example-wrap.edition .tooltip::after {
+ content: "This code runs with edition " attr(data-edition);
+}
+
+.example-wrap .tooltip:hover::before, .example-wrap .tooltip:hover::after {
+ display: inline;
+}
+
+.example-wrap.compile_fail .tooltip,
+.example-wrap.should_panic .tooltip,
+.example-wrap.ignore .tooltip {
font-weight: bold;
+ font-size: 1.25rem;
}
a.test-arrow {
@@ -1216,12 +1278,13 @@ a.test-arrow {
.example-wrap:hover .test-arrow {
visibility: visible;
}
-a.test-arrow:hover{
+a.test-arrow:hover {
text-decoration: none;
}
.code-attribute {
font-weight: 300;
+ color: var(--code-attribute-color);
}
.item-spacer {
@@ -1230,7 +1293,6 @@ a.test-arrow:hover{
}
.out-of-band > span.since {
- position: initial;
font-size: 1.25rem;
}
@@ -1258,12 +1320,6 @@ h3.variant {
margin-left: 24px;
}
-.toggle-label {
- display: inline-block;
- margin-left: 4px;
- margin-top: 3px;
-}
-
:target > code, :target > .code-header {
opacity: 1;
}
@@ -1272,61 +1328,6 @@ h3.variant {
padding-right: 3px;
}
-.information {
- position: absolute;
- left: -25px;
- margin-top: 7px;
- z-index: 1;
-}
-
-.tooltip {
- position: relative;
- display: inline-block;
- cursor: pointer;
-}
-
-.tooltip::after {
- display: none;
- text-align: center;
- padding: 5px 3px 3px 3px;
- border-radius: 6px;
- margin-left: 5px;
- font-size: 1rem;
-}
-
-.tooltip.ignore::after {
- content: "This example is not tested";
-}
-.tooltip.compile_fail::after {
- content: "This example deliberately fails to compile";
-}
-.tooltip.should_panic::after {
- content: "This example panics";
-}
-.tooltip.edition::after {
- content: "This code runs with edition " attr(data-edition);
-}
-
-.tooltip::before {
- content: " ";
- position: absolute;
- top: 50%;
- left: 16px;
- margin-top: -5px;
- border-width: 5px;
- border-style: solid;
- display: none;
-}
-
-.tooltip:hover::before, .tooltip:hover::after {
- display: inline;
-}
-
-.tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore {
- font-weight: bold;
- font-size: 1.25rem;
-}
-
.notable-traits-tooltip {
display: inline-block;
cursor: pointer;
@@ -1368,7 +1369,7 @@ h3.variant {
display: block;
}
-.notable-traits .docblock code.content{
+.notable-traits .docblock code.content {
margin: 0;
padding: 0;
font-size: 1.25rem;
@@ -1402,27 +1403,19 @@ pre.rust {
}
#titles {
- height: 35px;
+ display: flex;
+ flex-direction: row;
+ gap: 1px;
+ margin-bottom: 4px;
}
#titles > button {
- float: left;
- width: 33.3%;
text-align: center;
font-size: 1.125rem;
cursor: pointer;
border: 0;
border-top: 2px solid;
-}
-
-#titles > button:first-child:last-child {
- margin-right: 1px;
- width: calc(100% - 1px);
-}
-
-#titles > button:not(:last-child) {
- margin-right: 1px;
- width: calc(33.3% - 1px);
+ flex: 1;
}
#titles > button > div.count {
@@ -1457,7 +1450,7 @@ pre.rust {
#source-sidebar > .title {
font-size: 1.5rem;
text-align: center;
- border-bottom: 1px solid;
+ border-bottom: 1px solid var(--border-color);
margin-bottom: 6px;
}
#sidebar-toggle > button {
@@ -1483,23 +1476,29 @@ pre.rust {
outline: none;
}
-#copy-path {
- height: 34px;
-}
#settings-menu > a, #help-button > button, #copy-path {
padding: 5px;
width: 33px;
- border: 1px solid;
+ border: 1px solid var(--border-color);
border-radius: 2px;
cursor: pointer;
}
-#settings-menu {
- padding: 0;
-}
+
#settings-menu > a, #help-button > button {
padding: 5px;
height: 100%;
display: block;
+ background-color: var(--button-background-color);
+}
+
+#copy-path {
+ color: var(--copy-path-button-color);
+}
+#copy-path > img {
+ filter: var(--copy-path-img-filter);
+}
+#copy-path:hover > img {
+ filter: var(--copy-path-img-hover-filter);
}
@keyframes rotating {
@@ -1542,85 +1541,25 @@ input:checked + .slider {
}
#copy-path {
- background: initial;
+ height: 34px;
+ background-color: var(--main-background-color);
margin-left: 10px;
padding: 0;
padding-left: 2px;
border: 0;
}
-#theme-choices {
- display: none;
- position: absolute;
- left: 0;
- top: 28px;
- border: 1px solid;
- border-radius: 3px;
- z-index: 1;
- cursor: pointer;
-}
-
-#theme-choices > button {
- border: none;
- width: 100%;
- padding: 4px 8px;
- text-align: center;
- background: rgba(0,0,0,0);
- overflow-wrap: normal;
-}
-
-#theme-choices > button:not(:first-child) {
- border-top: 1px solid;
-}
-
kbd {
display: inline-block;
padding: 3px 5px;
font: 15px monospace;
line-height: 10px;
vertical-align: middle;
- border: solid 1px;
+ border: solid 1px var(--border-color);
border-radius: 3px;
cursor: default;
}
-.hidden-by-impl-hider,
-.hidden-by-usual-hider {
- /* important because of conflicting rule for small screens */
- display: none !important;
-}
-
-#implementations-list > h3 > span.in-band {
- width: 100%;
-}
-
-.table-display {
- width: 100%;
- border: 0;
- border-collapse: collapse;
- border-spacing: 0;
- font-size: 1rem;
-}
-
-.table-display tr td:first-child {
- padding-right: 0;
-}
-
-.table-display tr td:last-child {
- float: right;
-}
-.table-display .out-of-band {
- position: relative;
- font-size: 1.125rem;
- display: block;
-}
-
-.table-display td:hover .anchor {
- display: block;
- top: 2px;
- left: -5px;
-}
-
#main-content > ul {
padding-left: 10px;
}
@@ -1681,6 +1620,12 @@ details.rustdoc-toggle > summary::before {
opacity: .5;
}
+details.rustdoc-toggle > summary.hideme > span,
+details.rustdoc-toggle > summary::before,
+.more-examples-toggle summary, .more-examples-toggle .hide-more {
+ color: var(--toggles-color);
+}
+
/* Screen readers see the text version at the end the line.
Visual readers see the icon at the start of the line, but small and transparent. */
details.rustdoc-toggle > summary::after {
@@ -1785,7 +1730,7 @@ in storage.js plus the media query with (max-width: 700px)
to prevent an overlay between the "collapse toggle" and the information tooltip.
However, it's not needed with smaller screen width because the doc/code block is always put
"one line" below. */
- .docblock > .information:first-child > .tooltip {
+ .docblock > .example-wrap:first-child .tooltip {
margin-top: 16px;
}
@@ -1826,7 +1771,6 @@ in storage.js plus the media query with (min-width: 701px)
padding-top: 0px;
}
- .rustdoc,
.main-heading {
flex-direction: column;
}
@@ -1852,10 +1796,6 @@ in storage.js plus the media query with (min-width: 701px)
display: none;
}
- .sidebar-elems {
- margin-top: 1em;
- }
-
.sidebar {
position: fixed;
top: 45px;
@@ -1949,13 +1889,10 @@ in storage.js plus the media query with (min-width: 701px)
}
.sidebar-elems {
+ margin-top: 1em;
background-color: var(--sidebar-background-color);
}
- .source nav:not(.sidebar).sub {
- margin-left: 32px;
- }
-
.content {
margin-left: 0px;
}
@@ -1964,28 +1901,12 @@ in storage.js plus the media query with (min-width: 701px)
margin-top: 10px;
}
- #search {
- margin-left: 0;
- padding: 0;
- }
-
.anchor {
display: none !important;
}
- .notable-traits {
- position: absolute;
- left: -22px;
- top: 24px;
- }
-
#titles > button > div.count {
- float: left;
- width: 100%;
- }
-
- #titles {
- height: 50px;
+ display: block;
}
/* Because of ios, we need to actually have a full height sidebar title so the
@@ -2092,6 +2013,11 @@ in storage.js plus the media query with (min-width: 701px)
#main-content > div > details.rustdoc-toggle > summary::before {
left: -11px;
}
+
+ /* Align summary-nested and unnested item-info gizmos. */
+ .content .impl-items > .item-info {
+ margin-left: 34px;
+ }
}
@media print {
@@ -2111,15 +2037,6 @@ in storage.js plus the media query with (min-width: 701px)
}
@media (max-width: 464px) {
- #titles, #titles > button {
- height: 73px;
- }
-
- #main-content > table:not(.table-display) td {
- word-break: break-word;
- width: 50%;
- }
-
#crate-search {
border-radius: 4px;
}
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index c42cac59b..e7a898e9f 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -14,6 +14,27 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--scrollbar-thumb-background-color: #5c6773;
--scrollbar-color: #5c6773 #24292f;
--headings-border-bottom-color: #5c6773;
+ --border-color: #5c6773;
+ --button-background-color: #141920;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */
+ --copy-path-button-color: #fff;
+ --copy-path-img-filter: invert(70%);
+ --copy-path-img-hover-filter: invert(100%);
+ --codeblock-error-hover-color: rgb(255, 0, 0);
+ --codeblock-error-color: rgba(255, 0, 0, .5);
+ --codeblock-ignore-hover-color: rgb(255, 142, 0);
+ --codeblock-ignore-color: rgba(255, 142, 0, .6);
+ --type-link-color: #ffa0a5;
+ --trait-link-color: #39afd7;
+ --assoc-item-link-color: #39afd7;
+ --function-link-color: #fdd687;
+ --macro-link-color: #a37acc;
+ --keyword-link-color: #39afd7;
+ --mod-link-color: #39afd7;
+ --link-color: #39afd7;
}
.slider {
@@ -36,10 +57,6 @@ h4 {
border: none;
}
-.in-band {
- background-color: #0f1419;
-}
-
.docblock code {
color: #ffb454;
}
@@ -49,7 +66,7 @@ h4 {
.docblock pre > code, pre > code {
color: #e6e1cf;
}
-span code {
+.item-info code {
color: #e6e1cf;
}
.docblock a > code {
@@ -84,17 +101,14 @@ pre, .rustdoc.source .example-wrap {
border-right: 1px solid #ffb44c;
}
-.docblock table td, .docblock table th {
- border-color: #5c6773;
-}
-
.search-results a:hover {
- background-color: #777;
+ color: #fff !important;
+ background-color: #3c3c3c;
}
.search-results a:focus {
- color: #000 !important;
- background-color: #c6afb3;
+ color: #fff !important;
+ background-color: #3c3c3c;
}
.search-results a {
color: #0096cf;
@@ -105,97 +119,37 @@ pre, .rustdoc.source .example-wrap {
.content .item-info::before { color: #ccc; }
-.content span.foreigntype, .content a.foreigntype { color: #ffa0a5; }
-.content span.union, .content a.union { color: #ffa0a5; }
-.content span.constant, .content a.constant,
-.content span.static, .content a.static { color: #39AFD7; }
-.content span.primitive, .content a.primitive { color: #ffa0a5; }
-.content span.traitalias, .content a.traitalias { color: #39AFD7; }
-.content span.keyword, .content a.keyword { color: #39AFD7; }
-
-.content span.externcrate, .content span.mod, .content a.mod {
- color: #39AFD7;
-}
-.content span.struct, .content a.struct {
- color: #ffa0a5;
-}
-.content span.enum, .content a.enum {
- color: #ffa0a5;
-}
-.content span.trait, .content a.trait {
- color: #39AFD7;
-}
-.content span.type, .content a.type {
- color: #39AFD7;
-}
-.content span.type,
-.content a.type,
-.block a.current.type { color: #39AFD7; }
-.content span.associatedtype,
-.content a.associatedtype,
-.block a.current.associatedtype { color: #39AFD7; }
-.content span.fn, .content a.fn, .content span.method,
-.content a.method, .content span.tymethod,
-.content a.tymethod, .content .fnname {
- color: #fdd687;
-}
-.content span.attr, .content a.attr, .content span.derive,
-.content a.derive, .content span.macro, .content a.macro {
- color: #a37acc;
-}
-
.sidebar a { color: #53b1db; }
.sidebar a.current.type { color: #53b1db; }
-.sidebar a.current.associatedtype { color: #53b1db; }
pre.rust .comment { color: #788797; }
pre.rust .doccomment { color: #a1ac88; }
-nav.main .current {
- border-top-color: #5c6773;
- border-bottom-color: #5c6773;
-}
-nav.main .separator {
- border: 1px solid #5c6773;
-}
-a {
- color: #39AFD7;
-}
-
.sidebar h2 a,
.sidebar h3 a {
color: white;
}
-.search-results a {
- color: #0096cf;
-}
body.source .example-wrap pre.rust a {
background: #333;
}
-details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
- color: #999;
-}
-
details.rustdoc-toggle > summary::before {
filter: invert(100%);
}
-#crate-search, .search-input {
- background-color: #141920;
- border-color: #424c57;
+#crate-search-div::after {
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);
}
-
-#crate-search {
- /* Without the `!important`, the border-color is ignored for `<select>`...
- It cannot be in the group above because `.search-input` has a different border color on
- hover. */
- border-color: #424c57 !important;
+#crate-search:hover, #crate-search:focus {
+ border-color: #e0e0e0 !important;
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+ filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);
}
.search-input {
- color: #ffffff;
+ color: #fff;
}
.module-item .stab,
@@ -203,20 +157,9 @@ details.rustdoc-toggle > summary::before {
color: #000;
}
-/* Created this empty rule to satisfy the theme checks. */
-.stab.empty-impl {}
-.stab.must_implement {}
-
-.stab.unstable,
-.stab.deprecated,
-.stab.portability,
-.stab.empty-impl,
-.stab.must_implement {
+.stab {
color: #c5c5c5;
background: #314559 !important;
- border-style: none !important;
- border-radius: 4px;
- padding: 3px 6px 3px 6px;
}
.stab.portability > code {
@@ -224,11 +167,6 @@ details.rustdoc-toggle > summary::before {
background: none;
}
-.rightside,
-.out-of-band {
- color: grey;
-}
-
.result-name .primitive > i, .result-name .keyword > i {
color: #788797;
}
@@ -239,7 +177,7 @@ details.rustdoc-toggle > summary::before {
pre.rust .number, pre.rust .string { color: #b8cc52; }
pre.rust .kw, pre.rust .kw-2, pre.rust .prelude-ty,
pre.rust .bool-val, pre.rust .prelude-val,
-pre.rust .op, pre.rust .lifetime { color: #ff7733; }
+pre.rust .lifetime { color: #ff7733; }
pre.rust .macro, pre.rust .macro-nonterminal { color: #a37acc; }
pre.rust .question-mark {
color: #ff9011;
@@ -251,9 +189,6 @@ pre.rust .self {
pre.rust .attribute {
color: #e6e1cf;
}
-pre.rust .attribute .ident, pre.rust .attribute .op {
- color: #e6e1cf;
-}
.example-wrap > pre.line-number {
color: #5c67736e;
@@ -272,64 +207,11 @@ a.test-arrow:hover {
color: #c5c5c5;
}
-.toggle-label,
-.code-attribute {
- color: #999;
-}
-
:target {
background: rgba(255, 236, 164, 0.06);
border-right: 3px solid rgba(255, 180, 76, 0.85);
}
-pre.compile_fail {
- border-left: 2px solid rgba(255,0,0,.4);
-}
-
-pre.compile_fail:hover, .information:hover + pre.compile_fail {
- border-left: 2px solid #f00;
-}
-
-pre.should_panic {
- border-left: 2px solid rgba(255,0,0,.4);
-}
-
-pre.should_panic:hover, .information:hover + pre.should_panic {
- border-left: 2px solid #f00;
-}
-
-pre.ignore {
- border-left: 2px solid rgba(255,142,0,.6);
-}
-
-pre.ignore:hover, .information:hover + pre.ignore {
- border-left: 2px solid #ff9200;
-}
-
-.tooltip.compile_fail {
- color: rgba(255,0,0,.5);
-}
-
-.information > .compile_fail:hover {
- color: #f00;
-}
-
-.tooltip.should_panic {
- color: rgba(255,0,0,.5);
-}
-
-.information > .should_panic:hover {
- color: #f00;
-}
-
-.tooltip.ignore {
- color: rgba(255,142,0,.6);
-}
-
-.information > .ignore:hover {
- color: #ff9200;
-}
-
.search-failed a {
color: #39AFD7;
}
@@ -337,7 +219,6 @@ pre.ignore:hover, .information:hover + pre.ignore {
.tooltip::after {
background-color: #314559;
color: #c5c5c5;
- border: 1px solid #5c6773;
}
.tooltip::before {
@@ -346,11 +227,6 @@ pre.ignore:hover, .information:hover + pre.ignore {
.notable-traits-tooltiptext {
background-color: #314559;
- border-color: #5c6773;
-}
-
-.notable-traits-tooltiptext .notable {
- border-bottom-color: #5c6773;
}
#titles > button.selected {
@@ -378,38 +254,11 @@ 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-input:focus {}
-.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,
-.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {}
-.content span.struct,.content a.struct,.block a.current.struct {}
-#titles>button:hover,#titles>button.selected {}
-.content span.typedef,.content a.typedef,.block a.current.typedef {}
-.content span.union,.content a.union,.block a.current.union {}
pre.rust .lifetime {}
-.stab.unstable {}
-h2,
-h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {}
-.content span.enum,.content a.enum,.block a.current.enum {}
-.content span.constant,.content a.constant,.block a.current.constant,.content span.static,
-.content a.static, .block a.current.static {}
-.content span.keyword,.content a.keyword,.block a.current.keyword {}
-pre.rust .comment {}
-.content span.traitalias,.content a.traitalias,.block a.current.traitalias {}
-.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,
-.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,
-.content .fnname {}
pre.rust .kw {}
-pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,
-pre.rust .attribute .ident {}
-.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype {}
-pre.rust .doccomment {}
-.stab.deprecated {}
-.content a.attr,.content a.derive,.content a.macro {}
-.stab.portability {}
-.content span.primitive,.content a.primitive,.block a.current.primitive {}
-.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod {}
-pre.rust .kw-2,pre.rust .prelude-ty {}
-.content span.trait,.content a.trait,.block a.current.trait {}
+#titles > button:hover, #titles > button.selected {}
+pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, pre.rust .attribute {}
+pre.rust .kw-2, pre.rust .prelude-ty {}
.search-results a:focus span {}
a.result-trait:focus {}
@@ -445,32 +294,18 @@ a.result-keyword:focus {}
.sidebar a.current.constant
.sidebar a.current.static {}
.sidebar a.current.primitive {}
-.sidebar a.current.externcrate
-.sidebar a.current.mod {}
.sidebar a.current.trait {}
.sidebar a.current.traitalias {}
-.sidebar a.current.fn,
-.sidebar a.current.method,
-.sidebar a.current.tymethod {}
+.sidebar a.current.fn {}
.sidebar a.current.keyword {}
-@media (max-width: 700px) {
- .sidebar-elems {
- border-right-color: #5c6773;
- }
-}
-
kbd {
color: #c5c5c5;
background-color: #314559;
- border-color: #5c6773;
- border-bottom-color: #5c6773;
box-shadow: inset 0 -1px 0 #5c6773;
}
#settings-menu > a, #help-button > button {
- border-color: #5c6773;
- background-color: #0f1419;
color: #fff;
}
@@ -478,39 +313,11 @@ kbd {
filter: invert(100);
}
-.popover, .popover::before,
-#help-button span.top, #help-button span.bottom {
- border-color: #5c6773;
-}
-
-#copy-path {
- color: #fff;
-}
-#copy-path > img {
- filter: invert(70%);
-}
-#copy-path:hover > img {
- filter: invert(100%);
-}
-
#settings-menu > a:hover, #settings-menu > a:focus,
#help-button > button:hover, #help-button > button:focus {
border-color: #e0e0e0;
}
-#theme-choices {
- border-color: #5c6773;
- background-color: #0f1419;
-}
-
-#theme-choices > button:not(:first-child) {
- border-top-color: #5c6773;
-}
-
-#theme-choices > button:hover, #theme-choices > button:focus {
- background-color: rgba(110, 110, 110, 0.33);
-}
-
.search-results .result-name span.alias {
color: #c5c5c5;
}
@@ -520,7 +327,6 @@ kbd {
#source-sidebar > .title {
color: #fff;
- border-bottom-color: #5c6773;
}
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
@@ -540,9 +346,6 @@ kbd {
border-color: white;
color: white;
}
-.more-examples-toggle summary, .more-examples-toggle .hide-more {
- color: #999;
-}
.scraped-example .example-wrap .rust span.highlight {
background: rgb(91, 59, 1);
}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index a550eb1c1..07a1ed8b7 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -9,6 +9,27 @@
--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
--scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
--headings-border-bottom-color: #d2d2d2;
+ --border-color: #e0e0e0;
+ --button-background-color: #f0f0f0;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --search-input-focused-border-color: #008dfd;
+ --copy-path-button-color: #999;
+ --copy-path-img-filter: invert(50%);
+ --copy-path-img-hover-filter: invert(65%);
+ --codeblock-error-hover-color: rgb(255, 0, 0);
+ --codeblock-error-color: rgba(255, 0, 0, .5);
+ --codeblock-ignore-hover-color: rgb(255, 142, 0);
+ --codeblock-ignore-color: rgba(255, 142, 0, .6);
+ --type-link-color: #2dbfb8;
+ --trait-link-color: #b78cf2;
+ --assoc-item-link-color: #d2991d;
+ --function-link-color: #2bab63;
+ --macro-link-color: #09bd00;
+ --keyword-link-color: #d2991d;
+ --mod-link-color: #d2991d;
+ --link-color: #d2991d;
}
.slider {
@@ -21,10 +42,6 @@ input:focus + .slider {
box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
}
-.in-band {
- background-color: #353535;
-}
-
.rust-logo {
filter: drop-shadow(1px 0 0px #fff)
drop-shadow(0 1px 0 #fff)
@@ -42,10 +59,6 @@ input:focus + .slider {
background-color: #0a042f !important;
}
-.docblock table td, .docblock table th {
- border-color: #ddd;
-}
-
.search-results a:hover {
background-color: #777;
}
@@ -78,35 +91,10 @@ a.result-keyword:focus { background-color: #884719; }
.content .item-info::before { color: #ccc; }
-.content span.enum, .content a.enum, .block a.current.enum { color: #2dbfb8; }
-.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; }
-.content span.type, .content a.type, .block a.current.type { color: #2dbfb8; }
-.content span.associatedtype,
-.content a.associatedtype,
-.block a.current.associatedtype { color: #D2991D; }
-.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #2dbfb8; }
-.content span.attr, .content a.attr, .block a.current.attr,
-.content span.derive, .content a.derive, .block a.current.derive,
-.content span.macro, .content a.macro, .block a.current.macro { color: #09bd00; }
-.content span.union, .content a.union, .block a.current.union { color: #2dbfb8; }
-.content span.constant, .content a.constant, .block a.current.constant,
-.content span.static, .content a.static, .block a.current.static { color: #D2991D; }
-.content span.primitive, .content a.primitive, .block a.current.primitive { color: #2dbfb8; }
-.content span.externcrate,
-.content span.mod, .content a.mod, .block a.current.mod { color: #D2991D; }
-.content span.trait, .content a.trait, .block a.current.trait { color: #b78cf2; }
-.content span.traitalias, .content a.traitalias, .block a.current.traitalias { color: #b78cf2; }
-.content span.fn, .content a.fn, .block a.current.fn,
-.content span.method, .content a.method, .block a.current.method,
-.content span.tymethod, .content a.tymethod, .block a.current.tymethod,
-.content .fnname{ color: #2BAB63; }
-.content span.keyword, .content a.keyword, .block a.current.keyword { color: #D2991D; }
-
.sidebar a { color: #fdbf35; }
.sidebar a.current.enum { color: #12ece2; }
.sidebar a.current.struct { color: #12ece2; }
.sidebar a.current.type { color: #12ece2; }
-.sidebar a.current.associatedtype { color: #fdbf35; }
.sidebar a.current.foreigntype { color: #12ece2; }
.sidebar a.current.attr,
.sidebar a.current.derive,
@@ -115,74 +103,42 @@ a.result-keyword:focus { background-color: #884719; }
.sidebar a.current.constant
.sidebar a.current.static { color: #fdbf35; }
.sidebar a.current.primitive { color: #12ece2; }
-.sidebar a.current.externcrate
-.sidebar a.current.mod { color: #fdbf35; }
.sidebar a.current.trait { color: #cca7ff; }
.sidebar a.current.traitalias { color: #cca7ff; }
-.sidebar a.current.fn,
-.sidebar a.current.method,
-.sidebar a.current.tymethod { color: #32d479; }
+.sidebar a.current.fn { color: #32d479; }
.sidebar a.current.keyword { color: #fdbf35; }
pre.rust .comment { color: #8d8d8b; }
pre.rust .doccomment { color: #8ca375; }
-nav.main .current {
- border-top-color: #eee;
- border-bottom-color: #eee;
-}
-nav.main .separator {
- border-color: #eee;
-}
-
-a {
- color: #D2991D;
-}
-
body.source .example-wrap pre.rust a {
background: #333;
}
-details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
- color: #999;
-}
-
details.rustdoc-toggle > summary::before {
filter: invert(100%);
}
-#crate-search, .search-input {
+.search-input {
color: #111;
- background-color: #f0f0f0;
- border-color: #f0f0f0;
}
-#crate-search {
- /* Without the `!important`, the border-color is ignored for `<select>`...
- It cannot be in the group above because `.search-input` has a different border color on
- hover. */
- border-color: #f0f0f0 !important;
+#crate-search-div::after {
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);
}
-
-.search-input {
- border-color: #e0e0e0;
+#crate-search:hover, #crate-search:focus {
+ border-color: #2196f3 !important;
}
-
-.search-input:focus {
- border-color: #008dfd;
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+ filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);
}
-.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
-.stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
-.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; }
-.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
-.stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
-.stab.portability > code { background: none; }
+.stab { background: #314559; }
-.rightside,
-.out-of-band {
- color: grey;
+.stab.portability > code {
+ color: #e6e1cf;
+ background: none;
}
.line-numbers :target { background-color: transparent; }
@@ -192,7 +148,7 @@ pre.rust .kw { color: #ab8ac1; }
pre.rust .kw-2, pre.rust .prelude-ty { color: #769acb; }
pre.rust .number, pre.rust .string { color: #83a300; }
pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
-pre.rust .attribute, pre.rust .attribute .ident { color: #ee6868; }
+pre.rust .attribute { color: #ee6868; }
pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
pre.rust .lifetime { color: #d97f26; }
pre.rust .question-mark {
@@ -212,64 +168,11 @@ a.test-arrow:hover{
background-color: #4e8bca;
}
-.toggle-label,
-.code-attribute {
- color: #999;
-}
-
:target {
background-color: #494a3d;
border-right: 3px solid #bb7410;
}
-pre.compile_fail {
- border-left: 2px solid rgba(255,0,0,.8);
-}
-
-pre.compile_fail:hover, .information:hover + pre.compile_fail {
- border-left: 2px solid #f00;
-}
-
-pre.should_panic {
- border-left: 2px solid rgba(255,0,0,.8);
-}
-
-pre.should_panic:hover, .information:hover + pre.should_panic {
- border-left: 2px solid #f00;
-}
-
-pre.ignore {
- border-left: 2px solid rgba(255,142,0,.6);
-}
-
-pre.ignore:hover, .information:hover + pre.ignore {
- border-left: 2px solid #ff9200;
-}
-
-.tooltip.compile_fail {
- color: rgba(255,0,0,.8);
-}
-
-.information > .compile_fail:hover {
- color: #f00;
-}
-
-.tooltip.should_panic {
- color: rgba(255,0,0,.8);
-}
-
-.information > .should_panic:hover {
- color: #f00;
-}
-
-.tooltip.ignore {
- color: rgba(255,142,0,.6);
-}
-
-.information > .ignore:hover {
- color: #ff9200;
-}
-
.search-failed a {
color: #0089ff;
}
@@ -286,11 +189,6 @@ pre.ignore:hover, .information:hover + pre.ignore {
.notable-traits-tooltiptext {
background-color: #111;
- border-color: #777;
-}
-
-.notable-traits-tooltiptext .notable {
- border-bottom-color: #d2d2d2;
}
#titles > button:not(.selected) {
@@ -307,23 +205,13 @@ pre.ignore:hover, .information:hover + pre.ignore {
color: #888;
}
-@media (max-width: 700px) {
- .sidebar-elems {
- border-right-color: #000;
- }
-}
-
kbd {
color: #000;
background-color: #fafbfc;
- border-color: #d1d5da;
- border-bottom-color: #c6cbd1;
box-shadow: inset 0 -1px 0 #c6cbd1;
}
#settings-menu > a, #help-button > button {
- border-color: #e0e0e0;
- background: #f0f0f0;
color: #000;
}
@@ -332,34 +220,6 @@ kbd {
border-color: #ffb900;
}
-.popover, .popover::before,
-#help-button span.top, #help-button span.bottom {
- border-color: #d2d2d2;
-}
-
-#copy-path {
- color: #999;
-}
-#copy-path > img {
- filter: invert(50%);
-}
-#copy-path:hover > img {
- filter: invert(65%);
-}
-
-#theme-choices {
- border-color: #e0e0e0;
- background-color: #353535;
-}
-
-#theme-choices > button:not(:first-child) {
- border-top-color: #e0e0e0;
-}
-
-#theme-choices > button:hover, #theme-choices > button:focus {
- background-color: #4e4e4e;
-}
-
.search-results .result-name span.alias {
color: #fff;
}
@@ -367,9 +227,6 @@ kbd {
color: #ccc;
}
-#source-sidebar > .title {
- border-bottom-color: #ccc;
-}
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
background-color: #444;
@@ -386,9 +243,6 @@ kbd {
border-color: white;
color: white;
}
-.more-examples-toggle summary, .more-examples-toggle .hide-more {
- color: #999;
-}
.scraped-example .example-wrap .rust span.highlight {
background: rgb(91, 59, 1);
}
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index b751acff1..64335f629 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -9,6 +9,27 @@
--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
--scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
--headings-border-bottom-color: #ddd;
+ --border-color: #e0e0e0;
+ --button-background-color: #fff;
+ --right-side-color: grey;
+ --code-attribute-color: #999;
+ --toggles-color: #999;
+ --search-input-focused-border-color: #66afe9;
+ --copy-path-button-color: #999;
+ --copy-path-img-filter: invert(50%);
+ --copy-path-img-hover-filter: invert(35%);
+ --codeblock-error-hover-color: rgb(255, 0, 0);
+ --codeblock-error-color: rgba(255, 0, 0, .5);
+ --codeblock-ignore-hover-color: rgb(255, 142, 0);
+ --codeblock-ignore-color: rgba(255, 142, 0, .6);
+ --type-link-color: #ad378a;
+ --trait-link-color: #6e4fc9;
+ --assoc-item-link-color: #3873ad;
+ --function-link-color: #ad7c37;
+ --macro-link-color: #068000;
+ --keyword-link-color: #3873ad;
+ --mod-link-color: #3873ad;
+ --link-color: #3873ad;
}
.slider {
@@ -21,10 +42,6 @@ input:focus + .slider {
box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
}
-.in-band {
- background-color: white;
-}
-
.rust-logo {
/* This rule exists to force other themes to explicitly style the logo.
* Rustdoc has a custom linter for this purpose.
@@ -41,10 +58,6 @@ input:focus + .slider {
background-color: #FDFFD3 !important;
}
-.docblock table td, .docblock table th {
- border-color: #ddd;
-}
-
.search-results a:hover {
background-color: #ddd;
}
@@ -77,35 +90,10 @@ a.result-keyword:focus { background-color: #afc6e4; }
.content .item-info::before { color: #ccc; }
-.content span.enum, .content a.enum, .block a.current.enum { color: #AD378A; }
-.content span.struct, .content a.struct, .block a.current.struct { color: #AD378A; }
-.content span.type, .content a.type, .block a.current.type { color: #AD378A; }
-.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #3873AD; }
-.content span.associatedtype,
-.content a.associatedtype,
-.block a.current.associatedtype { color: #3873AD; }
-.content span.attr, .content a.attr, .block a.current.attr,
-.content span.derive, .content a.derive, .block a.current.derive,
-.content span.macro, .content a.macro, .block a.current.macro { color: #068000; }
-.content span.union, .content a.union, .block a.current.union { color: #AD378A; }
-.content span.constant, .content a.constant, .block a.current.constant,
-.content span.static, .content a.static, .block a.current.static { color: #3873AD; }
-.content span.primitive, .content a.primitive, .block a.current.primitive { color: #AD378A; }
-.content span.externcrate,
-.content span.mod, .content a.mod, .block a.current.mod { color: #3873AD; }
-.content span.trait, .content a.trait, .block a.current.trait { color: #6E4FC9; }
-.content span.traitalias, .content a.traitalias, .block a.current.traitalias { color: #5137AD; }
-.content span.fn, .content a.fn, .block a.current.fn,
-.content span.method, .content a.method, .block a.current.method,
-.content span.tymethod, .content a.tymethod, .block a.current.tymethod,
-.content .fnname { color: #AD7C37; }
-.content span.keyword, .content a.keyword, .block a.current.keyword { color: #3873AD; }
-
.sidebar a { color: #356da4; }
.sidebar a.current.enum { color: #a63283; }
.sidebar a.current.struct { color: #a63283; }
.sidebar a.current.type { color: #a63283; }
-.sidebar a.current.associatedtype { color: #356da4; }
.sidebar a.current.foreigntype { color: #356da4; }
.sidebar a.current.attr,
.sidebar a.current.derive,
@@ -114,64 +102,29 @@ a.result-keyword:focus { background-color: #afc6e4; }
.sidebar a.current.constant
.sidebar a.current.static { color: #356da4; }
.sidebar a.current.primitive { color: #a63283; }
-.sidebar a.current.externcrate
-.sidebar a.current.mod { color: #356da4; }
.sidebar a.current.trait { color: #6849c3; }
.sidebar a.current.traitalias { color: #4b349e; }
-.sidebar a.current.fn,
-.sidebar a.current.method,
-.sidebar a.current.tymethod { color: #a67736; }
+.sidebar a.current.fn { color: #a67736; }
.sidebar a.current.keyword { color: #356da4; }
-nav.main .current {
- border-top-color: #000;
- border-bottom-color: #000;
-}
-nav.main .separator {
- border: 1px solid #000;
-}
-
-a {
- color: #3873AD;
-}
-
body.source .example-wrap pre.rust a {
background: #eee;
}
-details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
- color: #999;
+#crate-search-div::after {
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);
}
-
-#crate-search, .search-input {
- background-color: white;
- border-color: #e0e0e0;
-}
-
-#crate-search {
- /* Without the `!important`, the border-color is ignored for `<select>`...
- It cannot be in the group above because `.search-input` has a different border color on
- hover. */
- border-color: #e0e0e0 !important;
+#crate-search:hover, #crate-search:focus {
+ border-color: #717171 !important;
}
-
-.search-input:focus {
- border-color: #66afe9;
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+ filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);
}
-.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; }
-.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
-.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; }
-.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; }
-.stab.portability { background: #F3DFFF; border-color: #b07bdb; }
+.stab { background: #FFF5D6; border-color: #FFC600; }
.stab.portability > code { background: none; }
-.rightside,
-.out-of-band {
- color: grey;
-}
-
.line-numbers :target { background-color: transparent; }
/* Code highlighting */
@@ -179,7 +132,7 @@ pre.rust .kw { color: #8959A8; }
pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
pre.rust .number, pre.rust .string { color: #718C00; }
pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
-pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
+pre.rust .attribute { color: #C82829; }
pre.rust .comment { color: #8E908C; }
pre.rust .doccomment { color: #4D4D4C; }
pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
@@ -201,64 +154,11 @@ a.test-arrow:hover{
background-color: #4e8bca;
}
-.toggle-label,
-.code-attribute {
- color: #999;
-}
-
:target {
background: #FDFFD3;
border-right: 3px solid #AD7C37;
}
-pre.compile_fail {
- border-left: 2px solid rgba(255,0,0,.5);
-}
-
-pre.compile_fail:hover, .information:hover + pre.compile_fail {
- border-left: 2px solid #f00;
-}
-
-pre.should_panic {
- border-left: 2px solid rgba(255,0,0,.5);
-}
-
-pre.should_panic:hover, .information:hover + pre.should_panic {
- border-left: 2px solid #f00;
-}
-
-pre.ignore {
- border-left: 2px solid rgba(255,142,0,.6);
-}
-
-pre.ignore:hover, .information:hover + pre.ignore {
- border-left: 2px solid #ff9200;
-}
-
-.tooltip.compile_fail {
- color: rgba(255,0,0,.5);
-}
-
-.information > .compile_fail:hover {
- color: #f00;
-}
-
-.tooltip.should_panic {
- color: rgba(255,0,0,.5);
-}
-
-.information > .should_panic:hover {
- color: #f00;
-}
-
-.tooltip.ignore {
- color: rgba(255,142,0,.6);
-}
-
-.information > .ignore:hover {
- color: #ff9200;
-}
-
.search-failed a {
color: #3873AD;
}
@@ -274,11 +174,6 @@ pre.ignore:hover, .information:hover + pre.ignore {
.notable-traits-tooltiptext {
background-color: #eee;
- border-color: #999;
-}
-
-.notable-traits-tooltiptext .notable {
- border-bottom-color: #DDDDDD;
}
#titles > button:not(.selected) {
@@ -295,58 +190,17 @@ pre.ignore:hover, .information:hover + pre.ignore {
color: #888;
}
-@media (max-width: 700px) {
- .sidebar-elems {
- border-right-color: #000;
- }
-}
-
kbd {
color: #000;
background-color: #fafbfc;
- border-color: #d1d5da;
- border-bottom-color: #c6cbd1;
box-shadow: inset 0 -1px 0 #c6cbd1;
}
-#settings-menu > a, #help-button > button {
- border-color: #e0e0e0;
- background-color: #fff;
-}
-
#settings-menu > a:hover, #settings-menu > a:focus,
#help-button > button:hover, #help-button > button:focus {
border-color: #717171;
}
-.popover, .popover::before,
-#help-button span.top, #help-button span.bottom {
- border-color: #DDDDDD;
-}
-
-#copy-path {
- color: #999;
-}
-#copy-path > img {
- filter: invert(50%);
-}
-#copy-path:hover > img {
- filter: invert(35%);
-}
-
-#theme-choices {
- border-color: #ccc;
- background-color: #fff;
-}
-
-#theme-choices > button:not(:first-child) {
- border-top-color: #e0e0e0;
-}
-
-#theme-choices > button:hover, #theme-choices > button:focus {
- background-color: #eee;
-}
-
.search-results .result-name span.alias {
color: #000;
}
@@ -354,9 +208,6 @@ kbd {
color: #999;
}
-#source-sidebar > .title {
- border-bottom-color: #ccc;
-}
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
background-color: #E0E0E0;
@@ -372,9 +223,6 @@ kbd {
border-color: black;
color: black;
}
-.more-examples-toggle summary, .more-examples-toggle .hide-more {
- color: #999;
-}
.scraped-example .example-wrap .rust span.highlight {
background: #fcffd6;
}
diff --git a/src/librustdoc/html/static/images/down-arrow.svg b/src/librustdoc/html/static/images/down-arrow.svg
index 35437e77a..5d76a64e9 100644
--- a/src/librustdoc/html/static/images/down-arrow.svg
+++ b/src/librustdoc/html/static/images/down-arrow.svg
@@ -1 +1 @@
-<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="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg> \ No newline at end of file
+<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/js/main.js b/src/librustdoc/html/static/js/main.js
index 0702b2b0b..6e9660ddc 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -348,8 +348,7 @@ function loadCss(cssFileName) {
function onHashChange(ev) {
// If we're in mobile mode, we should hide the sidebar in any case.
- const sidebar = document.getElementsByClassName("sidebar")[0];
- removeClass(sidebar, "shown");
+ hideSidebar();
handleHashes(ev);
}
@@ -501,6 +500,10 @@ function loadCss(cssFileName) {
const synthetic_implementors = document.getElementById("synthetic-implementors-list");
const inlined_types = new Set();
+ const TEXT_IDX = 0;
+ const SYNTHETIC_IDX = 1;
+ const TYPES_IDX = 2;
+
if (synthetic_implementors) {
// This `inlined_types` variable is used to avoid having the same implementation
// showing up twice. For example "String" in the "Sync" doc page.
@@ -525,9 +528,9 @@ function loadCss(cssFileName) {
// We don't want to include impls from this JS file, when the HTML already has them.
// The current crate should always be ignored. Other crates that should also be
// ignored are included in the attribute `data-ignore-extern-crates`.
- const ignoreExternCrates = document
- .querySelector("script[data-ignore-extern-crates]")
- .getAttribute("data-ignore-extern-crates");
+ const script = document
+ .querySelector("script[data-ignore-extern-crates]");
+ const ignoreExternCrates = script ? script.getAttribute("data-ignore-extern-crates") : "";
for (const lib of libs) {
if (lib === window.currentCrate || ignoreExternCrates.indexOf(lib) !== -1) {
continue;
@@ -536,10 +539,12 @@ function loadCss(cssFileName) {
struct_loop:
for (const struct of structs) {
- const list = struct.synthetic ? synthetic_implementors : implementors;
+ const list = struct[SYNTHETIC_IDX] ? synthetic_implementors : implementors;
- if (struct.synthetic) {
- for (const struct_type of struct.types) {
+ // The types list is only used for synthetic impls.
+ // If this changes, `main.js` and `write_shared.rs` both need changed.
+ if (struct[SYNTHETIC_IDX]) {
+ for (const struct_type of struct[TYPES_IDX]) {
if (inlined_types.has(struct_type)) {
continue struct_loop;
}
@@ -548,7 +553,7 @@ function loadCss(cssFileName) {
}
const code = document.createElement("h3");
- code.innerHTML = struct.text;
+ code.innerHTML = struct[TEXT_IDX];
addClass(code, "code-header");
addClass(code, "in-band");
@@ -694,9 +699,8 @@ function loadCss(cssFileName) {
(function() {
// To avoid checking on "rustdoc-line-numbers" value on every loop...
- let lineNumbersFunc = () => {};
if (getSettingValue("line-numbers") === "true") {
- lineNumbersFunc = x => {
+ onEachLazy(document.getElementsByClassName("rust-example-rendered"), x => {
const count = x.textContent.split("\n").length;
const elems = [];
for (let i = 0; i < count; ++i) {
@@ -706,33 +710,54 @@ function loadCss(cssFileName) {
addClass(node, "line-number");
node.innerHTML = elems.join("\n");
x.parentNode.insertBefore(node, x);
- };
+ });
}
- onEachLazy(document.getElementsByClassName("rust-example-rendered"), e => {
- if (hasClass(e, "compile_fail")) {
- e.addEventListener("mouseover", function() {
- this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
- });
- e.addEventListener("mouseout", function() {
- this.parentElement.previousElementSibling.childNodes[0].style.color = "";
- });
- } else if (hasClass(e, "ignore")) {
- e.addEventListener("mouseover", function() {
- this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
- });
- e.addEventListener("mouseout", function() {
- this.parentElement.previousElementSibling.childNodes[0].style.color = "";
- });
- }
- lineNumbersFunc(e);
- });
}());
+ let oldSidebarScrollPosition = null;
+
+ function showSidebar() {
+ if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+ // This is to keep the scroll position on mobile.
+ oldSidebarScrollPosition = window.scrollY;
+ document.body.style.width = `${document.body.offsetWidth}px`;
+ document.body.style.position = "fixed";
+ document.body.style.top = `-${oldSidebarScrollPosition}px`;
+ document.querySelector(".mobile-topbar").style.top = `${oldSidebarScrollPosition}px`;
+ document.querySelector(".mobile-topbar").style.position = "relative";
+ } else {
+ oldSidebarScrollPosition = null;
+ }
+ const sidebar = document.getElementsByClassName("sidebar")[0];
+ addClass(sidebar, "shown");
+ }
+
function hideSidebar() {
+ if (oldSidebarScrollPosition !== null) {
+ // This is to keep the scroll position on mobile.
+ document.body.style.width = "";
+ document.body.style.position = "";
+ document.body.style.top = "";
+ document.querySelector(".mobile-topbar").style.top = "";
+ document.querySelector(".mobile-topbar").style.position = "";
+ // The scroll position is lost when resetting the style, hence why we store it in
+ // `oldSidebarScrollPosition`.
+ window.scrollTo(0, oldSidebarScrollPosition);
+ oldSidebarScrollPosition = null;
+ }
const sidebar = document.getElementsByClassName("sidebar")[0];
removeClass(sidebar, "shown");
}
+ window.addEventListener("resize", () => {
+ if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT &&
+ oldSidebarScrollPosition !== null) {
+ // If the user opens the sidebar in "mobile" mode, and then grows the browser window,
+ // we need to switch away from mobile mode and make the main content area scrollable.
+ hideSidebar();
+ }
+ });
+
function handleClick(id, f) {
const elem = document.getElementById(id);
if (elem) {
@@ -775,9 +800,9 @@ function loadCss(cssFileName) {
sidebar_menu_toggle.addEventListener("click", () => {
const sidebar = document.getElementsByClassName("sidebar")[0];
if (!hasClass(sidebar, "shown")) {
- addClass(sidebar, "shown");
+ showSidebar();
} else {
- removeClass(sidebar, "shown");
+ hideSidebar();
}
});
}
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 75c7bd45a..d04ec357c 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -429,9 +429,9 @@ function initSearch(rawSearchIndex) {
}
const posBefore = parserState.pos;
getNextElem(query, parserState, elems, endChar === ">");
- // This case can be encountered if `getNextElem` encounted 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.
+ // 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.
if (posBefore === parserState.pos) {
parserState.pos += 1;
}
@@ -581,7 +581,7 @@ function initSearch(rawSearchIndex) {
const elem = document.getElementById("crate-search");
if (elem &&
- elem.value !== "All crates" &&
+ elem.value !== "all crates" &&
hasOwnPropertyRustdoc(rawSearchIndex, elem.value)
) {
return elem.value;
@@ -1551,12 +1551,6 @@ function initSearch(rawSearchIndex) {
return [displayPath, href];
}
- function escape(content) {
- const h1 = document.createElement("h1");
- h1.textContent = content;
- return h1.innerHTML;
- }
-
function pathSplitter(path) {
const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
if (tmp.endsWith("<span>")) {
@@ -1710,22 +1704,15 @@ function initSearch(rawSearchIndex) {
let crates = "";
const crates_list = Object.keys(rawSearchIndex);
if (crates_list.length > 1) {
- crates = " in <select id=\"crate-search\"><option value=\"All crates\">" +
- "All crates</option>";
+ crates = " in&nbsp;<div id=\"crate-search-div\"><select id=\"crate-search\">" +
+ "<option value=\"all crates\">all crates</option>";
for (const c of crates_list) {
crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`;
}
- crates += "</select>";
- }
-
- let typeFilter = "";
- if (results.query.typeFilter !== NO_TYPE_FILTER) {
- typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
+ crates += "</select></div>";
}
- let output = "<div id=\"search-settings\">" +
- `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
- `${typeFilter}</h1>${crates}</div>`;
+ let output = `<h1 class="search-results-title">Results${crates}</h1>`;
if (results.query.error !== null) {
output += `<h3>Query parser error: "${results.query.error}".</h3>`;
output += "<div id=\"titles\">" +
@@ -2245,7 +2232,7 @@ function initSearch(rawSearchIndex) {
}
function updateCrate(ev) {
- if (ev.target.value === "All crates") {
+ if (ev.target.value === "all crates") {
// If we don't remove it from the URL, it'll be picked up again by the search.
const params = searchState.getQueryStringParams();
const query = searchState.input.value.trim();
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index c45d61429..06d15d9e5 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -10,7 +10,7 @@
(function() {
const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
-let oldScrollPosition = 0;
+let oldScrollPosition = null;
const NAME_OFFSET = 0;
const DIRS_OFFSET = 1;
@@ -75,18 +75,21 @@ function toggleSidebar() {
oldScrollPosition = window.scrollY;
document.body.style.position = "fixed";
document.body.style.top = `-${oldScrollPosition}px`;
+ } else {
+ oldScrollPosition = null;
}
addClass(document.documentElement, "source-sidebar-expanded");
child.innerText = "<";
updateLocalStorage("source-sidebar-show", "true");
} else {
- if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+ if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
// This is to keep the scroll position on mobile.
document.body.style.position = "";
document.body.style.top = "";
// The scroll position is lost when resetting the style, hence why we store it in
- // `oldScroll`.
+ // `oldScrollPosition`.
window.scrollTo(0, oldScrollPosition);
+ oldScrollPosition = null;
}
removeClass(document.documentElement, "source-sidebar-expanded");
child.innerText = ">";
@@ -94,6 +97,17 @@ function toggleSidebar() {
}
}
+window.addEventListener("resize", () => {
+ if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
+ // If the user opens the sidebar in "mobile" mode, and then grows the browser window,
+ // we need to switch away from mobile mode and make the main content area scrollable.
+ document.body.style.position = "";
+ document.body.style.top = "";
+ window.scrollTo(0, oldScrollPosition);
+ oldScrollPosition = null;
+ }
+});
+
function createSidebarToggle() {
const sidebarToggle = document.createElement("div");
sidebarToggle.id = "sidebar-toggle";
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 8e25f6764..7caffeae3 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -13,13 +13,13 @@
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
- <link rel="stylesheet" type="text/css" {# -#}
+ <link rel="stylesheet" {# -#}
href="{{static_root_path|safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
- <link rel="stylesheet" type="text/css" {# -#}
+ <link rel="stylesheet" {# -#}
href="{{static_root_path|safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
id="mainThemeStyle"> {#- -#}
{%- for theme in themes -%}
- <link rel="stylesheet" type="text/css" {# -#}
+ <link rel="stylesheet" {# -#}
href="{{static_root_path|safe}}{{theme}}{{page.resource_suffix}}.css" {# -#}
{%- if theme == "light" -%}
id="themeStyle"
@@ -51,7 +51,7 @@
href="{{static_root_path|safe}}noscript{{page.resource_suffix}}.css"> {#- -#}
</noscript> {#- -#}
{%- if layout.css_file_extension.is_some() -%}
- <link rel="stylesheet" type="text/css" {# -#}
+ <link rel="stylesheet" {# -#}
href="{{static_root_path|safe}}theme{{page.resource_suffix}}.css"> {#- -#}
{%- endif -%}
{%- if !layout.favicon.is_empty() -%}