Skip to content

Commit 1aebff9

Browse files
committed
Add Top TOC support to rustdoc
This commit adds the headers for the top level documentation to rustdoc's existing table of contents, along with associated items. It only show two levels of headers. Going further would require the sidebar to be wider, and that seems unnecessary (the crates that have manually-built TOCs usually don't need deeply nested headers).
1 parent 5aea140 commit 1aebff9

15 files changed

+267
-129
lines changed

src/librustdoc/clean/types.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,6 @@ impl Item {
506506
pub(crate) fn is_mod(&self) -> bool {
507507
self.type_() == ItemType::Module
508508
}
509-
pub(crate) fn is_trait(&self) -> bool {
510-
self.type_() == ItemType::Trait
511-
}
512509
pub(crate) fn is_struct(&self) -> bool {
513510
self.type_() == ItemType::Struct
514511
}
@@ -536,9 +533,6 @@ impl Item {
536533
pub(crate) fn is_ty_method(&self) -> bool {
537534
self.type_() == ItemType::TyMethod
538535
}
539-
pub(crate) fn is_type_alias(&self) -> bool {
540-
self.type_() == ItemType::TypeAlias
541-
}
542536
pub(crate) fn is_primitive(&self) -> bool {
543537
self.type_() == ItemType::Primitive
544538
}

src/librustdoc/html/markdown.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use crate::html::format::Buffer;
5555
use crate::html::highlight;
5656
use crate::html::length_limit::HtmlWithLimit;
5757
use crate::html::render::small_url_encode;
58-
use crate::html::toc::TocBuilder;
58+
use crate::html::toc::{Toc, TocBuilder};
5959

6060
#[cfg(test)]
6161
mod tests;
@@ -101,6 +101,7 @@ pub struct Markdown<'a> {
101101
/// A struct like `Markdown` that renders the markdown with a table of contents.
102102
pub(crate) struct MarkdownWithToc<'a> {
103103
pub(crate) content: &'a str,
104+
pub(crate) links: &'a [RenderedLink],
104105
pub(crate) ids: &'a mut IdMap,
105106
pub(crate) error_codes: ErrorCodes,
106107
pub(crate) edition: Edition,
@@ -532,9 +533,9 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
532533
let id = self.id_map.derive(id);
533534

534535
if let Some(ref mut builder) = self.toc {
535-
let mut html_header = String::new();
536-
html::push_html(&mut html_header, self.buf.iter().map(|(ev, _)| ev.clone()));
537-
let sec = builder.push(level as u32, html_header, id.clone());
536+
let mut text_header = String::new();
537+
plain_text_from_events(self.buf.iter().map(|(ev, _)| ev.clone()), &mut text_header);
538+
let sec = builder.push(level as u32, text_header, id.clone());
538539
self.buf.push_front((Event::Html(format!("{sec} ").into()), 0..0));
539540
}
540541

@@ -1415,10 +1416,23 @@ impl Markdown<'_> {
14151416
}
14161417

14171418
impl MarkdownWithToc<'_> {
1418-
pub(crate) fn into_string(self) -> String {
1419-
let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self;
1419+
pub(crate) fn into_parts(self) -> (Toc, String) {
1420+
let MarkdownWithToc { content: md, links, ids, error_codes: codes, edition, playground } =
1421+
self;
14201422

1421-
let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
1423+
// This is actually common enough to special-case
1424+
if md.is_empty() {
1425+
return (Toc { entries: Vec::new() }, String::new());
1426+
}
1427+
let mut replacer = |broken_link: BrokenLink<'_>| {
1428+
links
1429+
.iter()
1430+
.find(|link| &*link.original_text == &*broken_link.reference)
1431+
.map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
1432+
};
1433+
1434+
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
1435+
let p = p.into_offset_iter();
14221436

14231437
let mut s = String::with_capacity(md.len() * 3 / 2);
14241438

@@ -1432,7 +1446,11 @@ impl MarkdownWithToc<'_> {
14321446
html::push_html(&mut s, p);
14331447
}
14341448

1435-
format!("<nav id=\"TOC\">{toc}</nav>{s}", toc = toc.into_toc().print())
1449+
(toc.into_toc(), s)
1450+
}
1451+
pub(crate) fn into_string(self) -> String {
1452+
let (toc, s) = self.into_parts();
1453+
format!("<nav id=\"TOC\">{toc}</nav>{s}", toc = toc.print())
14361454
}
14371455
}
14381456

@@ -1611,7 +1629,16 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
16111629

16121630
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
16131631

1614-
for event in p {
1632+
plain_text_from_events(p, &mut s);
1633+
1634+
s
1635+
}
1636+
1637+
pub(crate) fn plain_text_from_events<'a>(
1638+
events: impl Iterator<Item = pulldown_cmark::Event<'a>>,
1639+
s: &mut String,
1640+
) {
1641+
for event in events {
16151642
match &event {
16161643
Event::Text(text) => s.push_str(text),
16171644
Event::Code(code) => {
@@ -1626,8 +1653,6 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
16261653
_ => (),
16271654
}
16281655
}
1629-
1630-
s
16311656
}
16321657

16331658
#[derive(Debug)]

src/librustdoc/html/render/context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
616616
let all = shared.all.replace(AllTypes::new());
617617
let mut sidebar = Buffer::html();
618618

619-
let blocks = sidebar_module_like(all.item_sections());
619+
// all.html is not customizable, so a blank id map is fine
620+
let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new());
620621
let bar = Sidebar {
621622
title_prefix: "",
622623
title: "",

0 commit comments

Comments
 (0)