Skip to content

Commit f862bd8

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 5753b30 commit f862bd8

15 files changed

+262
-123
lines changed

src/librustdoc/clean/types.rs

-6
Original file line numberDiff line numberDiff line change
@@ -511,9 +511,6 @@ impl Item {
511511
pub(crate) fn is_mod(&self) -> bool {
512512
self.type_() == ItemType::Module
513513
}
514-
pub(crate) fn is_trait(&self) -> bool {
515-
self.type_() == ItemType::Trait
516-
}
517514
pub(crate) fn is_struct(&self) -> bool {
518515
self.type_() == ItemType::Struct
519516
}
@@ -541,9 +538,6 @@ impl Item {
541538
pub(crate) fn is_ty_method(&self) -> bool {
542539
self.type_() == ItemType::TyMethod
543540
}
544-
pub(crate) fn is_type_alias(&self) -> bool {
545-
self.type_() == ItemType::TypeAlias
546-
}
547541
pub(crate) fn is_primitive(&self) -> bool {
548542
self.type_() == ItemType::Primitive
549543
}

src/librustdoc/html/markdown.rs

+36-11
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use crate::html::format::Buffer;
5151
use crate::html::highlight;
5252
use crate::html::length_limit::HtmlWithLimit;
5353
use crate::html::render::small_url_encode;
54-
use crate::html::toc::TocBuilder;
54+
use crate::html::toc::{Toc, TocBuilder};
5555

5656
use pulldown_cmark::{
5757
html, BrokenLink, BrokenLinkCallback, CodeBlockKind, CowStr, Event, LinkType, OffsetIter,
@@ -102,6 +102,7 @@ pub struct Markdown<'a> {
102102
/// A struct like `Markdown` that renders the markdown with a table of contents.
103103
pub(crate) struct MarkdownWithToc<'a> {
104104
pub(crate) content: &'a str,
105+
pub(crate) links: &'a [RenderedLink],
105106
pub(crate) ids: &'a mut IdMap,
106107
pub(crate) error_codes: ErrorCodes,
107108
pub(crate) edition: Edition,
@@ -531,9 +532,9 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
531532
let id = self.id_map.derive(id);
532533

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

@@ -1396,10 +1397,23 @@ impl Markdown<'_> {
13961397
}
13971398

13981399
impl MarkdownWithToc<'_> {
1399-
pub(crate) fn into_string(self) -> String {
1400-
let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self;
1400+
pub(crate) fn into_parts(self) -> (Toc, String) {
1401+
let MarkdownWithToc { content: md, links, ids, error_codes: codes, edition, playground } =
1402+
self;
14011403

1402-
let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
1404+
// This is actually common enough to special-case
1405+
if md.is_empty() {
1406+
return (Toc { entries: Vec::new() }, String::new());
1407+
}
1408+
let mut replacer = |broken_link: BrokenLink<'_>| {
1409+
links
1410+
.iter()
1411+
.find(|link| &*link.original_text == &*broken_link.reference)
1412+
.map(|link| (link.href.as_str().into(), link.tooltip.as_str().into()))
1413+
};
1414+
1415+
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
1416+
let p = p.into_offset_iter();
14031417

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

@@ -1413,7 +1427,11 @@ impl MarkdownWithToc<'_> {
14131427
html::push_html(&mut s, p);
14141428
}
14151429

1416-
format!("<nav id=\"TOC\">{toc}</nav>{s}", toc = toc.into_toc().print())
1430+
(toc.into_toc(), s)
1431+
}
1432+
pub(crate) fn into_string(self) -> String {
1433+
let (toc, s) = self.into_parts();
1434+
format!("<nav id=\"TOC\">{toc}</nav>{s}", toc = toc.print())
14171435
}
14181436
}
14191437

@@ -1592,7 +1610,16 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
15921610

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

1595-
for event in p {
1613+
plain_text_from_events(p, &mut s);
1614+
1615+
s
1616+
}
1617+
1618+
pub(crate) fn plain_text_from_events<'a>(
1619+
events: impl Iterator<Item = pulldown_cmark::Event<'a>>,
1620+
s: &mut String,
1621+
) {
1622+
for event in events {
15961623
match &event {
15971624
Event::Text(text) => s.push_str(text),
15981625
Event::Code(code) => {
@@ -1607,8 +1634,6 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
16071634
_ => (),
16081635
}
16091636
}
1610-
1611-
s
16121637
}
16131638

16141639
#[derive(Debug)]

src/librustdoc/html/render/context.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
626626
let all = shared.all.replace(AllTypes::new());
627627
let mut sidebar = Buffer::html();
628628

629-
let blocks = sidebar_module_like(all.item_sections());
629+
// all.html is not customizable, so a blank id map is fine
630+
let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new());
630631
let bar = Sidebar {
631632
title_prefix: "",
632633
title: "",

0 commit comments

Comments
 (0)