Skip to content

Commit c21dcd7

Browse files
Rollup merge of rust-lang#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 rust-lang#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](GuillaumeGomez/rfcs#1).
2 parents 9a72ded + 669498c commit c21dcd7

File tree

5 files changed

+54
-19
lines changed

5 files changed

+54
-19
lines changed

src/librustdoc/html/highlight.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub(crate) struct HrefContext<'a, 'b, 'c> {
2929
/// This field is used to know "how far" from the top of the directory we are to link to either
3030
/// documentation pages or other source pages.
3131
pub(crate) root_path: &'c str,
32+
/// This field is used to calculate precise local URLs.
33+
pub(crate) current_href: &'c str,
3234
}
3335

3436
/// 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>(
977979
// a link to their definition can be generated using this:
978980
// https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
979981
match href {
980-
LinkFromSrc::Local(span) => context
981-
.href_from_span(*span, true)
982-
.map(|s| format!("{}{}", href_context.root_path, s)),
982+
LinkFromSrc::Local(span) => {
983+
context.href_from_span_relative(*span, href_context.current_href)
984+
}
983985
LinkFromSrc::External(def_id) => {
984986
format::href_with_root_path(*def_id, context, Some(href_context.root_path))
985987
.ok()

src/librustdoc/html/render/context.rs

+30
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use crate::formats::FormatRenderer;
3131
use crate::html::escape::Escape;
3232
use crate::html::format::{join_with_double_colon, Buffer};
3333
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
34+
use crate::html::url_parts_builder::UrlPartsBuilder;
3435
use crate::html::{layout, sources};
3536
use crate::scrape_examples::AllCallLocations;
3637
use crate::try_err;
@@ -370,6 +371,35 @@ impl<'tcx> Context<'tcx> {
370371
anchor = anchor
371372
))
372373
}
374+
375+
pub(crate) fn href_from_span_relative(
376+
&self,
377+
span: clean::Span,
378+
relative_to: &str,
379+
) -> Option<String> {
380+
self.href_from_span(span, false).map(|s| {
381+
let mut url = UrlPartsBuilder::new();
382+
let mut dest_href_parts = s.split('/');
383+
let mut cur_href_parts = relative_to.split('/');
384+
for (cur_href_part, dest_href_part) in (&mut cur_href_parts).zip(&mut dest_href_parts) {
385+
if cur_href_part != dest_href_part {
386+
url.push(dest_href_part);
387+
break;
388+
}
389+
}
390+
for dest_href_part in dest_href_parts {
391+
url.push(dest_href_part);
392+
}
393+
let loline = span.lo(self.sess()).line;
394+
let hiline = span.hi(self.sess()).line;
395+
format!(
396+
"{}{}#{}",
397+
"../".repeat(cur_href_parts.count()),
398+
url.finish(),
399+
if loline == hiline { loline.to_string() } else { format!("{loline}-{hiline}") }
400+
)
401+
})
402+
}
373403
}
374404

375405
/// Generates the documentation for `crate` into the directory `dst`

src/librustdoc/html/sources.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,14 @@ pub(crate) fn print_src(
288288
}
289289
}
290290
line_numbers.write_str("</pre>");
291+
let current_href = &context
292+
.href_from_span(clean::Span::new(file_span), false)
293+
.expect("only local crates should have sources emitted");
291294
highlight::render_source_with_highlighting(
292295
s,
293296
buf,
294297
line_numbers,
295-
highlight::HrefContext { context, file_span, root_path },
298+
highlight::HrefContext { context, file_span, root_path, current_href },
296299
decoration_info,
297300
);
298301
}

src/test/rustdoc/check-source-code-urls-to-def-std.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ fn babar() {}
99
// @has - '//a[@href="{{channel}}/std/primitive.u32.html"]' 'u32'
1010
// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str'
1111
// @has - '//a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
12-
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#7"]' 'babar'
12+
// @has - '//a[@href="#7"]' 'babar'
1313
pub fn foo(a: u32, b: &str, c: String) {
1414
let x = 12;
1515
let y: bool = true;
@@ -31,12 +31,12 @@ macro_rules! data {
3131
pub fn another_foo() {
3232
// This is known limitation: if the macro doesn't generate anything, the visitor
3333
// can't find any item or anything that could tell us that it comes from expansion.
34-
// @!has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#19"]' 'yolo!'
34+
// @!has - '//a[@href="#19"]' 'yolo!'
3535
yolo!();
3636
// @has - '//a[@href="{{channel}}/std/macro.eprintln.html"]' 'eprintln!'
3737
eprintln!();
38-
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#27-29"]' 'data!'
38+
// @has - '//a[@href="#27-29"]' 'data!'
3939
let x = data!(4);
40-
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#23-25"]' 'bar!'
40+
// @has - '//a[@href="#23-25"]' 'bar!'
4141
bar!(x);
4242
}

src/test/rustdoc/check-source-code-urls-to-def.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ extern crate source_code;
1010

1111
// @has 'src/foo/check-source-code-urls-to-def.rs.html'
1212

13-
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#1-17"]' 'bar'
13+
// @has - '//a[@href="auxiliary/source-code-bar.rs.html#1-17"]' 'bar'
1414
#[path = "auxiliary/source-code-bar.rs"]
1515
pub mod bar;
1616

17-
// @count - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#5"]' 4
17+
// @count - '//a[@href="auxiliary/source-code-bar.rs.html#5"]' 4
1818
use bar::Bar;
19-
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#13"]' 'self'
20-
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait'
19+
// @has - '//a[@href="auxiliary/source-code-bar.rs.html#13"]' 'self'
20+
// @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
2121
use bar::sub::{self, Trait};
2222

2323
pub struct Foo;
@@ -31,26 +31,26 @@ fn babar() {}
3131
// @has - '//a/@href' '/struct.String.html'
3232
// @has - '//a/@href' '/primitive.u32.html'
3333
// @has - '//a/@href' '/primitive.str.html'
34-
// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#23"]' 5
34+
// @count - '//a[@href="#23"]' 5
3535
// @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
3636
pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
3737
let x = 12;
3838
let y: Foo = Foo;
3939
let z: Bar = bar::Bar { field: Foo };
4040
babar();
41-
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#26"]' 'hello'
41+
// @has - '//a[@href="#26"]' 'hello'
4242
y.hello();
4343
}
4444

45-
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait'
46-
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait'
45+
// @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait'
46+
// @has - '//a[@href="auxiliary/source-code-bar.rs.html#14"]' 'Trait'
4747
pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {}
4848

4949
pub trait AnotherTrait {}
5050
pub trait WhyNot {}
5151

52-
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#49"]' 'AnotherTrait'
53-
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#50"]' 'WhyNot'
52+
// @has - '//a[@href="#49"]' 'AnotherTrait'
53+
// @has - '//a[@href="#50"]' 'WhyNot'
5454
pub fn foo3<T, V>(t: &T, v: &V)
5555
where
5656
T: AnotherTrait,
@@ -59,7 +59,7 @@ where
5959

6060
pub trait AnotherTrait2 {}
6161

62-
// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#60"]' 'AnotherTrait2'
62+
// @has - '//a[@href="#60"]' 'AnotherTrait2'
6363
pub fn foo4() {
6464
let x: Vec<AnotherTrait2> = Vec::new();
6565
}

0 commit comments

Comments
 (0)