Skip to content

Commit 898e56b

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 1086aff commit 898e56b

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, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, Parser, Tag,
@@ -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,
@@ -534,9 +535,9 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
534535
let id = self.id_map.derive(id);
535536

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

@@ -1399,10 +1400,23 @@ impl Markdown<'_> {
13991400
}
14001401

14011402
impl MarkdownWithToc<'_> {
1402-
pub(crate) fn into_string(self) -> String {
1403-
let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self;
1403+
pub(crate) fn into_parts(self) -> (Toc, String) {
1404+
let MarkdownWithToc { content: md, links, ids, error_codes: codes, edition, playground } =
1405+
self;
14041406

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

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

@@ -1416,7 +1430,11 @@ impl MarkdownWithToc<'_> {
14161430
html::push_html(&mut s, p);
14171431
}
14181432

1419-
format!("<nav id=\"TOC\">{toc}</nav>{s}", toc = toc.into_toc().print())
1433+
(toc.into_toc(), s)
1434+
}
1435+
pub(crate) fn into_string(self) -> String {
1436+
let (toc, s) = self.into_parts();
1437+
format!("<nav id=\"TOC\">{toc}</nav>{s}", toc = toc.print())
14201438
}
14211439
}
14221440

@@ -1595,7 +1613,16 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
15951613

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

1598-
for event in p {
1616+
plain_text_from_events(p, &mut s);
1617+
1618+
s
1619+
}
1620+
1621+
pub(crate) fn plain_text_from_events<'a>(
1622+
events: impl Iterator<Item = pulldown_cmark::Event<'a>>,
1623+
s: &mut String,
1624+
) {
1625+
for event in events {
15991626
match &event {
16001627
Event::Text(text) => s.push_str(text),
16011628
Event::Code(code) => {
@@ -1610,8 +1637,6 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
16101637
_ => (),
16111638
}
16121639
}
1613-
1614-
s
16151640
}
16161641

16171642
#[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)