From 96abd034a91deab95b68883d09c2ff564edce823 Mon Sep 17 00:00:00 2001 From: Wuji Chen Date: Fri, 27 Feb 2026 19:28:34 +0800 Subject: [PATCH] Fix Cmd+click navigating to file instead of definition (#49012) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Tighten `link_pattern_file_candidates` regex from `\(([^)]*)\)` to `]\(([^)]*)\)` so only Markdown link syntax `[title](path)` triggers path extraction from parentheses - Prevents function call arguments like `do_work(file2)` from being incorrectly resolved as file paths, which preempted LSP go-to-definition Closes #48938 ## Test plan - [x] `cargo test -p editor hover_links` — all 12 tests pass - [x] New unit tests verify: function calls don't extract arguments as file candidates; Markdown links still extract correctly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Release Notes: - Fixed Cmd+click navigating to file instead of definition in certain cases Co-authored-by: Claude Opus 4.6 --- crates/editor/src/hover_links.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/crates/editor/src/hover_links.rs b/crates/editor/src/hover_links.rs index a2f56f625d9553e81c9de4abbe21451982cfd17e..d4877a5f1986685bea37f243edf4ac8bbdfdf9f5 100644 --- a/crates/editor/src/hover_links.rs +++ b/crates/editor/src/hover_links.rs @@ -673,7 +673,7 @@ pub(crate) async fn find_file( // (literally, [LinkTitle](link_file.txt)) as a candidate. fn link_pattern_file_candidates(candidate: &str) -> Vec<(String, Range)> { static MD_LINK_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"\(([^)]*)\)").expect("Failed to create REGEX")); + LazyLock::new(|| Regex::new(r"]\(([^)]*)\)").expect("Failed to create REGEX")); let candidate_len = candidate.len(); @@ -1444,14 +1444,26 @@ mod tests { candidates, vec!["LinkTitle](link\\ _file.txt)", "link\\ _file.txt",] ); - // - // Square brackets not strictly necessary + // Parentheses without preceding `]` should not extract inner content, + // to avoid matching function calls like `do_work(file2)` as file paths. let candidates: Vec = link_pattern_file_candidates("(link_file.txt)") .into_iter() .map(|(c, _)| c) .collect(); + assert_eq!(candidates, vec!["(link_file.txt)"]); - assert_eq!(candidates, vec!["(link_file.txt)", "link_file.txt",]); + let candidates: Vec = link_pattern_file_candidates("do_work(file2);") + .into_iter() + .map(|(c, _)| c) + .collect(); + assert_eq!(candidates, vec!["do_work(file2);"]); + + // Markdown links should still extract the path + let candidates: Vec = link_pattern_file_candidates("](readme.md)") + .into_iter() + .map(|(c, _)| c) + .collect(); + assert_eq!(candidates, vec!["](readme.md)", "readme.md"]); // No nesting let candidates: Vec =