From 3d88c1e647237376e846d6cf74f7f0b900104103 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 3 Jul 2025 00:41:47 +0300 Subject: [PATCH] Remove keyword prefixes (`macro@` or `macro `) from links in the docs only if the link target is inferred That is, do it for `[macro foo]`, but not for `[macro foo](macro foo)`. --- crates/ide/src/doc_links.rs | 27 +++++++++++++++++++++------ crates/ide/src/hover/tests.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 2c983287d89c..f58202a42130 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -60,7 +60,7 @@ pub(crate) fn rewrite_links( let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb)) .into_offset_iter(); - let doc = map_links(doc, |target, title, range| { + let doc = map_links(doc, |target, title, range, link_type| { // This check is imperfect, there's some overlap between valid intra-doc links // and valid URLs so we choose to be too eager to try to resolve what might be // a URL. @@ -78,7 +78,7 @@ pub(crate) fn rewrite_links( .map(|(_, attr_id)| attr_id.is_inner_attr()) .unwrap_or(false); if let Some((target, title)) = - rewrite_intra_doc_link(db, definition, target, title, is_inner_doc) + rewrite_intra_doc_link(db, definition, target, title, is_inner_doc, link_type) { (None, target, title) } else if let Some(target) = rewrite_url_link(db, definition, target) { @@ -417,6 +417,7 @@ fn rewrite_intra_doc_link( target: &str, title: &str, is_inner_doc: bool, + link_type: LinkType, ) -> Option<(String, String)> { let (link, ns) = parse_intra_doc_link(target); @@ -438,7 +439,21 @@ fn rewrite_intra_doc_link( url = url.join(&file).ok()?; url.set_fragment(frag); - Some((url.into(), strip_prefixes_suffixes(title).to_owned())) + // We want to strip the keyword prefix from the title, but only if the target is implicitly the same + // as the title. + let title = match link_type { + LinkType::Email + | LinkType::Autolink + | LinkType::Shortcut + | LinkType::Collapsed + | LinkType::Reference + | LinkType::Inline => title.to_owned(), + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown | LinkType::ReferenceUnknown => { + strip_prefixes_suffixes(title).to_owned() + } + }; + + Some((url.into(), title)) } /// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`). @@ -470,7 +485,7 @@ fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option { /// Rewrites a markdown document, applying 'callback' to each link. fn map_links<'e>( events: impl Iterator, Range)>, - callback: impl Fn(&str, &str, Range) -> (Option, String, String), + callback: impl Fn(&str, &str, Range, LinkType) -> (Option, String, String), ) -> impl Iterator> { let mut in_link = false; // holds the origin link target on start event and the rewritten one on end event @@ -497,7 +512,7 @@ fn map_links<'e>( } Event::Text(s) if in_link => { let (link_type, link_target_s, link_name) = - callback(&end_link_target.take().unwrap(), &s, range); + callback(&end_link_target.take().unwrap(), &s, range, end_link_type.unwrap()); end_link_target = Some(CowStr::Boxed(link_target_s.into())); if !matches!(end_link_type, Some(LinkType::Autolink)) { end_link_type = link_type; @@ -506,7 +521,7 @@ fn map_links<'e>( } Event::Code(s) if in_link => { let (link_type, link_target_s, link_name) = - callback(&end_link_target.take().unwrap(), &s, range); + callback(&end_link_target.take().unwrap(), &s, range, end_link_type.unwrap()); end_link_target = Some(CowStr::Boxed(link_target_s.into())); if !matches!(end_link_type, Some(LinkType::Autolink)) { end_link_type = link_type; diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index a281a491525c..f63499aa0fd4 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -10927,3 +10927,34 @@ fn main() { "#]], ); } + +#[test] +fn keyword_inside_link() { + check( + r#" +enum Foo { + MacroExpansion, +} + +/// I return a [macro expansion](Foo::MacroExpansion). +fn bar$0() -> Foo { + Foo::MacroExpansion +} + "#, + expect![[r#" + *bar* + + ```rust + ra_test_fixture + ``` + + ```rust + fn bar() -> Foo + ``` + + --- + + I return a [macro expansion](https://docs.rs/ra_test_fixture/*/ra_test_fixture/enum.Foo.html#variant.MacroExpansion). + "#]], + ); +}