From fcce5621a072ab16bffdcedbf04e626dd383cabc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Fr=C3=B3es=20Franco?= Date: Sun, 7 Jun 2026 14:29:41 +0000 Subject: [PATCH] fix(lsp): resolve links from anywhere in the link, including the title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit goto-definition (and references/hover) reported "No locations found" when the cursor was on the *description* of a piped link — `[[target|Title]]` or `[desc](url)` — and only worked over the target/location part. find_in_inlines descended into the link's description and returned its inner Text node, so the nav handlers saw a Text (not a WikiLink/ ExternalLink) and bailed. A link is an atomic unit for navigation: stop descending into descriptions so a hit anywhere in the link returns the link node itself. Adds a navigation regression test for cursor-on-title. Co-Authored-By: Claude Opus 4.8 --- crates/nuwiki-lsp/src/nav.rs | 13 +++++-------- crates/nuwiki-lsp/tests/navigation.rs | 12 ++++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/crates/nuwiki-lsp/src/nav.rs b/crates/nuwiki-lsp/src/nav.rs index bf7ea39..22587d9 100644 --- a/crates/nuwiki-lsp/src/nav.rs +++ b/crates/nuwiki-lsp/src/nav.rs @@ -106,14 +106,11 @@ fn find_in_inlines(inlines: &[InlineNode], line: u32, col: u32) -> Option<&Inlin InlineNode::Superscript(s) => find_in_inlines(&s.children, line, col), InlineNode::Subscript(s) => find_in_inlines(&s.children, line, col), InlineNode::Color(c) => find_in_inlines(&c.children, line, col), - InlineNode::WikiLink(w) => w - .description - .as_ref() - .and_then(|d| find_in_inlines(d, line, col)), - InlineNode::ExternalLink(e) => e - .description - .as_ref() - .and_then(|d| find_in_inlines(d, line, col)), + // Links are an atomic unit for navigation: a cursor anywhere in + // `[[target|description]]` (or `[desc](url)`) should resolve the + // link itself. Don't descend into the description — returning its + // inner Text node leaves goto-definition/references/hover with + // nothing to act on ("No locations found" when on the title). _ => None, }; return Some(deeper.unwrap_or(n)); diff --git a/crates/nuwiki-lsp/tests/navigation.rs b/crates/nuwiki-lsp/tests/navigation.rs index e5ea3e8..f0e9e8b 100644 --- a/crates/nuwiki-lsp/tests/navigation.rs +++ b/crates/nuwiki-lsp/tests/navigation.rs @@ -201,6 +201,18 @@ fn find_inline_at_returns_wikilink_under_cursor() { assert!(matches!(node, InlineNode::WikiLink(_))); } +#[test] +fn find_inline_at_returns_wikilink_when_cursor_on_description() { + // Regression: pressing on the *title* part of a piped link used to + // descend into the description's Text node, so goto-definition saw a Text + // (not a WikiLink) and reported "No locations found". + let src = "see [[Other|My Title]] now\n"; + let doc = parse(src); + // Byte col 16 is inside "Title" (the description), past the '|' at 11. + let node = find_inline_at(&doc, 0, 16).expect("wikilink at cursor"); + assert!(matches!(node, InlineNode::WikiLink(_))); +} + #[test] fn find_inline_at_returns_none_for_plain_text() { let src = "just text\n";