Skip to content

Commit a5c68d7

Browse files
authored
Rollup merge of #83337 - Manishearth:item-hide, r=GuillaumeGomez
rustdoc: Hide item contents, not items This tweaks rustdoc to hide item contents instead of items, and only when there are too many of them. This means that users will _always_ see the type parameters, and will _often_ see fields/etc as long as they are small. Traits have some heuristics for hiding only the methods or only the methods and the consts, since the associated types are super important. I'm happy to play around with the heuristics here; we could potentially make it so that structs/enums/etc are always hidden but traits will try really hard to show type aliases. This needs a test, but you can see it rendered at https://manishearth.net/sand/doc_render/bar/ <details> <summary> Code example </summary> ```rust pub struct PubStruct { pub a: usize, pub b: usize, } pub struct BigPubStruct { pub a: usize, pub b: usize, pub c: usize, pub d: usize, pub e: usize, pub f: usize, } pub union BigUnion { pub a: usize, pub b: usize, pub c: usize, pub d: usize, pub e: usize, pub f: usize, } pub union Union { pub a: usize, pub b: usize, pub c: usize, } pub struct PrivStruct { a: usize, b: usize, } pub enum Enum { A, B, C, D { a: u8, b: u8 } } pub enum LargeEnum { A, B, C, D, E, F, G, H, I, J } pub trait Trait { type A; #[must_use] fn foo(); fn bar(); } pub trait GinormousTrait { type A; type B; type C; type D; type E; type F; const N: usize = 1; #[must_use] fn foo(); fn bar(); } pub trait HugeTrait { type A; const M: usize = 1; const N: usize = 1; const O: usize = 1; const P: usize = 1; const Q: usize = 1; #[must_use] fn foo(); fn bar(); } pub trait BigTrait { type A; #[must_use] fn foo(); fn bar(); fn baz(); fn quux(); fn frob(); fn greeble(); } #[macro_export] macro_rules! foo { (a) => {a}; } ``` </details> Fixes #82114
2 parents d4bc912 + 55b2944 commit a5c68d7

File tree

11 files changed

+347
-154
lines changed

11 files changed

+347
-154
lines changed

src/librustdoc/html/render/mod.rs

+26-38
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ use std::path::PathBuf;
4343
use std::str;
4444
use std::string::ToString;
4545

46-
use itertools::Itertools;
4746
use rustc_ast_pretty::pprust;
4847
use rustc_attr::{Deprecation, StabilityLevel};
4948
use rustc_data_structures::fx::FxHashSet;
@@ -486,18 +485,7 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<Strin
486485
],
487486
)
488487
.into(),
489-
(
490-
"Auto-hide item declarations",
491-
vec![
492-
("auto-hide-struct", "Auto-hide structs declaration", true),
493-
("auto-hide-enum", "Auto-hide enums declaration", false),
494-
("auto-hide-union", "Auto-hide unions declaration", true),
495-
("auto-hide-trait", "Auto-hide traits declaration", true),
496-
("auto-hide-macro", "Auto-hide macros declaration", false),
497-
],
498-
)
499-
.into(),
500-
("auto-hide-attributes", "Auto-hide item attributes.", true).into(),
488+
("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
501489
("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
502490
("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", true)
503491
.into(),
@@ -947,19 +935,21 @@ fn render_assoc_item(
947935
+ name.as_str().len()
948936
+ generics_len;
949937

950-
let (indent, end_newline) = if parent == ItemType::Trait {
938+
let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
951939
header_len += 4;
952-
(4, false)
940+
let indent_str = " ";
941+
render_attributes_in_pre(w, meth, indent_str);
942+
(4, indent_str, false)
953943
} else {
954-
(0, true)
944+
render_attributes_in_code(w, meth);
945+
(0, "", true)
955946
};
956-
render_attributes(w, meth, false);
957947
w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
958948
write!(
959949
w,
960950
"{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
961951
{generics}{decl}{notable_traits}{where_clause}",
962-
if parent == ItemType::Trait { " " } else { "" },
952+
indent_str,
963953
vis,
964954
constness,
965955
asyncness,
@@ -1015,35 +1005,33 @@ const ALLOWED_ATTRIBUTES: &[Symbol] = &[
10151005
sym::non_exhaustive,
10161006
];
10171007

1018-
// The `top` parameter is used when generating the item declaration to ensure it doesn't have a
1019-
// left padding. For example:
1020-
//
1021-
// #[foo] <----- "top" attribute
1022-
// struct Foo {
1023-
// #[bar] <---- not "top" attribute
1024-
// bar: usize,
1025-
// }
1026-
fn render_attributes(w: &mut Buffer, it: &clean::Item, top: bool) {
1027-
let attrs = it
1028-
.attrs
1008+
fn attributes(it: &clean::Item) -> Vec<String> {
1009+
it.attrs
10291010
.other_attrs
10301011
.iter()
10311012
.filter_map(|attr| {
10321013
if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
1033-
Some(pprust::attribute_to_string(&attr))
1014+
Some(pprust::attribute_to_string(&attr).replace("\n", "").replace(" ", " "))
10341015
} else {
10351016
None
10361017
}
10371018
})
1038-
.join("\n");
1019+
.collect()
1020+
}
10391021

1040-
if !attrs.is_empty() {
1041-
write!(
1042-
w,
1043-
"<span class=\"docblock attributes{}\">{}</span>",
1044-
if top { " top-attr" } else { "" },
1045-
&attrs
1046-
);
1022+
// When an attribute is rendered inside a `<pre>` tag, it is formatted using
1023+
// a whitespace prefix and newline.
1024+
fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
1025+
for a in attributes(it) {
1026+
write!(w, "{}{}\n", prefix, a);
1027+
}
1028+
}
1029+
1030+
// When an attribute is rendered inside a <code> tag, it is formatted using
1031+
// a div to produce a newline after it.
1032+
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
1033+
for a in attributes(it) {
1034+
write!(w, "<div class=\"code-attribute\">{}</div>", a);
10471035
}
10481036
}
10491037

src/librustdoc/html/render/print_item.rs

+83-16
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use rustc_span::symbol::{kw, sym, Symbol};
1111

1212
use super::{
1313
collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_strs, notable_traits_decl,
14-
render_assoc_item, render_assoc_items, render_attributes, render_impl,
15-
render_stability_since_raw, write_srclink, AssocItemLink, Context,
14+
render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre,
15+
render_impl, render_stability_since_raw, write_srclink, AssocItemLink, Context,
1616
};
1717
use crate::clean::{self, GetDefId};
1818
use crate::formats::cache::Cache;
@@ -131,6 +131,26 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer)
131131
}
132132
}
133133

134+
/// For large structs, enums, unions, etc, determine whether to hide their fields
135+
fn should_hide_fields(n_fields: usize) -> bool {
136+
n_fields > 12
137+
}
138+
139+
fn toggle_open(w: &mut Buffer, text: &str) {
140+
write!(
141+
w,
142+
"<details class=\"rustdoc-toggle type-contents-toggle\">\
143+
<summary class=\"hideme\">\
144+
<span>Show {}</span>\
145+
</summary>",
146+
text
147+
);
148+
}
149+
150+
fn toggle_close(w: &mut Buffer) {
151+
w.write_str("</details>");
152+
}
153+
134154
fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) {
135155
document(w, cx, item, None);
136156

@@ -377,7 +397,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
377397
)
378398
.len();
379399
w.write_str("<pre class=\"rust fn\">");
380-
render_attributes(w, it, false);
400+
render_attributes_in_pre(w, it, "");
381401
write!(
382402
w,
383403
"{vis}{constness}{asyncness}{unsafety}{abi}fn \
@@ -406,7 +426,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
406426
// Output the trait definition
407427
wrap_into_docblock(w, |w| {
408428
w.write_str("<pre class=\"rust trait\">");
409-
render_attributes(w, it, true);
429+
render_attributes_in_pre(w, it, "");
410430
write!(
411431
w,
412432
"{}{}{}trait {}{}{}",
@@ -429,17 +449,36 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
429449
} else {
430450
// FIXME: we should be using a derived_id for the Anchors here
431451
w.write_str("{\n");
452+
let mut toggle = false;
453+
454+
// If there are too many associated types, hide _everything_
455+
if should_hide_fields(types.len()) {
456+
toggle = true;
457+
toggle_open(w, "associated items");
458+
}
432459
for t in &types {
433460
render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
434461
w.write_str(";\n");
435462
}
463+
// If there are too many associated constants, hide everything after them
464+
// We also do this if the types + consts is large because otherwise we could
465+
// render a bunch of types and _then_ a bunch of consts just because both were
466+
// _just_ under the limit
467+
if !toggle && should_hide_fields(types.len() + consts.len()) {
468+
toggle = true;
469+
toggle_open(w, "associated constants and methods");
470+
}
436471
if !types.is_empty() && !consts.is_empty() {
437472
w.write_str("\n");
438473
}
439474
for t in &consts {
440475
render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
441476
w.write_str(";\n");
442477
}
478+
if !toggle && should_hide_fields(required.len() + provided.len()) {
479+
toggle = true;
480+
toggle_open(w, "methods");
481+
}
443482
if !consts.is_empty() && !required.is_empty() {
444483
w.write_str("\n");
445484
}
@@ -470,6 +509,9 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
470509
w.write_str("<div class=\"item-spacer\"></div>");
471510
}
472511
}
512+
if toggle {
513+
toggle_close(w);
514+
}
473515
w.write_str("}");
474516
}
475517
w.write_str("</pre>")
@@ -693,7 +735,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
693735

694736
fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
695737
w.write_str("<pre class=\"rust trait-alias\">");
696-
render_attributes(w, it, false);
738+
render_attributes_in_pre(w, it, "");
697739
write!(
698740
w,
699741
"trait {}{}{} = {};</pre>",
@@ -714,7 +756,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
714756

715757
fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
716758
w.write_str("<pre class=\"rust opaque\">");
717-
render_attributes(w, it, false);
759+
render_attributes_in_pre(w, it, "");
718760
write!(
719761
w,
720762
"type {}{}{where_clause} = impl {bounds};</pre>",
@@ -735,7 +777,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
735777

736778
fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
737779
w.write_str("<pre class=\"rust typedef\">");
738-
render_attributes(w, it, false);
780+
render_attributes_in_pre(w, it, "");
739781
write!(
740782
w,
741783
"type {}{}{where_clause} = {type_};</pre>",
@@ -757,7 +799,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::T
757799
fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
758800
wrap_into_docblock(w, |w| {
759801
w.write_str("<pre class=\"rust union\">");
760-
render_attributes(w, it, true);
802+
render_attributes_in_pre(w, it, "");
761803
render_union(w, it, Some(&s.generics), &s.fields, "", true, cx);
762804
w.write_str("</pre>")
763805
});
@@ -803,7 +845,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
803845
fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
804846
wrap_into_docblock(w, |w| {
805847
w.write_str("<pre class=\"rust enum\">");
806-
render_attributes(w, it, true);
848+
render_attributes_in_pre(w, it, "");
807849
write!(
808850
w,
809851
"{}enum {}{}{}",
@@ -816,6 +858,10 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
816858
w.write_str(" {}");
817859
} else {
818860
w.write_str(" {\n");
861+
let toggle = should_hide_fields(e.variants.len());
862+
if toggle {
863+
toggle_open(w, "variants");
864+
}
819865
for v in &e.variants {
820866
w.write_str(" ");
821867
let name = v.name.as_ref().unwrap();
@@ -844,6 +890,9 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
844890
if e.variants_stripped {
845891
w.write_str(" // some variants omitted\n");
846892
}
893+
if toggle {
894+
toggle_close(w);
895+
}
847896
w.write_str("}");
848897
}
849898
w.write_str("</pre>")
@@ -976,7 +1025,7 @@ fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
9761025

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

9811030
write!(
9821031
w,
@@ -1015,7 +1064,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::
10151064
fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
10161065
wrap_into_docblock(w, |w| {
10171066
w.write_str("<pre class=\"rust struct\">");
1018-
render_attributes(w, it, true);
1067+
render_attributes_in_code(w, it);
10191068
render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true, cx);
10201069
w.write_str("</pre>")
10211070
});
@@ -1064,7 +1113,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
10641113

10651114
fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
10661115
w.write_str("<pre class=\"rust static\">");
1067-
render_attributes(w, it, false);
1116+
render_attributes_in_code(w, it);
10681117
write!(
10691118
w,
10701119
"{vis}static {mutability}{name}: {typ}</pre>",
@@ -1078,7 +1127,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
10781127

10791128
fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
10801129
w.write_str("<pre class=\"rust foreigntype\">extern {\n");
1081-
render_attributes(w, it, false);
1130+
render_attributes_in_code(w, it);
10821131
write!(
10831132
w,
10841133
" {}type {};\n}}</pre>",
@@ -1171,7 +1220,7 @@ fn wrap_into_docblock<F>(w: &mut Buffer, f: F)
11711220
where
11721221
F: FnOnce(&mut Buffer),
11731222
{
1174-
w.write_str("<div class=\"docblock type-decl hidden-by-usual-hider\">");
1223+
w.write_str("<div class=\"docblock type-decl\">");
11751224
f(w);
11761225
w.write_str("</div>")
11771226
}
@@ -1261,6 +1310,13 @@ fn render_union(
12611310
}
12621311

12631312
write!(w, " {{\n{}", tab);
1313+
let count_fields =
1314+
fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
1315+
let toggle = should_hide_fields(count_fields);
1316+
if toggle {
1317+
toggle_open(w, "fields");
1318+
}
1319+
12641320
for field in fields {
12651321
if let clean::StructFieldItem(ref ty) = *field.kind {
12661322
write!(
@@ -1277,6 +1333,9 @@ fn render_union(
12771333
if it.has_stripped_fields().unwrap() {
12781334
write!(w, " // some fields omitted\n{}", tab);
12791335
}
1336+
if toggle {
1337+
toggle_close(w);
1338+
}
12801339
w.write_str("}");
12811340
}
12821341

@@ -1305,8 +1364,14 @@ fn render_struct(
13051364
if let Some(g) = g {
13061365
write!(w, "{}", print_where_clause(g, cx.cache(), cx.tcx(), 0, true),)
13071366
}
1308-
let mut has_visible_fields = false;
13091367
w.write_str(" {");
1368+
let count_fields =
1369+
fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
1370+
let has_visible_fields = count_fields > 0;
1371+
let toggle = should_hide_fields(count_fields);
1372+
if toggle {
1373+
toggle_open(w, "fields");
1374+
}
13101375
for field in fields {
13111376
if let clean::StructFieldItem(ref ty) = *field.kind {
13121377
write!(
@@ -1317,7 +1382,6 @@ fn render_struct(
13171382
field.name.as_ref().unwrap(),
13181383
ty.print(cx.cache(), cx.tcx()),
13191384
);
1320-
has_visible_fields = true;
13211385
}
13221386
}
13231387

@@ -1331,6 +1395,9 @@ fn render_struct(
13311395
// `{ /* fields omitted */ }` to save space.
13321396
write!(w, " /* fields omitted */ ");
13331397
}
1398+
if toggle {
1399+
toggle_close(w);
1400+
}
13341401
w.write_str("}");
13351402
}
13361403
CtorKind::Fn => {

0 commit comments

Comments
 (0)