Skip to content

Commit

Permalink
Unrolled build for rust-lang#117662
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#117662 - GuillaumeGomez:links-in-headings, r=notriddle

[rustdoc] Allows links in headings

Reopening of rust-lang#94360.

# Explanations

Rustdoc currently doesn't follow the markdown spec on headings: we don't allow links in them. So instead of having headings linking to themselves, this PR generates an anchor on the left side like this:

![image](https://github.com/rust-lang/rust/assets/3050060/a118a7e9-5ef8-4d07-914f-46defc3245c3)

<details>
<summary>previous version</summary>

![image](https://github.com/rust-lang/rust/assets/3050060/c34fa844-9cd4-47dc-bb51-b37f5f66afee)

</details>

Having the anchor always displayed allows for mobile devices users to be able to have a link to the anchor. The different color used for the anchor itself is the same as links so people notice when looking at it that they can click on it.

You can test it [here](https://rustdoc.crud.net/imperio/links-in-headings/std/index.html).

cc `@camelid`
r? `@notriddle`
  • Loading branch information
rust-timer authored Jan 20, 2024
2 parents 0547c41 + bf4a20c commit d73b841
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 99 deletions.
9 changes: 3 additions & 6 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,6 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
for event in &mut self.inner {
match &event.0 {
Event::End(Tag::Heading(..)) => break,
Event::Start(Tag::Link(_, _, _)) | Event::End(Tag::Link(..)) => {}
Event::Text(text) | Event::Code(text) => {
id.extend(text.chars().filter_map(slugify));
self.buf.push_back(event);
Expand All @@ -549,12 +548,10 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator

let level =
std::cmp::min(level as u32 + (self.heading_offset as u32), MAX_HEADER_LEVEL);
self.buf.push_back((Event::Html(format!("</a></h{level}>").into()), 0..0));
self.buf.push_back((Event::Html(format!("</h{level}>").into()), 0..0));

let start_tags = format!(
"<h{level} id=\"{id}\">\
<a href=\"#{id}\">",
);
let start_tags =
format!("<h{level} id=\"{id}\"><a class=\"doc-anchor\" href=\"#{id}\">§</a>");
return Some((Event::Html(start_tags.into()), 0..0));
}
event
Expand Down
60 changes: 48 additions & 12 deletions src/librustdoc/html/markdown/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,26 +311,38 @@ fn test_header() {
assert_eq!(output, expect, "original: {}", input);
}

t("# Foo bar", "<h2 id=\"foo-bar\"><a href=\"#foo-bar\">Foo bar</a></h2>");
t(
"# Foo bar",
"<h2 id=\"foo-bar\"><a class=\"doc-anchor\" href=\"#foo-bar\">§</a>Foo bar</h2>",
);
t(
"## Foo-bar_baz qux",
"<h3 id=\"foo-bar_baz-qux\">\
<a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h3>",
<a class=\"doc-anchor\" href=\"#foo-bar_baz-qux\">§</a>\
Foo-bar_baz qux\
</h3>",
);
t(
"### **Foo** *bar* baz!?!& -_qux_-%",
"<h4 id=\"foo-bar-baz--qux-\">\
<a href=\"#foo-bar-baz--qux-\"><strong>Foo</strong> \
<em>bar</em> baz!?!&amp; -<em>qux</em>-%</a>\
<a class=\"doc-anchor\" href=\"#foo-bar-baz--qux-\">§</a>\
<strong>Foo</strong> <em>bar</em> baz!?!&amp; -<em>qux</em>-%\
</h4>",
);
t(
"#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux",
"<h5 id=\"foo--bar--baz--qux\">\
<a href=\"#foo--bar--baz--qux\"><strong>Foo?</strong> &amp; *bar?!* \
<em><code>baz</code></em> ❤ #qux</a>\
<a class=\"doc-anchor\" href=\"#foo--bar--baz--qux\">§</a>\
<strong>Foo?</strong> &amp; *bar?!* <em><code>baz</code></em> ❤ #qux\
</h5>",
);
t(
"# Foo [bar](https://hello.yo)",
"<h2 id=\"foo-bar\">\
<a class=\"doc-anchor\" href=\"#foo-bar\">§</a>\
Foo <a href=\"https://hello.yo\">bar</a>\
</h2>",
);
}

#[test]
Expand All @@ -351,12 +363,36 @@ fn test_header_ids_multiple_blocks() {
assert_eq!(output, expect, "original: {}", input);
}

t(&mut map, "# Example", "<h2 id=\"example\"><a href=\"#example\">Example</a></h2>");
t(&mut map, "# Panics", "<h2 id=\"panics\"><a href=\"#panics\">Panics</a></h2>");
t(&mut map, "# Example", "<h2 id=\"example-1\"><a href=\"#example-1\">Example</a></h2>");
t(&mut map, "# Search", "<h2 id=\"search-1\"><a href=\"#search-1\">Search</a></h2>");
t(&mut map, "# Example", "<h2 id=\"example-2\"><a href=\"#example-2\">Example</a></h2>");
t(&mut map, "# Panics", "<h2 id=\"panics-1\"><a href=\"#panics-1\">Panics</a></h2>");
t(
&mut map,
"# Example",
"<h2 id=\"example\"><a class=\"doc-anchor\" href=\"#example\">§</a>Example</h2>",
);
t(
&mut map,
"# Panics",
"<h2 id=\"panics\"><a class=\"doc-anchor\" href=\"#panics\">§</a>Panics</h2>",
);
t(
&mut map,
"# Example",
"<h2 id=\"example-1\"><a class=\"doc-anchor\" href=\"#example-1\">§</a>Example</h2>",
);
t(
&mut map,
"# Search",
"<h2 id=\"search-1\"><a class=\"doc-anchor\" href=\"#search-1\">§</a>Search</h2>",
);
t(
&mut map,
"# Example",
"<h2 id=\"example-2\"><a class=\"doc-anchor\" href=\"#example-2\">§</a>Example</h2>",
);
t(
&mut map,
"# Panics",
"<h2 id=\"panics-1\"><a class=\"doc-anchor\" href=\"#panics-1\">§</a>Panics</h2>",
);
}

#[test]
Expand Down
20 changes: 17 additions & 3 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1207,17 +1207,31 @@ impl<'a> AssocItemLink<'a> {
}
}

fn write_impl_section_heading(mut w: impl fmt::Write, title: &str, id: &str) {
pub fn write_section_heading(
w: &mut impl fmt::Write,
title: &str,
id: &str,
extra_class: Option<&str>,
extra: impl fmt::Display,
) {
let (extra_class, whitespace) = match extra_class {
Some(extra) => (extra, " "),
None => ("", ""),
};
write!(
w,
"<h2 id=\"{id}\" class=\"section-header\">\
"<h2 id=\"{id}\" class=\"{extra_class}{whitespace}section-header\">\
{title}\
<a href=\"#{id}\" class=\"anchor\">§</a>\
</h2>"
</h2>{extra}",
)
.unwrap();
}

fn write_impl_section_heading(w: &mut impl fmt::Write, title: &str, id: &str) {
write_section_heading(w, title, id, None, "")
}

pub(crate) fn render_all_impls(
mut w: impl Write,
cx: &mut Context<'_>,
Expand Down
Loading

0 comments on commit d73b841

Please sign in to comment.