Skip to content

Commit 27bfbd5

Browse files
QuietMisdreavusQuietMisdreavus
QuietMisdreavus
authored andcommitted
rustdoc: add a list of headings to the sidebar
1 parent 2c48ae6 commit 27bfbd5

File tree

2 files changed

+225
-4
lines changed

2 files changed

+225
-4
lines changed

src/librustdoc/clean/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ impl Item {
292292
self.type_() == ItemType::Struct
293293
}
294294
pub fn is_enum(&self) -> bool {
295-
self.type_() == ItemType::Module
295+
self.type_() == ItemType::Enum
296296
}
297297
pub fn is_fn(&self) -> bool {
298298
self.type_() == ItemType::Function
@@ -312,6 +312,9 @@ impl Item {
312312
pub fn is_primitive(&self) -> bool {
313313
self.type_() == ItemType::Primitive
314314
}
315+
pub fn is_union(&self) -> bool {
316+
self.type_() == ItemType::Union
317+
}
315318
pub fn is_stripped(&self) -> bool {
316319
match self.inner { StrippedItem(..) => true, _ => false }
317320
}

src/librustdoc/html/render.rs

+221-3
Original file line numberDiff line numberDiff line change
@@ -2411,7 +2411,7 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
24112411
}).peekable();
24122412
if let doctree::Plain = s.struct_type {
24132413
if fields.peek().is_some() {
2414-
write!(w, "<h2 class='fields'>Fields</h2>")?;
2414+
write!(w, "<h2 id='fields' class='fields'>Fields</h2>")?;
24152415
for (field, ty) in fields {
24162416
let id = derive_id(format!("{}.{}",
24172417
ItemType::StructField,
@@ -2459,7 +2459,7 @@ fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
24592459
}
24602460
}).peekable();
24612461
if fields.peek().is_some() {
2462-
write!(w, "<h2 class='fields'>Fields</h2>")?;
2462+
write!(w, "<h2 id='fields' class='fields'>Fields</h2>")?;
24632463
for (field, ty) in fields {
24642464
write!(w, "<span id='{shortty}.{name}' class=\"{shortty}\"><code>{name}: {ty}</code>
24652465
</span>",
@@ -2535,7 +2535,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
25352535

25362536
document(w, cx, it)?;
25372537
if !e.variants.is_empty() {
2538-
write!(w, "<h2 class='variants'>Variants</h2>\n")?;
2538+
write!(w, "<h2 id='variants' class='variants'>Variants</h2>\n")?;
25392539
for variant in &e.variants {
25402540
let id = derive_id(format!("{}.{}",
25412541
ItemType::Variant,
@@ -3077,6 +3077,37 @@ impl<'a> fmt::Display for Sidebar<'a> {
30773077
let it = self.item;
30783078
let parentlen = cx.current.len() - if it.is_mod() {1} else {0};
30793079

3080+
if it.is_struct() || it.is_trait() || it.is_primitive() || it.is_union()
3081+
|| it.is_enum() || it.is_mod()
3082+
{
3083+
write!(fmt, "<p class='location'>")?;
3084+
match it.inner {
3085+
clean::StructItem(..) => write!(fmt, "Struct ")?,
3086+
clean::TraitItem(..) => write!(fmt, "Trait ")?,
3087+
clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
3088+
clean::UnionItem(..) => write!(fmt, "Union ")?,
3089+
clean::EnumItem(..) => write!(fmt, "Enum ")?,
3090+
clean::ModuleItem(..) => if it.is_crate() {
3091+
write!(fmt, "Crate ")?;
3092+
} else {
3093+
write!(fmt, "Module ")?;
3094+
},
3095+
_ => (),
3096+
}
3097+
write!(fmt, "{}", it.name.as_ref().unwrap())?;
3098+
write!(fmt, "</p>")?;
3099+
3100+
match it.inner {
3101+
clean::StructItem(ref s) => sidebar_struct(fmt, it, s)?,
3102+
clean::TraitItem(ref t) => sidebar_trait(fmt, it, t)?,
3103+
clean::PrimitiveItem(ref p) => sidebar_primitive(fmt, it, p)?,
3104+
clean::UnionItem(ref u) => sidebar_union(fmt, it, u)?,
3105+
clean::EnumItem(ref e) => sidebar_enum(fmt, it, e)?,
3106+
clean::ModuleItem(ref m) => sidebar_module(fmt, it, &m.items)?,
3107+
_ => (),
3108+
}
3109+
}
3110+
30803111
// The sidebar is designed to display sibling functions, modules and
30813112
// other miscellaneous information. since there are lots of sibling
30823113
// items (and that causes quadratic growth in large modules),
@@ -3119,6 +3150,193 @@ impl<'a> fmt::Display for Sidebar<'a> {
31193150
}
31203151
}
31213152

3153+
fn sidebar_assoc_items(it: &clean::Item) -> String {
3154+
let mut out = String::new();
3155+
let c = cache();
3156+
if let Some(v) = c.impls.get(&it.def_id) {
3157+
if v.iter().any(|i| i.inner_impl().trait_.is_none()) {
3158+
out.push_str("<li><a href=\"#methods\">Methods</a></li>");
3159+
}
3160+
3161+
if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
3162+
if let Some(impl_) = v.iter()
3163+
.filter(|i| i.inner_impl().trait_.is_some())
3164+
.find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did) {
3165+
if let Some(target) = impl_.inner_impl().items.iter().filter_map(|item| {
3166+
match item.inner {
3167+
clean::TypedefItem(ref t, true) => Some(&t.type_),
3168+
_ => None,
3169+
}
3170+
}).next() {
3171+
let inner_impl = target.def_id().or(target.primitive_type().and_then(|prim| {
3172+
c.primitive_locations.get(&prim).cloned()
3173+
})).and_then(|did| c.impls.get(&did));
3174+
if inner_impl.is_some() {
3175+
out.push_str("<li><a href=\"#deref-methods\">");
3176+
out.push_str(&format!("Methods from {:#}&lt;Target={:#}&gt;",
3177+
impl_.inner_impl().trait_.as_ref().unwrap(),
3178+
target));
3179+
out.push_str("</a></li>");
3180+
}
3181+
}
3182+
}
3183+
out.push_str("<li><a href=\"#implementations\">Trait Implementations</a></li>");
3184+
}
3185+
}
3186+
3187+
out
3188+
}
3189+
3190+
fn sidebar_struct(fmt: &mut fmt::Formatter, it: &clean::Item,
3191+
s: &clean::Struct) -> fmt::Result {
3192+
let mut sidebar = String::new();
3193+
3194+
if s.fields.iter()
3195+
.any(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) {
3196+
if let doctree::Plain = s.struct_type {
3197+
sidebar.push_str("<li><a href=\"#fields\">Fields</a></li>");
3198+
}
3199+
}
3200+
3201+
sidebar.push_str(&sidebar_assoc_items(it));
3202+
3203+
if !sidebar.is_empty() {
3204+
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
3205+
}
3206+
Ok(())
3207+
}
3208+
3209+
fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item,
3210+
t: &clean::Trait) -> fmt::Result {
3211+
let mut sidebar = String::new();
3212+
3213+
let has_types = t.items.iter().any(|m| m.is_associated_type());
3214+
let has_consts = t.items.iter().any(|m| m.is_associated_const());
3215+
let has_required = t.items.iter().any(|m| m.is_ty_method());
3216+
let has_provided = t.items.iter().any(|m| m.is_method());
3217+
3218+
if has_types {
3219+
sidebar.push_str("<li><a href=\"#associated-types\">Associated Types</a></li>");
3220+
}
3221+
if has_consts {
3222+
sidebar.push_str("<li><a href=\"#associated-const\">Associated Constants</a></li>");
3223+
}
3224+
if has_required {
3225+
sidebar.push_str("<li><a href=\"#required-methods\">Required Methods</a></li>");
3226+
}
3227+
if has_provided {
3228+
sidebar.push_str("<li><a href=\"#provided-methods\">Provided Methods</a></li>");
3229+
}
3230+
3231+
sidebar.push_str(&sidebar_assoc_items(it));
3232+
3233+
sidebar.push_str("<li><a href=\"#implementors\">Implementors</a></li>");
3234+
3235+
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)
3236+
}
3237+
3238+
fn sidebar_primitive(fmt: &mut fmt::Formatter, it: &clean::Item,
3239+
_p: &clean::PrimitiveType) -> fmt::Result {
3240+
let sidebar = sidebar_assoc_items(it);
3241+
3242+
if !sidebar.is_empty() {
3243+
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
3244+
}
3245+
Ok(())
3246+
}
3247+
3248+
fn sidebar_union(fmt: &mut fmt::Formatter, it: &clean::Item,
3249+
u: &clean::Union) -> fmt::Result {
3250+
let mut sidebar = String::new();
3251+
3252+
if u.fields.iter()
3253+
.any(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) {
3254+
sidebar.push_str("<li><a href=\"#fields\">Fields</a></li>");
3255+
}
3256+
3257+
sidebar.push_str(&sidebar_assoc_items(it));
3258+
3259+
if !sidebar.is_empty() {
3260+
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
3261+
}
3262+
Ok(())
3263+
}
3264+
3265+
fn sidebar_enum(fmt: &mut fmt::Formatter, it: &clean::Item,
3266+
e: &clean::Enum) -> fmt::Result {
3267+
let mut sidebar = String::new();
3268+
3269+
if !e.variants.is_empty() {
3270+
sidebar.push_str("<li><a href=\"#variants\">Variants</a></li>");
3271+
}
3272+
3273+
sidebar.push_str(&sidebar_assoc_items(it));
3274+
3275+
if !sidebar.is_empty() {
3276+
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
3277+
}
3278+
Ok(())
3279+
}
3280+
3281+
fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
3282+
items: &[clean::Item]) -> fmt::Result {
3283+
let mut sidebar = String::new();
3284+
3285+
if items.iter().any(|it| it.type_() == ItemType::ExternCrate ||
3286+
it.type_() == ItemType::Import) {
3287+
sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
3288+
id = "reexports",
3289+
name = "Reexports"));
3290+
}
3291+
3292+
// ordering taken from item_module, reorder, where it prioritized elements in a certain order
3293+
// to print its headings
3294+
for &myty in &[ItemType::Primitive, ItemType::Module, ItemType::Macro, ItemType::Struct,
3295+
ItemType::Enum, ItemType::Constant, ItemType::Static, ItemType::Trait,
3296+
ItemType::Function, ItemType::Typedef, ItemType::Union, ItemType::Impl,
3297+
ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
3298+
ItemType::AssociatedType, ItemType::AssociatedConst] {
3299+
if items.iter().any(|it| {
3300+
if let clean::DefaultImplItem(..) = it.inner {
3301+
false
3302+
} else {
3303+
!maybe_ignore_item(it) && !it.is_stripped() && it.type_() == myty
3304+
}
3305+
}) {
3306+
let (short, name) = match myty {
3307+
ItemType::ExternCrate |
3308+
ItemType::Import => ("reexports", "Reexports"),
3309+
ItemType::Module => ("modules", "Modules"),
3310+
ItemType::Struct => ("structs", "Structs"),
3311+
ItemType::Union => ("unions", "Unions"),
3312+
ItemType::Enum => ("enums", "Enums"),
3313+
ItemType::Function => ("functions", "Functions"),
3314+
ItemType::Typedef => ("types", "Type Definitions"),
3315+
ItemType::Static => ("statics", "Statics"),
3316+
ItemType::Constant => ("constants", "Constants"),
3317+
ItemType::Trait => ("traits", "Traits"),
3318+
ItemType::Impl => ("impls", "Implementations"),
3319+
ItemType::TyMethod => ("tymethods", "Type Methods"),
3320+
ItemType::Method => ("methods", "Methods"),
3321+
ItemType::StructField => ("fields", "Struct Fields"),
3322+
ItemType::Variant => ("variants", "Variants"),
3323+
ItemType::Macro => ("macros", "Macros"),
3324+
ItemType::Primitive => ("primitives", "Primitive Types"),
3325+
ItemType::AssociatedType => ("associated-types", "Associated Types"),
3326+
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
3327+
};
3328+
sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
3329+
id = short,
3330+
name = name));
3331+
}
3332+
}
3333+
3334+
if !sidebar.is_empty() {
3335+
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
3336+
}
3337+
Ok(())
3338+
}
3339+
31223340
impl<'a> fmt::Display for Source<'a> {
31233341
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
31243342
let Source(s) = *self;

0 commit comments

Comments
 (0)