about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2024-07-22 12:59:34 -0700
committerMichael Howell <michael@notriddle.com>2024-08-20 16:51:37 -0700
commit7091fa5880db84392783147171f5709b72ffa784 (patch)
tree718dcf9656df5b144031bc66a598be6c36677f42
parent68773c789a6a84a888b69f7287fd294b6dd3625c (diff)
downloadrust-7091fa5880db84392783147171f5709b72ffa784.tar.gz
rust-7091fa5880db84392783147171f5709b72ffa784.zip
rustdoc: show code spans as `<code>` in TOC
-rw-r--r--src/librustdoc/html/markdown.rs29
-rw-r--r--src/librustdoc/html/render/sidebar.rs12
-rw-r--r--src/librustdoc/html/templates/sidebar.html18
-rw-r--r--src/librustdoc/html/toc.rs15
-rw-r--r--src/librustdoc/html/toc/tests.rs6
-rw-r--r--tests/rustdoc/sidebar/top-toc-html.rs15
-rw-r--r--tests/rustdoc/sidebar/top-toc-idmap.rs22
-rw-r--r--tests/rustdoc/sidebar/top-toc-nil.rs4
-rw-r--r--tests/rustdoc/strip-enum-variant.no-not-shown.html2
9 files changed, 92 insertions, 31 deletions
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<Item = SpannedEvent<'a>>> 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<Item = pulldown_cmark::Event<'a>>,
+    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("<code>");
+                write!(s, "{}", EscapeBodyText(code)).expect("string alloc infallible");
+                s.push_str("</code>");
+            }
+            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<Cow<'a, str>>,
     /// 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<Cow<'a, str>>, name: impl Into<Cow<'a, str>>) -> 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 @@
                         <ul class="block{% if !block.class.is_empty() +%} {{+block.class}}{% endif %}">
                             {% for link in block.links %}
                                 <li> {# #}
-                                    <a href="#{{link.href|safe}}">{{link.name}}</a> {# #}
+                                    <a href="#{{link.href|safe}}" title="{{link.name}}">
+                                        {% match link.name_html %}
+                                            {% when Some with (html) %}
+                                                {{html|safe}}
+                                            {% else %}
+                                                {{link.name}}
+                                        {% endmatch %}
+                                    </a> {# #}
                                     {% if !link.children.is_empty() %}
                                         <ul>
                                             {% for child in link.children %}
-                                                <li><a href="#{{child.href|safe}}">{{child.name}}</a></li>
+                                                <li><a href="#{{child.href|safe}}" title="{{child.name}}">
+                                                    {% match child.name_html %}
+                                                        {% when Some with (html) %}
+                                                            {{html|safe}}
+                                                        {% else %}
+                                                            {{child.name}}
+                                                    {% endmatch %}
+                                                </a></li>
                                             {% endfor %}
                                         </ul>
                                     {% 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 `<code>` 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
     /// `<num>.<num>.<num>` 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<li><a href=\"#{id}\">{num} {name}</a>",
+                "\n<li><a href=\"#{id}\" title=\"{name}\">{num} {html}</a>",
                 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("</li>");
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 @@
-<ul class="block variant"><li><a href="#variant.Shown">Shown</a></li></ul>
\ No newline at end of file
+<ul class="block variant"><li><a href="#variant.Shown" title="Shown">Shown</a></li></ul>
\ No newline at end of file