Rollup merge of #101868 - notriddle:notriddle/short-links-jump-to-definition, r=GuillaumeGomez

rustdoc: use more precise URLs for jump-to-definition links

As an example, this cuts down <https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/ty/mod.rs.html> by about 11%.

    $ du -h new_mod.rs.html old_mod.rs.html
    296K	new_mod.rs.html
    332K	old_mod.rs.html

Like https://github.com/rust-lang/rust/pull/83237, but separate code since source links have a different URL structure.

Related to [Zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/RFC.20for.20.22jump.20to.20definition.22.20feature/near/299029786) and [the jump-to-definition pre-RFC](https://github.com/GuillaumeGomez/rfcs/pull/1).
This commit is contained in:
Guillaume Gomez 2022-09-16 13:07:19 +02:00 committed by GitHub
commit c21dcd7914
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 19 deletions

View File

@ -29,6 +29,8 @@ pub(crate) struct HrefContext<'a, 'b, 'c> {
/// This field is used to know "how far" from the top of the directory we are to link to either /// This field is used to know "how far" from the top of the directory we are to link to either
/// documentation pages or other source pages. /// documentation pages or other source pages.
pub(crate) root_path: &'c str, pub(crate) root_path: &'c str,
/// This field is used to calculate precise local URLs.
pub(crate) current_href: &'c str,
} }
/// Decorations are represented as a map from CSS class to vector of character ranges. /// Decorations are represented as a map from CSS class to vector of character ranges.
@ -977,9 +979,9 @@ fn string_without_closing_tag<T: Display>(
// a link to their definition can be generated using this: // a link to their definition can be generated using this:
// https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338 // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
match href { match href {
LinkFromSrc::Local(span) => context LinkFromSrc::Local(span) => {
.href_from_span(*span, true) context.href_from_span_relative(*span, href_context.current_href)
.map(|s| format!("{}{}", href_context.root_path, s)), }
LinkFromSrc::External(def_id) => { LinkFromSrc::External(def_id) => {
format::href_with_root_path(*def_id, context, Some(href_context.root_path)) format::href_with_root_path(*def_id, context, Some(href_context.root_path))
.ok() .ok()

View File

@ -31,6 +31,7 @@ use crate::formats::FormatRenderer;
use crate::html::escape::Escape; use crate::html::escape::Escape;
use crate::html::format::{join_with_double_colon, Buffer}; use crate::html::format::{join_with_double_colon, Buffer};
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap}; use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
use crate::html::url_parts_builder::UrlPartsBuilder;
use crate::html::{layout, sources}; use crate::html::{layout, sources};
use crate::scrape_examples::AllCallLocations; use crate::scrape_examples::AllCallLocations;
use crate::try_err; use crate::try_err;
@ -370,6 +371,35 @@ impl<'tcx> Context<'tcx> {
anchor = anchor anchor = anchor
)) ))
} }
pub(crate) fn href_from_span_relative(
&self,
span: clean::Span,
relative_to: &str,
) -> Option<String> {
self.href_from_span(span, false).map(|s| {
let mut url = UrlPartsBuilder::new();
let mut dest_href_parts = s.split('/');
let mut cur_href_parts = relative_to.split('/');
for (cur_href_part, dest_href_part) in (&mut cur_href_parts).zip(&mut dest_href_parts) {
if cur_href_part != dest_href_part {
url.push(dest_href_part);
break;
}
}
for dest_href_part in dest_href_parts {
url.push(dest_href_part);
}
let loline = span.lo(self.sess()).line;
let hiline = span.hi(self.sess()).line;
format!(
"{}{}#{}",
"../".repeat(cur_href_parts.count()),
url.finish(),
if loline == hiline { loline.to_string() } else { format!("{loline}-{hiline}") }
)
})
}
} }
/// Generates the documentation for `crate` into the directory `dst` /// Generates the documentation for `crate` into the directory `dst`

View File

@ -288,11 +288,14 @@ pub(crate) fn print_src(
} }
} }
line_numbers.write_str("</pre>"); line_numbers.write_str("</pre>");
let current_href = &context
.href_from_span(clean::Span::new(file_span), false)
.expect("only local crates should have sources emitted");
highlight::render_source_with_highlighting( highlight::render_source_with_highlighting(
s, s,
buf, buf,
line_numbers, line_numbers,
highlight::HrefContext { context, file_span, root_path }, highlight::HrefContext { context, file_span, root_path, current_href },
decoration_info, decoration_info,
); );
} }

View File

@ -9,7 +9,7 @@ fn babar() {}
// @has - '//a[@href="{{channel}}/std/primitive.u32.html"]' 'u32' // @has - '//a[@href="{{channel}}/std/primitive.u32.html"]' 'u32'
// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str' // @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str'
// @has - '//a[@href="{{channel}}/std/primitive.bool.html"]' 'bool' // @has - '//a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#7"]' 'babar' // @has - '//a[@href="#7"]' 'babar'
pub fn foo(a: u32, b: &str, c: String) { pub fn foo(a: u32, b: &str, c: String) {
let x = 12; let x = 12;
let y: bool = true; let y: bool = true;
@ -31,12 +31,12 @@ macro_rules! data {
pub fn another_foo() { pub fn another_foo() {
// This is known limitation: if the macro doesn't generate anything, the visitor // This is known limitation: if the macro doesn't generate anything, the visitor
// can't find any item or anything that could tell us that it comes from expansion. // can't find any item or anything that could tell us that it comes from expansion.
// @!has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#19"]' 'yolo!' // @!has - '//a[@href="#19"]' 'yolo!'
yolo!(); yolo!();
// @has - '//a[@href="{{channel}}/std/macro.eprintln.html"]' 'eprintln!' // @has - '//a[@href="{{channel}}/std/macro.eprintln.html"]' 'eprintln!'
eprintln!(); eprintln!();
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#27-29"]' 'data!' // @has - '//a[@href="#27-29"]' 'data!'
let x = data!(4); let x = data!(4);
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#23-25"]' 'bar!' // @has - '//a[@href="#23-25"]' 'bar!'
bar!(x); bar!(x);
} }

View File

@ -10,14 +10,14 @@ extern crate source_code;
// @has 'src/foo/check-source-code-urls-to-def.rs.html' // @has 'src/foo/check-source-code-urls-to-def.rs.html'
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#1-17"]' 'bar' // @has - '//a[@href="auxiliary/source-code-bar.rs.html#1-17"]' 'bar'
#[path = "auxiliary/source-code-bar.rs"] #[path = "auxiliary/source-code-bar.rs"]
pub mod bar; pub mod bar;
// @count - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#5"]' 4 // @count - '//a[@href="auxiliary/source-code-bar.rs.html#5"]' 4
use bar::Bar; use bar::Bar;
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#13"]' 'self' // @has - '//a[@href="auxiliary/source-code-bar.rs.html#13"]' 'self'
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait' // @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
use bar::sub::{self, Trait}; use bar::sub::{self, Trait};
pub struct Foo; pub struct Foo;
@ -31,26 +31,26 @@ fn babar() {}
// @has - '//a/@href' '/struct.String.html' // @has - '//a/@href' '/struct.String.html'
// @has - '//a/@href' '/primitive.u32.html' // @has - '//a/@href' '/primitive.u32.html'
// @has - '//a/@href' '/primitive.str.html' // @has - '//a/@href' '/primitive.str.html'
// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#23"]' 5 // @count - '//a[@href="#23"]' 5
// @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode' // @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) { pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
let x = 12; let x = 12;
let y: Foo = Foo; let y: Foo = Foo;
let z: Bar = bar::Bar { field: Foo }; let z: Bar = bar::Bar { field: Foo };
babar(); babar();
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#26"]' 'hello' // @has - '//a[@href="#26"]' 'hello'
y.hello(); y.hello();
} }
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait' // @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait'
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait' // @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {} pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {}
pub trait AnotherTrait {} pub trait AnotherTrait {}
pub trait WhyNot {} pub trait WhyNot {}
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#49"]' 'AnotherTrait' // @has - '//a[@href="#49"]' 'AnotherTrait'
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#50"]' 'WhyNot' // @has - '//a[@href="#50"]' 'WhyNot'
pub fn foo3<T, V>(t: &T, v: &V) pub fn foo3<T, V>(t: &T, v: &V)
where where
T: AnotherTrait, T: AnotherTrait,
@ -59,7 +59,7 @@ where
pub trait AnotherTrait2 {} pub trait AnotherTrait2 {}
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#60"]' 'AnotherTrait2' // @has - '//a[@href="#60"]' 'AnotherTrait2'
pub fn foo4() { pub fn foo4() {
let x: Vec<AnotherTrait2> = Vec::new(); let x: Vec<AnotherTrait2> = Vec::new();
} }