Skip to content

Commit

Permalink
Improve CSS for "hide contents, not items"
Browse files Browse the repository at this point in the history
Introduce a first use of the `<details>` and `<summary>` tags as
replacements for the JS-built toggles. I think this has the potential to
replace all the JS toggles and generally clean up the JS, CSS, and HTML.

Split rendering of attributes into two cases: in the case where they are
rendered as descendents of a `<pre>` tag, where they use indent spaces and
newlines for formatting, matching their surrounding markup. In the case
where they are rendered as descendants of a `<code>` tag, they are
rendered as `<div>`. This let me clean up some fragile CSS that was
adjusting the margin-left of attributes depending on context.

Remove toggles for attributes. With the ALLOWED_ATTRIBUTES filter, it's
rare for an item to have more than one attribute, so hiding attributes
behind a toggle doesn't save any screen space in the common case.

Fix a couple of invocations of `matches!` that didn't compile on my
machine.

Fix a boolean for the JS `createToggle` call that was causing
"Expand description" to show up spuriously on already-expanded
descriptions.

Add JS for auto-hide settings and hide all / show all.

Remove a z-index property and some font color tweaks made unnecessary
by the <details> toggles.

Add CSS for the <details> toggles.
  • Loading branch information
jsha committed Mar 27, 2021
1 parent 790218f commit 79bd6be
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 130 deletions.
52 changes: 25 additions & 27 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ use std::str;
use std::string::ToString;
use std::sync::mpsc::Receiver;

use itertools::Itertools;
use rustc_ast_pretty::pprust;
use rustc_attr::{Deprecation, StabilityLevel};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
Expand Down Expand Up @@ -575,7 +574,6 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<Strin
)
.into(),
("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
("auto-hide-attributes", "Auto-hide item attributes.", true).into(),
("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", true)
.into(),
Expand Down Expand Up @@ -1011,18 +1009,20 @@ fn render_assoc_item(
g.print(cx.cache())
)
.len();
let (indent, end_newline) = if parent == ItemType::Trait {
let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
header_len += 4;
(4, false)
let indent_str = " ";
render_attributes_in_pre(w, meth, indent_str);
(4, indent_str, false)
} else {
(0, true)
render_attributes_in_code(w, meth);
(0, "", true)
};
render_attributes(w, meth, false);
write!(
w,
"{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
{generics}{decl}{spotlight}{where_clause}",
if parent == ItemType::Trait { " " } else { "" },
indent_str,
meth.visibility.print_with_space(cx.tcx(), meth.def_id, cx.cache()),
header.constness.print_with_space(),
header.asyncness.print_with_space(),
Expand Down Expand Up @@ -1078,35 +1078,33 @@ const ALLOWED_ATTRIBUTES: &[Symbol] = &[
sym::non_exhaustive,
];

// The `top` parameter is used when generating the item declaration to ensure it doesn't have a
// left padding. For example:
//
// #[foo] <----- "top" attribute
// struct Foo {
// #[bar] <---- not "top" attribute
// bar: usize,
// }
fn render_attributes(w: &mut Buffer, it: &clean::Item, top: bool) {
let attrs = it
.attrs
fn attributes(it: &clean::Item) -> Vec<String> {
it.attrs
.other_attrs
.iter()
.filter_map(|attr| {
if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
Some(pprust::attribute_to_string(&attr))
Some(pprust::attribute_to_string(&attr).replace("\n", "").replace(" ", " "))
} else {
None
}
})
.join("\n");
.collect()
}

if !attrs.is_empty() {
write!(
w,
"<span class=\"docblock attributes{}\">{}</span>",
if top { " top-attr" } else { "" },
&attrs
);
// When an attribute is rendered inside a `<pre>` tag, it is formatted using
// a whitespace prefix and newline.
fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
for a in attributes(it) {
write!(w, "{}{}\n", prefix, a);
}
}

// When an attribute is rendered inside a <code> tag, it is formatted using
// a div to produce a newline after it.
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
for a in attributes(it) {
write!(w, "<div>{}</div>", a);
}
}

Expand Down
46 changes: 23 additions & 23 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use rustc_span::symbol::{kw, sym, Symbol};

use super::{
collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_strs, render_assoc_item,
render_assoc_items, render_attributes, render_impl, render_stability_since_raw, spotlight_decl,
write_srclink, AssocItemLink, Context,
render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl,
render_stability_since_raw, spotlight_decl, write_srclink, AssocItemLink, Context,
};
use crate::clean::{self, GetDefId};
use crate::formats::cache::Cache;
Expand Down Expand Up @@ -137,11 +137,15 @@ fn should_hide_fields(n_fields: usize) -> bool {
}

fn toggle_open(w: &mut Buffer, text: &str) {
write!(w, "<div class=\"docblock type-contents-toggle\" data-toggle-text=\"{}\">", text);
write!(
w,
"<details class=\"type-contents-toggle\"><summary class=\"hideme\"><span>Show {}</span></summary>",
text
);
}

fn toggle_close(w: &mut Buffer) {
w.write_str("</div>");
w.write_str("</details>");
}

fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) {
Expand Down Expand Up @@ -390,7 +394,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
)
.len();
w.write_str("<pre class=\"rust fn\">");
render_attributes(w, it, false);
render_attributes_in_pre(w, it, "");
write!(
w,
"{vis}{constness}{asyncness}{unsafety}{abi}fn \
Expand Down Expand Up @@ -421,7 +425,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
// Output the trait definition
wrap_into_docblock(w, |w| {
w.write_str("<pre class=\"rust trait\">");
render_attributes(w, it, true);
render_attributes_in_pre(w, it, "");
write!(
w,
"{}{}{}trait {}{}{}",
Expand Down Expand Up @@ -731,7 +735,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra

fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
w.write_str("<pre class=\"rust trait-alias\">");
render_attributes(w, it, false);
render_attributes_in_pre(w, it, "");
write!(
w,
"trait {}{}{} = {};</pre>",
Expand All @@ -752,7 +756,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea

fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
w.write_str("<pre class=\"rust opaque\">");
render_attributes(w, it, false);
render_attributes_in_pre(w, it, "");
write!(
w,
"type {}{}{where_clause} = impl {bounds};</pre>",
Expand All @@ -774,7 +778,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:

fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
w.write_str("<pre class=\"rust typedef\">");
render_attributes(w, it, false);
render_attributes_in_pre(w, it, "");
write!(
w,
"type {}{}{where_clause} = {type_};</pre>",
Expand All @@ -797,7 +801,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::T
fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
wrap_into_docblock(w, |w| {
w.write_str("<pre class=\"rust union\">");
render_attributes(w, it, true);
render_attributes_in_pre(w, it, "");
render_union(w, it, Some(&s.generics), &s.fields, "", true, cx);
w.write_str("</pre>")
});
Expand Down Expand Up @@ -843,7 +847,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
wrap_into_docblock(w, |w| {
w.write_str("<pre class=\"rust enum\">");
render_attributes(w, it, true);
render_attributes_in_pre(w, it, "");
write!(
w,
"{}enum {}{}{}",
Expand Down Expand Up @@ -1023,7 +1027,7 @@ fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {

fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) {
w.write_str("<pre class=\"rust const\">");
render_attributes(w, it, false);
render_attributes_in_code(w, it);

write!(
w,
Expand Down Expand Up @@ -1059,7 +1063,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::
fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
wrap_into_docblock(w, |w| {
w.write_str("<pre class=\"rust struct\">");
render_attributes(w, it, true);
render_attributes_in_code(w, it);
render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true, cx);
w.write_str("</pre>")
});
Expand Down Expand Up @@ -1108,7 +1112,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St

fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
w.write_str("<pre class=\"rust static\">");
render_attributes(w, it, false);
render_attributes_in_code(w, it);
write!(
w,
"{vis}static {mutability}{name}: {typ}</pre>",
Expand All @@ -1122,7 +1126,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St

fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
w.write_str("<pre class=\"rust foreigntype\">extern {\n");
render_attributes(w, it, false);
render_attributes_in_code(w, it);
write!(
w,
" {}type {};\n}}</pre>",
Expand Down Expand Up @@ -1295,10 +1299,8 @@ fn render_union(
}

write!(w, " {{\n{}", tab);
let count_fields = fields
.iter()
.filter(|f| matches!(clean::StructFieldItem(..), *f.kind))
.count();
let count_fields =
fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
let toggle = should_hide_fields(count_fields);
if toggle {
toggle_open(w, "fields");
Expand Down Expand Up @@ -1356,10 +1358,8 @@ fn render_struct(
)
}
w.write_str(" {");
let count_fields = fields
.iter()
.filter(|f| matches!(clean::StructFieldItem(..) = *f.kind))
.count();
let count_fields =
fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
let has_visible_fields = count_fields > 0;
let toggle = should_hide_fields(count_fields);
if toggle {
Expand Down
58 changes: 16 additions & 42 deletions src/librustdoc/html/static/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// ignore-tidy-filelength
// Local js definitions:
/* global addClass, getSettingValue, hasClass */
/* global onEach, onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */
Expand Down Expand Up @@ -2252,6 +2251,9 @@ function defocusSearchBar() {
if (hasClass(innerToggle, "will-expand")) {
updateLocalStorage("rustdoc-collapse", "false");
removeClass(innerToggle, "will-expand");
onEachLazy(document.getElementsByTagName("details"), function(e) {
e.open = true;
});
onEveryMatchingChild(innerToggle, "inner", function(e) {
e.innerHTML = labelForToggleButton(false);
});
Expand All @@ -2264,6 +2266,9 @@ function defocusSearchBar() {
} else {
updateLocalStorage("rustdoc-collapse", "true");
addClass(innerToggle, "will-expand");
onEachLazy(document.getElementsByTagName("details"), function(e) {
e.open = false;
});
onEveryMatchingChild(innerToggle, "inner", function(e) {
var parent = e.parentNode;
var superParent = null;
Expand Down Expand Up @@ -2505,6 +2510,7 @@ function defocusSearchBar() {
var toggle = createSimpleToggle(false);
var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
let hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";

var func = function(e) {
var next = e.nextElementSibling;
Expand Down Expand Up @@ -2551,6 +2557,14 @@ function defocusSearchBar() {
onEachLazy(document.getElementsByClassName("associatedconstant"), func);
onEachLazy(document.getElementsByClassName("impl"), funcImpl);
var impl_call = function() {};
// Large items are hidden by default in the HTML. If the setting overrides that, show 'em.
if (!hideLargeItemContents) {
onEachLazy(document.getElementsByTagName("details"), function (e) {
if (hasClass(e, "type-contents-toggle")) {
e.open = true;
}
});
}
if (hideMethodDocs === true) {
impl_call = function(e, newToggle) {
if (e.id.match(/^impl(?:-\d+)?$/) === null) {
Expand Down Expand Up @@ -2639,14 +2653,6 @@ function defocusSearchBar() {
}
});
}
} else if (hasClass(e, "type-contents-toggle")) {
let text = e.getAttribute("data-toggle-text");
let hideItemContents = getSettingValue("auto-hide-large-items") !== "false";
let tog = createToggle(toggle, `Show ${text}`, null, "", !hideItemContents);
e.parentNode.insertBefore(tog, e);
if (hideItemContents) {
collapseDocs(e.previousSibling.childNodes[0], "toggle");
}
}
if (e.parentNode.id === "main") {
var otherMessage = "";
Expand Down Expand Up @@ -2680,7 +2686,7 @@ function defocusSearchBar() {
otherMessage,
fontSize,
extraClass,
false),
true),
e);
if (hasClass(e, "non-exhaustive") === true) {
collapseDocs(e.previousSibling.childNodes[0], "toggle");
Expand All @@ -2699,38 +2705,6 @@ function defocusSearchBar() {
}
}());

function createToggleWrapper(tog) {
var span = document.createElement("span");
span.className = "toggle-label";
span.style.display = "none";
span.innerHTML = "&nbsp;Expand&nbsp;attributes";
tog.appendChild(span);

var wrapper = document.createElement("div");
wrapper.className = "toggle-wrapper toggle-attributes";
wrapper.appendChild(tog);
return wrapper;
}

(function() {
// To avoid checking on "rustdoc-item-attributes" value on every loop...
var itemAttributesFunc = function() {};
if (getSettingValue("auto-hide-attributes") !== "false") {
itemAttributesFunc = function(x) {
collapseDocs(x.previousSibling.childNodes[0], "toggle");
};
}
var attributesToggle = createToggleWrapper(createSimpleToggle(false));
onEachLazy(main.getElementsByClassName("attributes"), function(i_e) {
var attr_tog = attributesToggle.cloneNode(true);
if (hasClass(i_e, "top-attr") === true) {
addClass(attr_tog, "top-attr");
}
i_e.parentNode.insertBefore(attr_tog, i_e);
itemAttributesFunc(i_e);
});
}());

(function() {
// To avoid checking on "rustdoc-line-numbers" value on every loop...
var lineNumbersFunc = function() {};
Expand Down
Loading

0 comments on commit 79bd6be

Please sign in to comment.