fix(lsp): resolve wikilinks source-relative first, with .. collapsing
`[[llm-wiki-pattern]]` in `tips/index.wiki` should resolve to
`tips/llm-wiki-pattern.wiki` — vimwiki's default is source-relative
for non-absolute targets. The index keyed every page by its
workspace-relative path, so the link looked up `llm-wiki-pattern`
(root-relative) and missed the sibling. Goto-definition then
synthesised a non-existent root URL, and `nuwiki.link` diagnostics
flagged every such link as missing-page.
- `WorkspaceIndex::resolve_wiki_path` and `page_for_wiki_target`
centralise the lookup: try `{source_dir}/{path}` first, fall back
to root-relative. Used by goto-definition, diagnostics, and the
workspace `checkLinks` walker.
- `collapse_dots` resolves `.` / `..` segments before lookup so
`[[../Other]]` from `posts/foo` correctly hits `Other` at the
wiki root (and is reported broken if no such page exists, rather
than silently going to nowhere).
- `canonical_link_name` applies the same rule when keying the
backlinks index, so backlinks queried by the resolved page name
pick up references that were written source-relative.
- `OutgoingLink` carries `is_absolute` now so `classify_outgoing`
(driven from cached index data, not the live AST) gets the same
treatment without re-parsing the source.
- `classify_outgoing`'s File/Local branch now reuses
`resolve_file_path` instead of duplicating the `//absolute` /
relative-to-source logic inline.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -166,9 +166,7 @@ pub fn classify_link(
|
||||
match link.target.kind {
|
||||
LinkKind::Wiki => {
|
||||
let path = link.target.path.as_deref()?;
|
||||
let normalized = index.strip_link_extension(path);
|
||||
let page = index.page_by_name(normalized);
|
||||
match page {
|
||||
match index.page_for_wiki_target(path, source_page, link.target.is_absolute) {
|
||||
None => Some(BrokenLinkKind::MissingPage(path.to_string())),
|
||||
Some(page) => {
|
||||
if let Some(anchor) = &link.target.anchor {
|
||||
@@ -229,8 +227,7 @@ pub fn classify_outgoing(
|
||||
match link.kind {
|
||||
LinkKind::Wiki => {
|
||||
let path = link.target_page.as_deref()?;
|
||||
let normalized = index.strip_link_extension(path);
|
||||
match index.page_by_name(normalized) {
|
||||
match index.page_for_wiki_target(path, source_page, link.is_absolute) {
|
||||
None => Some(BrokenLinkKind::MissingPage(path.to_string())),
|
||||
Some(page) => {
|
||||
if let Some(anchor) = &link.anchor {
|
||||
@@ -262,23 +259,7 @@ pub fn classify_outgoing(
|
||||
}
|
||||
LinkKind::File | LinkKind::Local => {
|
||||
let path = link.target_page.as_deref()?;
|
||||
// OutgoingLink doesn't carry `is_absolute`; recover from the
|
||||
// string itself — `//path` and any other root-anchored form
|
||||
// start with `/`. Anything else is relative to the source URI's
|
||||
// parent directory.
|
||||
let candidate = PathBuf::from(path);
|
||||
let resolved = if candidate.is_absolute() {
|
||||
candidate
|
||||
} else if let Ok(base) = source_uri.to_file_path() {
|
||||
match base.parent() {
|
||||
Some(dir) => dir.join(&candidate),
|
||||
None => candidate,
|
||||
}
|
||||
} else if let Some(root) = index.root.as_ref() {
|
||||
root.join(&candidate)
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
let resolved = resolve_file_path(Some(source_uri), index, path, link.is_absolute)?;
|
||||
if resolved.exists() {
|
||||
None
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user