Skip to content

Commit b7984c0

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 99322d8 commit b7984c0

File tree

15 files changed

+267
-129
lines changed

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
@@ -507,9 +507,6 @@ impl Item {
507507
pub(crate) fn is_mod(&self) -> bool {
508508
self.type_() == ItemType::Module
509509
}
510-
pub(crate) fn is_trait(&self) -> bool {
511-
self.type_() == ItemType::Trait
512-
}
513510
pub(crate) fn is_struct(&self) -> bool {
514511
self.type_() == ItemType::Struct
515512
}
@@ -537,9 +534,6 @@ impl Item {
537534
pub(crate) fn is_ty_method(&self) -> bool {
538535
self.type_() == ItemType::TyMethod
539536
}
540-
pub(crate) fn is_type_alias(&self) -> bool {
541-
self.type_() == ItemType::TypeAlias
542-
}
543537
pub(crate) fn is_primitive(&self) -> bool {
544538
self.type_() == ItemType::Primitive
545539
}

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,
@@ -530,9 +531,9 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
530531
let id = self.id_map.derive(id);
531532

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

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

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

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

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

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

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

@@ -1591,7 +1609,16 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
15911609

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

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

16131638
#[derive(Debug)]

src/librustdoc/html/render/context.rs

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

626-
let blocks = sidebar_module_like(all.item_sections());
626+
// all.html is not customizable, so a blank id map is fine
627+
let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new());
627628
let bar = Sidebar {
628629
title_prefix: "",
629630
title: "",

0 commit comments

Comments
 (0)