From 15207a0474f9af0926fcd379b597e0a2127d741c Mon Sep 17 00:00:00 2001 From: Nicholas Crothers Date: Thu, 27 Feb 2025 16:39:07 -0600 Subject: [PATCH] Add anchor for intra-doc links to associated items --- crates/ide/src/doc_links.rs | 14 ++--- crates/ide/src/doc_links/tests.rs | 92 +++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 7 deletions(-) diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index e35e47e747..d88f7c5033 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -379,13 +379,15 @@ fn rewrite_intra_doc_link( let resolved = resolve_doc_path_for_def(db, def, link, ns)?; let mut url = get_doc_base_urls(db, resolved, None, None).0?; - let (_, file, _) = filename_and_frag_for_def(db, resolved)?; + let (_, file, frag) = filename_and_frag_for_def(db, resolved)?; if let Some(path) = mod_path_of_def(db, resolved) { url = url.join(&path).ok()?; } + let frag = anchor.or(frag.as_deref()); + url = url.join(&file).ok()?; - url.set_fragment(anchor); + url.set_fragment(frag); Some((url.into(), strip_prefixes_suffixes(title).to_owned())) } @@ -621,11 +623,9 @@ fn filename_and_frag_for_def( format!("fn.{}.html", f.name(db).as_str()) } Definition::Variant(ev) => { - format!( - "enum.{}.html#variant.{}", - ev.parent_enum(db).name(db).as_str(), - ev.name(db).as_str() - ) + let def = Definition::Adt(ev.parent_enum(db).into()); + let (_, file, _) = filename_and_frag_for_def(db, def)?; + return Some((def, file, Some(format!("variant.{}", ev.name(db).as_str())))); } Definition::Const(c) => { format!("const.{}.html", c.name(db)?.as_str()) diff --git a/crates/ide/src/doc_links/tests.rs b/crates/ide/src/doc_links/tests.rs index d7291c4b9f..b09e3a3c80 100644 --- a/crates/ide/src/doc_links/tests.rs +++ b/crates/ide/src/doc_links/tests.rs @@ -686,3 +686,95 @@ fn rewrite_intra_doc_link_with_anchor() { expect!["[PartialEq#derivable](https://doc.rust-lang.org/stable/core/cmp/trait.PartialEq.html#derivable)"], ); } + +#[test] +fn rewrite_intra_doc_link_to_associated_item() { + check_rewrite( + r#" +//- /main.rs crate:foo +/// [Foo::bar] +pub struct $0Foo; + +impl Foo { + fn bar() {} +} +"#, + expect![[r#"[Foo::bar](https://docs.rs/foo/*/foo/struct.Foo.html#method.bar)"#]], + ); + check_rewrite( + r#" +//- /main.rs crate:foo +/// [Foo::bar] +pub struct $0Foo { + bar: () +} +"#, + expect![[r#"[Foo::bar](https://docs.rs/foo/*/foo/struct.Foo.html#structfield.bar)"#]], + ); + check_rewrite( + r#" +//- /main.rs crate:foo +/// [Foo::Bar] +pub enum $0Foo { + Bar +} +"#, + expect![[r#"[Foo::Bar](https://docs.rs/foo/*/foo/enum.Foo.html#variant.Bar)"#]], + ); + check_rewrite( + r#" +//- /main.rs crate:foo +/// [Foo::BAR] +pub struct $0Foo; + +impl Foo { + const BAR: () = (); +} +"#, + expect![[ + r#"[Foo::BAR](https://docs.rs/foo/*/foo/struct.Foo.html#associatedconstant.BAR)"# + ]], + ); + check_rewrite( + r#" +//- /main.rs crate:foo +/// [Foo::bar] +pub trait $0Foo { + fn bar(); +} +"#, + expect![[r#"[Foo::bar](https://docs.rs/foo/*/foo/trait.Foo.html#tymethod.bar)"#]], + ); + check_rewrite( + r#" +//- /main.rs crate:foo +/// [Foo::Bar] +pub trait $0Foo { + type Bar; +} +"#, + expect![[r#"[Foo::Bar](https://docs.rs/foo/*/foo/trait.Foo.html#associatedtype.Bar)"#]], + ); + check_rewrite( + r#" +//- /main.rs crate:foo +/// [Foo::bar#anchor] +pub struct $0Foo { + bar: (), +} +"#, + expect![[r#"[Foo::bar#anchor](https://docs.rs/foo/*/foo/struct.Foo.html#anchor)"#]], + ); + check_rewrite( + r#" +//- /main.rs crate:foo +/// [method](Foo::bar) +pub struct $0Foo; + +impl Foo { + fn bar() {} +} +"#, + expect![[r#"[method](https://docs.rs/foo/*/foo/struct.Foo.html#method.bar)"#]], + ); +}