From 1aebff96ade6518038e0f7522d3304bd0f9bf891 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 6 Feb 2024 10:22:24 -0700 Subject: 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). --- tests/rustdoc/sidebar-all-page.rs | 34 ------------ tests/rustdoc/sidebar-items.rs | 63 ---------------------- tests/rustdoc/sidebar-link-generation.rs | 13 ----- tests/rustdoc/sidebar-links-to-foreign-impl.rs | 16 ------ tests/rustdoc/sidebar/sidebar-all-page.rs | 34 ++++++++++++ tests/rustdoc/sidebar/sidebar-items.rs | 63 ++++++++++++++++++++++ tests/rustdoc/sidebar/sidebar-link-generation.rs | 13 +++++ .../sidebar/sidebar-links-to-foreign-impl.rs | 16 ++++++ tests/rustdoc/sidebar/top-toc-html.rs | 19 +++++++ tests/rustdoc/sidebar/top-toc-idmap.rs | 44 +++++++++++++++ 10 files changed, 189 insertions(+), 126 deletions(-) delete mode 100644 tests/rustdoc/sidebar-all-page.rs delete mode 100644 tests/rustdoc/sidebar-items.rs delete mode 100644 tests/rustdoc/sidebar-link-generation.rs delete mode 100644 tests/rustdoc/sidebar-links-to-foreign-impl.rs create mode 100644 tests/rustdoc/sidebar/sidebar-all-page.rs create mode 100644 tests/rustdoc/sidebar/sidebar-items.rs create mode 100644 tests/rustdoc/sidebar/sidebar-link-generation.rs create mode 100644 tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs create mode 100644 tests/rustdoc/sidebar/top-toc-html.rs create mode 100644 tests/rustdoc/sidebar/top-toc-idmap.rs (limited to 'tests/rustdoc') diff --git a/tests/rustdoc/sidebar-all-page.rs b/tests/rustdoc/sidebar-all-page.rs deleted file mode 100644 index 1f97a414048..00000000000 --- a/tests/rustdoc/sidebar-all-page.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![crate_name = "foo"] -#![feature(rustc_attrs)] - -//@ has 'foo/all.html' -//@ has - '//*[@class="sidebar-elems"]//li' 'Structs' -//@ has - '//*[@class="sidebar-elems"]//li' 'Enums' -//@ has - '//*[@class="sidebar-elems"]//li' 'Unions' -//@ has - '//*[@class="sidebar-elems"]//li' 'Functions' -//@ has - '//*[@class="sidebar-elems"]//li' 'Traits' -//@ has - '//*[@class="sidebar-elems"]//li' 'Macros' -//@ has - '//*[@class="sidebar-elems"]//li' 'Type Aliases' -//@ has - '//*[@class="sidebar-elems"]//li' 'Constants' -//@ has - '//*[@class="sidebar-elems"]//li' 'Statics' -//@ has - '//*[@class="sidebar-elems"]//li' 'Primitive Types' - -pub struct Foo; -pub enum Enum { - A, -} -pub union Bar { - a: u8, - b: u16, -} -pub fn foo() {} -pub trait Trait {} -#[macro_export] -macro_rules! foo { - () => {}; -} -pub type Type = u8; -pub const FOO: u8 = 0; -pub static BAR: u8 = 0; -#[rustc_doc_primitive = "u8"] -mod u8 {} diff --git a/tests/rustdoc/sidebar-items.rs b/tests/rustdoc/sidebar-items.rs deleted file mode 100644 index f3812143a7d..00000000000 --- a/tests/rustdoc/sidebar-items.rs +++ /dev/null @@ -1,63 +0,0 @@ -#![feature(associated_type_defaults)] -#![crate_name = "foo"] - -//@ has foo/trait.Foo.html -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-methods"]' 'Required Methods' -//@ has - '//*[@class="sidebar-elems"]//section//a' 'bar' -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-methods"]' 'Provided Methods' -//@ has - '//*[@class="sidebar-elems"]//section//a' 'foo' -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-associated-consts"]' 'Required Associated Constants' -//@ has - '//*[@class="sidebar-elems"]//section//a' 'FOO' -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-associated-consts"]' 'Provided Associated Constants' -//@ has - '//*[@class="sidebar-elems"]//section//a' 'BAR' -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-associated-types"]' 'Required Associated Types' -//@ has - '//*[@class="sidebar-elems"]//section//a' 'Output' -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-associated-types"]' 'Provided Associated Types' -//@ has - '//*[@class="sidebar-elems"]//section//a' 'Extra' -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#object-safety"]' 'Object Safety' -pub trait Foo { - const FOO: usize; - const BAR: u32 = 0; - type Extra: Copy = (); - type Output: ?Sized; - - fn foo() {} - fn bar() -> Self::Output; -} - -//@ has foo/trait.Safe.html -//@ !has - '//div[@class="sidebar-elems"]//h3/a[@href="#object-safety"]' '' -pub trait Safe { - fn access(&self); -} - -//@ has foo/struct.Bar.html -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#fields"]' 'Fields' -//@ has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f"]' 'f' -//@ has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.u"]' 'u' -//@ !has - '//*[@class="sidebar-elems"]//section//a' 'waza' -pub struct Bar { - pub f: u32, - pub u: u32, - waza: u32, -} - -//@ has foo/enum.En.html -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#variants"]' 'Variants' -//@ has - '//*[@class="sidebar-elems"]//section//a' 'Foo' -//@ has - '//*[@class="sidebar-elems"]//section//a' 'Bar' -pub enum En { - Foo, - Bar, -} - -//@ has foo/union.MyUnion.html -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#fields"]' 'Fields' -//@ has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f1"]' 'f1' -//@ has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f2"]' 'f2' -//@ !has - '//*[@class="sidebar-elems"]//section//a' 'waza' -pub union MyUnion { - pub f1: u32, - pub f2: f32, - waza: u32, -} diff --git a/tests/rustdoc/sidebar-link-generation.rs b/tests/rustdoc/sidebar-link-generation.rs deleted file mode 100644 index ee868ec75d3..00000000000 --- a/tests/rustdoc/sidebar-link-generation.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![crate_name = "foo"] - -//@ has foo/struct.SomeStruct.html '//*[@class="sidebar-elems"]//section//li/a[@href="#method.some_fn-1"]' \ -// "some_fn" -pub struct SomeStruct { _inner: T } - -impl SomeStruct<()> { - pub fn some_fn(&self) {} -} - -impl SomeStruct { - pub fn some_fn(&self) {} -} diff --git a/tests/rustdoc/sidebar-links-to-foreign-impl.rs b/tests/rustdoc/sidebar-links-to-foreign-impl.rs deleted file mode 100644 index 7c039eeb39f..00000000000 --- a/tests/rustdoc/sidebar-links-to-foreign-impl.rs +++ /dev/null @@ -1,16 +0,0 @@ -// issue #56018: "Implementations on Foreign Types" sidebar items should link to specific impls - -#![crate_name = "foo"] - -//@ has foo/trait.Foo.html -//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#foreign-impls"]' 'Implementations on Foreign Types' -//@ has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types' -//@ has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32' -//@ has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header"]' 'impl Foo for u32' -//@ has - "//*[@class=\"sidebar-elems\"]//section//a[@href=\"#impl-Foo-for-%26str\"]" "&'a str" -//@ has - "//*[@id=\"impl-Foo-for-%26str\"]//h3[@class=\"code-header\"]" "impl<'a> Foo for &'a str" -pub trait Foo {} - -impl Foo for u32 {} - -impl<'a> Foo for &'a str {} diff --git a/tests/rustdoc/sidebar/sidebar-all-page.rs b/tests/rustdoc/sidebar/sidebar-all-page.rs new file mode 100644 index 00000000000..1f97a414048 --- /dev/null +++ b/tests/rustdoc/sidebar/sidebar-all-page.rs @@ -0,0 +1,34 @@ +#![crate_name = "foo"] +#![feature(rustc_attrs)] + +//@ has 'foo/all.html' +//@ has - '//*[@class="sidebar-elems"]//li' 'Structs' +//@ has - '//*[@class="sidebar-elems"]//li' 'Enums' +//@ has - '//*[@class="sidebar-elems"]//li' 'Unions' +//@ has - '//*[@class="sidebar-elems"]//li' 'Functions' +//@ has - '//*[@class="sidebar-elems"]//li' 'Traits' +//@ has - '//*[@class="sidebar-elems"]//li' 'Macros' +//@ has - '//*[@class="sidebar-elems"]//li' 'Type Aliases' +//@ has - '//*[@class="sidebar-elems"]//li' 'Constants' +//@ has - '//*[@class="sidebar-elems"]//li' 'Statics' +//@ has - '//*[@class="sidebar-elems"]//li' 'Primitive Types' + +pub struct Foo; +pub enum Enum { + A, +} +pub union Bar { + a: u8, + b: u16, +} +pub fn foo() {} +pub trait Trait {} +#[macro_export] +macro_rules! foo { + () => {}; +} +pub type Type = u8; +pub const FOO: u8 = 0; +pub static BAR: u8 = 0; +#[rustc_doc_primitive = "u8"] +mod u8 {} diff --git a/tests/rustdoc/sidebar/sidebar-items.rs b/tests/rustdoc/sidebar/sidebar-items.rs new file mode 100644 index 00000000000..f3812143a7d --- /dev/null +++ b/tests/rustdoc/sidebar/sidebar-items.rs @@ -0,0 +1,63 @@ +#![feature(associated_type_defaults)] +#![crate_name = "foo"] + +//@ has foo/trait.Foo.html +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-methods"]' 'Required Methods' +//@ has - '//*[@class="sidebar-elems"]//section//a' 'bar' +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-methods"]' 'Provided Methods' +//@ has - '//*[@class="sidebar-elems"]//section//a' 'foo' +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-associated-consts"]' 'Required Associated Constants' +//@ has - '//*[@class="sidebar-elems"]//section//a' 'FOO' +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-associated-consts"]' 'Provided Associated Constants' +//@ has - '//*[@class="sidebar-elems"]//section//a' 'BAR' +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-associated-types"]' 'Required Associated Types' +//@ has - '//*[@class="sidebar-elems"]//section//a' 'Output' +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-associated-types"]' 'Provided Associated Types' +//@ has - '//*[@class="sidebar-elems"]//section//a' 'Extra' +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#object-safety"]' 'Object Safety' +pub trait Foo { + const FOO: usize; + const BAR: u32 = 0; + type Extra: Copy = (); + type Output: ?Sized; + + fn foo() {} + fn bar() -> Self::Output; +} + +//@ has foo/trait.Safe.html +//@ !has - '//div[@class="sidebar-elems"]//h3/a[@href="#object-safety"]' '' +pub trait Safe { + fn access(&self); +} + +//@ has foo/struct.Bar.html +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#fields"]' 'Fields' +//@ has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f"]' 'f' +//@ has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.u"]' 'u' +//@ !has - '//*[@class="sidebar-elems"]//section//a' 'waza' +pub struct Bar { + pub f: u32, + pub u: u32, + waza: u32, +} + +//@ has foo/enum.En.html +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#variants"]' 'Variants' +//@ has - '//*[@class="sidebar-elems"]//section//a' 'Foo' +//@ has - '//*[@class="sidebar-elems"]//section//a' 'Bar' +pub enum En { + Foo, + Bar, +} + +//@ has foo/union.MyUnion.html +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#fields"]' 'Fields' +//@ has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f1"]' 'f1' +//@ has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f2"]' 'f2' +//@ !has - '//*[@class="sidebar-elems"]//section//a' 'waza' +pub union MyUnion { + pub f1: u32, + pub f2: f32, + waza: u32, +} diff --git a/tests/rustdoc/sidebar/sidebar-link-generation.rs b/tests/rustdoc/sidebar/sidebar-link-generation.rs new file mode 100644 index 00000000000..ee868ec75d3 --- /dev/null +++ b/tests/rustdoc/sidebar/sidebar-link-generation.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] + +//@ has foo/struct.SomeStruct.html '//*[@class="sidebar-elems"]//section//li/a[@href="#method.some_fn-1"]' \ +// "some_fn" +pub struct SomeStruct { _inner: T } + +impl SomeStruct<()> { + pub fn some_fn(&self) {} +} + +impl SomeStruct { + pub fn some_fn(&self) {} +} diff --git a/tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs b/tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs new file mode 100644 index 00000000000..7c039eeb39f --- /dev/null +++ b/tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs @@ -0,0 +1,16 @@ +// issue #56018: "Implementations on Foreign Types" sidebar items should link to specific impls + +#![crate_name = "foo"] + +//@ has foo/trait.Foo.html +//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#foreign-impls"]' 'Implementations on Foreign Types' +//@ has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types' +//@ has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32' +//@ has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header"]' 'impl Foo for u32' +//@ has - "//*[@class=\"sidebar-elems\"]//section//a[@href=\"#impl-Foo-for-%26str\"]" "&'a str" +//@ has - "//*[@id=\"impl-Foo-for-%26str\"]//h3[@class=\"code-header\"]" "impl<'a> Foo for &'a str" +pub trait Foo {} + +impl Foo for u32 {} + +impl<'a> Foo for &'a str {} diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs new file mode 100644 index 00000000000..6fc84c1964c --- /dev/null +++ b/tests/rustdoc/sidebar/top-toc-html.rs @@ -0,0 +1,19 @@ +// ignore-tidy-linelength + +#![crate_name = "foo"] +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +//! # Basic [link](https://example.com) and *emphasis* +//! +//! This test case covers TOC entries with rich text inside. +//! Rustdoc normally supports headers with links, but for the +//! TOC, that would break the layout. +//! +//! For consistency, emphasis is also filtered out. + +// @has foo/index.html +// User header +// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]' 'Basic link and emphasis' +// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/em' 0 +// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/a' 0 diff --git a/tests/rustdoc/sidebar/top-toc-idmap.rs b/tests/rustdoc/sidebar/top-toc-idmap.rs new file mode 100644 index 00000000000..ccfc7336e9f --- /dev/null +++ b/tests/rustdoc/sidebar/top-toc-idmap.rs @@ -0,0 +1,44 @@ +#![crate_name = "foo"] +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +//! # Structs +//! +//! This header has the same name as a built-in header, +//! and we need to make sure they're disambiguated with +//! suffixes. +//! +//! Module-like headers get derived from the internal ID map, +//! so the *internal* one gets a suffix here. To make sure it +//! works right, the one in the `top-toc` needs to match the one +//! in the `top-doc`, and the one that's not in the `top-doc` +//! needs to match the one that isn't in the `top-toc`. + +// @has foo/index.html +// User header +// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs' +// @has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs' +// Built-in header +// @has - '//section[@id="TOC"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs' +// @has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs' + +/// # Fields +/// ## Fields +/// ### Fields +/// +/// The difference between struct-like headers and module-like headers +/// is strange, but not actually a problem as long as we're consistent. + +// @has foo/struct.MyStruct.html +// User header +// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields' +// @has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields' +// Only one level of nesting +// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]//a' 2 +// Built-in header +// @has - '//section[@id="TOC"]/h3/a[@href="#fields"]' 'Fields' +// @has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields' + +pub struct MyStruct { + pub fields: i32, +} -- cgit 1.4.1-3-g733a5 From 5a6054b4a2850d195bf54d7176b4a32382a8df49 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 22 Jul 2024 10:31:24 -0700 Subject: rustdoc: add separate section for module items --- src/librustdoc/html/render/context.rs | 9 ++++++--- src/librustdoc/html/render/sidebar.rs | 27 ++++++++++++++++++++++++--- src/librustdoc/html/templates/sidebar.html | 10 +++++----- tests/rustdoc/sidebar/top-toc-nil.rs | 7 +++++++ 4 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 tests/rustdoc/sidebar/top-toc-nil.rs (limited to 'tests/rustdoc') diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index a167681b316..510da99c9ef 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -14,9 +14,12 @@ use rustc_span::edition::Edition; use rustc_span::{sym, FileName, Symbol}; use super::print_item::{full_path, item_path, print_item}; -use super::sidebar::{print_sidebar, sidebar_module_like, Sidebar}; use super::write_shared::write_shared; -use super::{collect_spans_and_sources, scrape_examples_help, AllTypes, LinkFromSrc, StylePath}; +use super::{ + collect_spans_and_sources, scrape_examples_help, + sidebar::{print_sidebar, sidebar_module_like, ModuleLike, Sidebar}, + AllTypes, LinkFromSrc, StylePath, +}; use crate::clean::types::ExternalLocation; use crate::clean::utils::has_doc_flag; use crate::clean::{self, ExternalCrate}; @@ -617,7 +620,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let mut sidebar = Buffer::html(); // all.html is not customizable, so a blank id map is fine - let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new()); + let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new(), ModuleLike::Crate); let bar = Sidebar { title_prefix: "", title: "", diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 5e59754da79..c76253c9fc3 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -15,6 +15,18 @@ use crate::{ use super::{item_ty_to_section, Context, ItemSection}; +#[derive(Clone, Copy)] +pub(crate) enum ModuleLike { + Module, + Crate, +} + +impl ModuleLike { + pub(crate) fn is_crate(self) -> bool { + matches!(self, ModuleLike::Crate) + } +} + #[derive(Template)] #[template(path = "sidebar.html")] pub(super) struct Sidebar<'a> { @@ -530,14 +542,23 @@ fn sidebar_enum<'a>( pub(crate) fn sidebar_module_like( item_sections_in_use: FxHashSet, ids: &mut IdMap, + module_like: ModuleLike, ) -> LinkBlock<'static> { - let item_sections = ItemSection::ALL + let item_sections: Vec> = ItemSection::ALL .iter() .copied() .filter(|sec| item_sections_in_use.contains(sec)) .map(|sec| Link::new(ids.derive(sec.id()), sec.name())) .collect(); - LinkBlock::new(Link::empty(), "", item_sections) + let header = if let Some(first_section) = item_sections.get(0) { + Link::new( + first_section.href.to_owned(), + if module_like.is_crate() { "Crate Items" } else { "Module Items" }, + ) + } else { + Link::empty() + }; + LinkBlock::new(header, "", item_sections) } fn sidebar_module(items: &[clean::Item], ids: &mut IdMap) -> LinkBlock<'static> { @@ -561,7 +582,7 @@ fn sidebar_module(items: &[clean::Item], ids: &mut IdMap) -> LinkBlock<'static> .map(|it| item_ty_to_section(it.type_())) .collect(); - sidebar_module_like(item_sections_in_use, ids) + sidebar_module_like(item_sections_in_use, ids, ModuleLike::Module) } fn sidebar_foreign_type<'a>( diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index c0a9b254425..f49cdbabb88 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -17,7 +17,7 @@ {% if !block.heading.name.is_empty() %}

{# #} {{block.heading.name|wrapped|safe}} {# #} -

{# #} + {% endif %} {% if !block.links.is_empty() %}
    @@ -25,13 +25,13 @@
  • {# #} {{link.name}} {# #} {% if !link.children.is_empty() %} -
      {# #} + {# #} +
    {% endif %} -
  • {# #} + {% endfor %}
{% endif %} @@ -43,7 +43,7 @@ {% if !path.is_empty() %} {# #} In {{+ path|wrapped|safe}} {# #} - {# #} + {% endif %} {# #} diff --git a/tests/rustdoc/sidebar/top-toc-nil.rs b/tests/rustdoc/sidebar/top-toc-nil.rs new file mode 100644 index 00000000000..91c7df50ab4 --- /dev/null +++ b/tests/rustdoc/sidebar/top-toc-nil.rs @@ -0,0 +1,7 @@ +#![crate_name = "foo"] + +//! This test case covers missing top TOC entries. + +// @has foo/index.html +// User header +// @!has - '//section[@id="TOC"]/ul[@class="block top-toc"]' 'Basic link and emphasis' -- cgit 1.4.1-3-g733a5 From 68773c789a6a84a888b69f7287fd294b6dd3625c Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 22 Jul 2024 11:12:38 -0700 Subject: rustdoc: add separate section for module items --- src/librustdoc/html/render/sidebar.rs | 17 ++++++++++++++--- tests/rustdoc/sidebar/module.rs | 16 ++++++++++++++++ tests/rustdoc/sidebar/top-toc-html.rs | 1 + 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 tests/rustdoc/sidebar/module.rs (limited to 'tests/rustdoc') diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index c76253c9fc3..a6b22a18de2 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -26,6 +26,11 @@ impl ModuleLike { matches!(self, ModuleLike::Crate) } } +impl<'a> From<&'a clean::Item> for ModuleLike { + fn from(it: &'a clean::Item) -> ModuleLike { + if it.is_crate() { ModuleLike::Crate } else { ModuleLike::Module } + } +} #[derive(Template)] #[template(path = "sidebar.html")] @@ -119,7 +124,9 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf clean::UnionItem(ref u) => sidebar_union(cx, it, u, &mut blocks), clean::EnumItem(ref e) => sidebar_enum(cx, it, e, &mut blocks), clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t, &mut blocks), - clean::ModuleItem(ref m) => blocks.push(sidebar_module(&m.items, &mut ids)), + clean::ModuleItem(ref m) => { + blocks.push(sidebar_module(&m.items, &mut ids, ModuleLike::from(it))) + } clean::ForeignTypeItem => sidebar_foreign_type(cx, it, &mut blocks), _ => {} } @@ -561,7 +568,11 @@ pub(crate) fn sidebar_module_like( LinkBlock::new(header, "", item_sections) } -fn sidebar_module(items: &[clean::Item], ids: &mut IdMap) -> LinkBlock<'static> { +fn sidebar_module( + items: &[clean::Item], + ids: &mut IdMap, + module_like: ModuleLike, +) -> LinkBlock<'static> { let item_sections_in_use: FxHashSet<_> = items .iter() .filter(|it| { @@ -582,7 +593,7 @@ fn sidebar_module(items: &[clean::Item], ids: &mut IdMap) -> LinkBlock<'static> .map(|it| item_ty_to_section(it.type_())) .collect(); - sidebar_module_like(item_sections_in_use, ids, ModuleLike::Module) + sidebar_module_like(item_sections_in_use, ids, module_like) } fn sidebar_foreign_type<'a>( diff --git a/tests/rustdoc/sidebar/module.rs b/tests/rustdoc/sidebar/module.rs new file mode 100644 index 00000000000..926af71ddfb --- /dev/null +++ b/tests/rustdoc/sidebar/module.rs @@ -0,0 +1,16 @@ +#![crate_name = "foo"] + +//@ has 'foo/index.html' +//@ has - '//section[@id="TOC"]/h3' 'Crate Items' + +//@ has 'foo/bar/index.html' +//@ has - '//section[@id="TOC"]/h3' 'Module Items' +pub mod bar { + //@ has 'foo/bar/struct.Baz.html' + //@ !has - '//section[@id="TOC"]/h3' 'Module Items' + pub struct Baz; +} + +//@ has 'foo/baz/index.html' +//@ !has - '//section[@id="TOC"]/h3' 'Module Items' +pub mod baz {} diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs index 6fc84c1964c..fa1325c8dca 100644 --- a/tests/rustdoc/sidebar/top-toc-html.rs +++ b/tests/rustdoc/sidebar/top-toc-html.rs @@ -14,6 +14,7 @@ // @has foo/index.html // User header +// @has - '//section[@id="TOC"]/h3' 'Sections' // @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]' 'Basic link and emphasis' // @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/em' 0 // @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/a' 0 -- cgit 1.4.1-3-g733a5 From 7091fa5880db84392783147171f5709b72ffa784 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 22 Jul 2024 12:59:34 -0700 Subject: rustdoc: show code spans as `` in TOC --- src/librustdoc/html/markdown.rs | 29 ++++++++++++++++++++-- src/librustdoc/html/render/sidebar.rs | 12 +++++++-- src/librustdoc/html/templates/sidebar.html | 18 ++++++++++++-- src/librustdoc/html/toc.rs | 15 ++++++++--- src/librustdoc/html/toc/tests.rs | 6 ++++- tests/rustdoc/sidebar/top-toc-html.rs | 15 ++++++----- tests/rustdoc/sidebar/top-toc-idmap.rs | 22 ++++++++-------- tests/rustdoc/sidebar/top-toc-nil.rs | 4 +-- tests/rustdoc/strip-enum-variant.no-not-shown.html | 2 +- 9 files changed, 92 insertions(+), 31 deletions(-) (limited to 'tests/rustdoc') diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 58795508a58..4b82f232765 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -50,7 +50,7 @@ use rustc_span::{Span, Symbol}; use crate::clean::RenderedLink; use crate::doctest; use crate::doctest::GlobalTestOptions; -use crate::html::escape::Escape; +use crate::html::escape::{Escape, EscapeBodyText}; use crate::html::format::Buffer; use crate::html::highlight; use crate::html::length_limit::HtmlWithLimit; @@ -535,7 +535,9 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator if let Some(ref mut builder) = self.toc { let mut text_header = String::new(); plain_text_from_events(self.buf.iter().map(|(ev, _)| ev.clone()), &mut text_header); - let sec = builder.push(level as u32, text_header, id.clone()); + let mut html_header = String::new(); + html_text_from_events(self.buf.iter().map(|(ev, _)| ev.clone()), &mut html_header); + let sec = builder.push(level as u32, text_header, html_header, id.clone()); self.buf.push_front((Event::Html(format!("{sec} ").into()), 0..0)); } @@ -1655,6 +1657,29 @@ pub(crate) fn plain_text_from_events<'a>( } } +pub(crate) fn html_text_from_events<'a>( + events: impl Iterator>, + s: &mut String, +) { + for event in events { + match &event { + Event::Text(text) => { + write!(s, "{}", EscapeBodyText(text)).expect("string alloc infallible") + } + Event::Code(code) => { + s.push_str(""); + write!(s, "{}", EscapeBodyText(code)).expect("string alloc infallible"); + s.push_str(""); + } + Event::HardBreak | Event::SoftBreak => s.push(' '), + Event::Start(Tag::CodeBlock(..)) => break, + Event::End(TagEnd::Paragraph) => break, + Event::End(TagEnd::Heading(..)) => break, + _ => (), + } + } +} + #[derive(Debug)] pub(crate) struct MarkdownLink { pub kind: LinkType, diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index a6b22a18de2..351a23b880d 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -81,8 +81,10 @@ impl<'a> LinkBlock<'a> { /// A link to an item. Content should not be escaped. #[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone)] pub(crate) struct Link<'a> { - /// The content for the anchor tag + /// The content for the anchor tag and title attr name: Cow<'a, str>, + /// The content for the anchor tag (if different from name) + name_html: Option>, /// The id of an anchor within the page (without a `#` prefix) href: Cow<'a, str>, /// Nested list of links (used only in top-toc) @@ -91,7 +93,7 @@ pub(crate) struct Link<'a> { impl<'a> Link<'a> { pub fn new(href: impl Into>, name: impl Into>) -> Self { - Self { href: href.into(), name: name.into(), children: vec![] } + Self { href: href.into(), name: name.into(), children: vec![], name_html: None } } pub fn empty() -> Link<'static> { Link::new("", "") @@ -207,6 +209,7 @@ fn docblock_toc<'a>( .into_iter() .map(|entry| { Link { + name_html: if entry.html == entry.name { None } else { Some(entry.html.into()) }, name: entry.name.into(), href: entry.id.into(), children: entry @@ -214,6 +217,11 @@ fn docblock_toc<'a>( .entries .into_iter() .map(|entry| Link { + name_html: if entry.html == entry.name { + None + } else { + Some(entry.html.into()) + }, name: entry.name.into(), href: entry.id.into(), // Only a single level of nesting is shown here. diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index f49cdbabb88..31823848ec3 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -23,11 +23,25 @@
    {% for link in block.links %}
  • {# #} - {{link.name}} {# #} + + {% match link.name_html %} + {% when Some with (html) %} + {{html|safe}} + {% else %} + {{link.name}} + {% endmatch %} + {# #} {% if !link.children.is_empty() %} {% endif %} diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs index a44c4a1b59e..7fdce41a634 100644 --- a/src/librustdoc/html/toc.rs +++ b/src/librustdoc/html/toc.rs @@ -1,5 +1,5 @@ //! Table-of-contents creation. -use crate::html::escape::EscapeBodyText; +use crate::html::escape::Escape; /// A (recursive) table of contents #[derive(Debug, PartialEq)] @@ -30,7 +30,12 @@ impl Toc { pub(crate) struct TocEntry { pub(crate) level: u32, pub(crate) sec_number: String, + // name is a plain text header that works in a `title` tag + // html includes `` tags + // the tooltip is used so that, when a toc is truncated, + // you can mouse over it to see the whole thing pub(crate) name: String, + pub(crate) html: String, pub(crate) id: String, pub(crate) children: Toc, } @@ -116,7 +121,7 @@ impl TocBuilder { /// Push a level `level` heading into the appropriate place in the /// hierarchy, returning a string containing the section number in /// `..` format. - pub(crate) fn push(&mut self, level: u32, name: String, id: String) -> &str { + pub(crate) fn push(&mut self, level: u32, name: String, html: String, id: String) -> &str { assert!(level >= 1); // collapse all previous sections into their parents until we @@ -150,6 +155,7 @@ impl TocBuilder { self.chain.push(TocEntry { level, name, + html, sec_number, id, children: Toc { entries: Vec::new() }, @@ -171,10 +177,11 @@ impl Toc { // recursively format this table of contents let _ = write!( v, - "\n
  • {num} {name}", + "\n
  • {num} {html}", id = entry.id, num = entry.sec_number, - name = EscapeBodyText(&entry.name) + name = Escape(&entry.name), + html = &entry.html, ); entry.children.print_inner(&mut *v); v.push_str("
  • "); diff --git a/src/librustdoc/html/toc/tests.rs b/src/librustdoc/html/toc/tests.rs index 014f346862b..81aca737baf 100644 --- a/src/librustdoc/html/toc/tests.rs +++ b/src/librustdoc/html/toc/tests.rs @@ -9,7 +9,10 @@ fn builder_smoke() { // there's been no macro mistake. macro_rules! push { ($level: expr, $name: expr) => { - assert_eq!(builder.push($level, $name.to_string(), "".to_string()), $name); + assert_eq!( + builder.push($level, $name.to_string(), $name.to_string(), "".to_string()), + $name + ); }; } push!(2, "0.1"); @@ -48,6 +51,7 @@ fn builder_smoke() { TocEntry { level: $level, name: $name.to_string(), + html: $name.to_string(), sec_number: $name.to_string(), id: "".to_string(), children: toc!($($sub),*) diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs index fa1325c8dca..db998775644 100644 --- a/tests/rustdoc/sidebar/top-toc-html.rs +++ b/tests/rustdoc/sidebar/top-toc-html.rs @@ -4,7 +4,7 @@ #![feature(lazy_type_alias)] #![allow(incomplete_features)] -//! # Basic [link](https://example.com) and *emphasis* +//! # Basic [link](https://example.com) and *emphasis* and `code` //! //! This test case covers TOC entries with rich text inside. //! Rustdoc normally supports headers with links, but for the @@ -12,9 +12,12 @@ //! //! For consistency, emphasis is also filtered out. -// @has foo/index.html +//@ has foo/index.html // User header -// @has - '//section[@id="TOC"]/h3' 'Sections' -// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]' 'Basic link and emphasis' -// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/em' 0 -// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis"]/a' 0 +//@ has - '//section[@id="TOC"]/h3' 'Sections' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/@title' 'Basic link and emphasis and `code`' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]' 'Basic link and emphasis and code' +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/em' 0 +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/a' 0 +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/code' 1 +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/code' 'code' diff --git a/tests/rustdoc/sidebar/top-toc-idmap.rs b/tests/rustdoc/sidebar/top-toc-idmap.rs index ccfc7336e9f..fdb99fd05a1 100644 --- a/tests/rustdoc/sidebar/top-toc-idmap.rs +++ b/tests/rustdoc/sidebar/top-toc-idmap.rs @@ -14,13 +14,13 @@ //! in the `top-doc`, and the one that's not in the `top-doc` //! needs to match the one that isn't in the `top-toc`. -// @has foo/index.html +//@ has foo/index.html // User header -// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs' -// @has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#structs"]' 'Structs' +//@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="structs"]' 'Structs' // Built-in header -// @has - '//section[@id="TOC"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs' -// @has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs' +//@ has - '//section[@id="TOC"]/ul[@class="block"]/li/a[@href="#structs-1"]' 'Structs' +//@ has - '//section[@id="main-content"]/h2[@id="structs-1"]' 'Structs' /// # Fields /// ## Fields @@ -29,15 +29,15 @@ /// The difference between struct-like headers and module-like headers /// is strange, but not actually a problem as long as we're consistent. -// @has foo/struct.MyStruct.html +//@ has foo/struct.MyStruct.html // User header -// @has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields' -// @has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#fields-1"]' 'Fields' +//@ has - '//details[@class="toggle top-doc"]/div[@class="docblock"]/h2[@id="fields-1"]' 'Fields' // Only one level of nesting -// @count - '//section[@id="TOC"]/ul[@class="block top-toc"]//a' 2 +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]//a' 2 // Built-in header -// @has - '//section[@id="TOC"]/h3/a[@href="#fields"]' 'Fields' -// @has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields' +//@ has - '//section[@id="TOC"]/h3/a[@href="#fields"]' 'Fields' +//@ has - '//section[@id="main-content"]/h2[@id="fields"]' 'Fields' pub struct MyStruct { pub fields: i32, diff --git a/tests/rustdoc/sidebar/top-toc-nil.rs b/tests/rustdoc/sidebar/top-toc-nil.rs index 91c7df50ab4..c338bd67fcf 100644 --- a/tests/rustdoc/sidebar/top-toc-nil.rs +++ b/tests/rustdoc/sidebar/top-toc-nil.rs @@ -2,6 +2,6 @@ //! This test case covers missing top TOC entries. -// @has foo/index.html +//@ has foo/index.html // User header -// @!has - '//section[@id="TOC"]/ul[@class="block top-toc"]' 'Basic link and emphasis' +//@ !has - '//section[@id="TOC"]/ul[@class="block top-toc"]' 'Basic link and emphasis' diff --git a/tests/rustdoc/strip-enum-variant.no-not-shown.html b/tests/rustdoc/strip-enum-variant.no-not-shown.html index e072335297d..d7a36cc631a 100644 --- a/tests/rustdoc/strip-enum-variant.no-not-shown.html +++ b/tests/rustdoc/strip-enum-variant.no-not-shown.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 95fcddd29f7127bbca70375b8db3d455019843e0 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 23 Jul 2024 09:11:52 -0700 Subject: Add more test case --- tests/rustdoc/sidebar/top-toc-html.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'tests/rustdoc') diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc/sidebar/top-toc-html.rs index db998775644..8991ed0330e 100644 --- a/tests/rustdoc/sidebar/top-toc-html.rs +++ b/tests/rustdoc/sidebar/top-toc-html.rs @@ -4,7 +4,7 @@ #![feature(lazy_type_alias)] #![allow(incomplete_features)] -//! # Basic [link](https://example.com) and *emphasis* and `code` +//! # Basic [link](https://example.com), *emphasis*, **_very emphasis_** and `code` //! //! This test case covers TOC entries with rich text inside. //! Rustdoc normally supports headers with links, but for the @@ -15,9 +15,9 @@ //@ has foo/index.html // User header //@ has - '//section[@id="TOC"]/h3' 'Sections' -//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/@title' 'Basic link and emphasis and `code`' -//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]' 'Basic link and emphasis and code' -//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/em' 0 -//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/a' 0 -//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/code' 1 -//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-and-emphasis-and-code"]/code' 'code' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/@title' 'Basic link, emphasis, very emphasis and `code`' +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]' 'Basic link, emphasis, very emphasis and code' +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/em' 0 +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/a' 0 +//@ count - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 1 +//@ has - '//section[@id="TOC"]/ul[@class="block top-toc"]/li/a[@href="#basic-link-emphasis-very-emphasis-and-code"]/code' 'code' -- cgit 1.4.1-3-g733a5 From 12a3c42cccd18d5fadcbad44c3c5442e4aca1a13 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 24 Jul 2024 13:16:08 -0700 Subject: rustdoc: consistentify `#TOC` and `#ModNav` to lowercase --- src/doc/not_found.md | 2 +- src/librustdoc/html/markdown.rs | 5 +++-- src/librustdoc/html/static/css/rustdoc.css | 4 ++-- src/librustdoc/html/static/js/main.js | 4 ++-- src/librustdoc/html/templates/sidebar.html | 4 ++-- tests/rustdoc-gui/sidebar.goml | 24 ++++++++++++------------ tests/rustdoc/sidebar/module.rs | 8 ++++---- tests/rustdoc/sidebar/top-toc-html.rs | 14 +++++++------- tests/rustdoc/sidebar/top-toc-idmap.rs | 10 +++++----- tests/rustdoc/sidebar/top-toc-nil.rs | 2 +- 10 files changed, 39 insertions(+), 38 deletions(-) (limited to 'tests/rustdoc') diff --git a/src/doc/not_found.md b/src/doc/not_found.md index f0794fc0be3..9552759d2b8 100644 --- a/src/doc/not_found.md +++ b/src/doc/not_found.md @@ -2,7 +2,7 @@