From 61b9c0f5d7d3cd927accfbd396bc8f4758af3220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Menu?= Date: Thu, 14 Jul 2022 16:05:28 +0200 Subject: [PATCH] LSP: Fix finding backlink references for notes in a folder (#245) --- CHANGELOG.md | 7 ++++++- internal/adapter/lsp/document.go | 22 +++++++++++++++++++--- internal/adapter/lsp/server.go | 29 ++++++++++++++++------------- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16ad449..6d4420e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,12 @@ All notable changes to this project will be documented in this file. - +## Unreleased + +### Fixed + +* [#243](https://github.com/mickael-menu/zk/issues/243) LSP: Fixed finding backlink references for notes in a folder. + ## 0.11.1 diff --git a/internal/adapter/lsp/document.go b/internal/adapter/lsp/document.go index f3fe1c8..fbe6d3d 100644 --- a/internal/adapter/lsp/document.go +++ b/internal/adapter/lsp/document.go @@ -2,6 +2,7 @@ package lsp import ( "net/url" + "path/filepath" "regexp" "strings" @@ -159,6 +160,19 @@ func (d *document) LookForward(pos protocol.Position, length int) string { var wikiLinkRegex = regexp.MustCompile(`\[?\[\[(.+?)(?: *\| *(.+?))?\]\]`) var markdownLinkRegex = regexp.MustCompile(`\[([^\]]+?[^\\])\]\((.+?[^\\])\)`) +// LinkFromRoot returns a Link to this document from the root of the given +// notebook. +func (d *document) LinkFromRoot(nb *core.Notebook) (*documentLink, error) { + href, err := nb.RelPath(d.Path) + if err != nil { + return nil, err + } + return &documentLink{ + Href: href, + RelativeToDir: nb.Path, + }, nil +} + // DocumentLinkAt returns the internal or external link found in the document // at the given position. func (d *document) DocumentLinkAt(pos protocol.Position) (*documentLink, error) { @@ -194,7 +208,8 @@ func (d *document) DocumentLinks() ([]documentLink, error) { end = strutil.ByteIndexToRuneIndex(line, end) links = append(links, documentLink{ - Href: href, + Href: href, + RelativeToDir: filepath.Dir(d.Path), Range: protocol.Range{ Start: protocol.Position{ Line: protocol.UInteger(lineIndex), @@ -257,8 +272,9 @@ func (d *document) IsTagPosition(position protocol.Position, noteContentParser c } type documentLink struct { - Href string - Range protocol.Range + Href string + RelativeToDir string + Range protocol.Range // HasTitle indicates whether this link has a title information. For // example [[filename]] doesn't but [[filename|title]] does. HasTitle bool diff --git a/internal/adapter/lsp/server.go b/internal/adapter/lsp/server.go index c41ef10..6f5511c 100644 --- a/internal/adapter/lsp/server.go +++ b/internal/adapter/lsp/server.go @@ -238,7 +238,7 @@ func NewServer(opts ServerOpts) *Server { return nil, err } - target, err := server.noteForLink(*link, doc, notebook) + target, err := server.noteForLink(*link, notebook) if err != nil || target == nil { return nil, err } @@ -281,7 +281,7 @@ func NewServer(opts ServerOpts) *Server { documentLinks := []protocol.DocumentLink{} for _, link := range links { - target, err := server.noteForLink(link, doc, notebook) + target, err := server.noteForLink(link, notebook) if target == nil || err != nil { continue } @@ -311,7 +311,7 @@ func NewServer(opts ServerOpts) *Server { return nil, err } - target, err := server.noteForLink(*link, doc, notebook) + target, err := server.noteForLink(*link, notebook) if link == nil || target == nil || err != nil { return nil, err } @@ -442,14 +442,13 @@ func NewServer(opts ServerOpts) *Server { return nil, err } if link == nil { - href, err := notebook.RelPath(doc.Path) + link, err = doc.LinkFromRoot(notebook) if err != nil { return nil, err } - link = &documentLink{Href: href} } - target, err := server.noteForLink(*link, doc, notebook) + target, err := server.noteForLink(*link, notebook) if link == nil || target == nil || err != nil { return nil, err } @@ -510,14 +509,14 @@ func (s *Server) notebookOf(doc *document) (*core.Notebook, error) { return s.notebooks.Open(doc.Path) } -// noteForLink returns the LSP documentUri for the note targeted by the given link. +// noteForLink returns the Note object for the note targeted by the given link. // // Match by order of precedence: // 1. Prefix of relative path // 2. Find any occurrence of the href in a note path (substring) // 3. Match the href as a term in the note titles -func (s *Server) noteForLink(link documentLink, doc *document, notebook *core.Notebook) (*Note, error) { - note, err := s.noteForHref(link.Href, doc, notebook) +func (s *Server) noteForLink(link documentLink, notebook *core.Notebook) (*Note, error) { + note, err := s.noteForHref(link.Href, link.RelativeToDir, notebook) if note == nil && err == nil && link.IsWikiLink { // Try to find a partial href match. note, err = notebook.FindByHref(link.Href, true) @@ -530,13 +529,17 @@ func (s *Server) noteForLink(link documentLink, doc *document, notebook *core.No return &Note{*note, pathToURI(joined_path)}, nil } -// noteForHref returns the LSP documentUri for the note targeted by the given HREF. -func (s *Server) noteForHref(href string, doc *document, notebook *core.Notebook) (*core.MinimalNote, error) { +// noteForHref returns the Note object for the note targeted by the given HREF +// relative to relativeToDir. +func (s *Server) noteForHref(href string, relativeToDir string, notebook *core.Notebook) (*core.MinimalNote, error) { if strutil.IsURL(href) { return nil, nil } - path := filepath.Clean(filepath.Join(filepath.Dir(doc.Path), href)) + path := href + if relativeToDir != "" { + path = filepath.Clean(filepath.Join(relativeToDir, path)) + } path, err := filepath.Rel(notebook.Path, path) if err != nil { return nil, errors.Wrapf(err, "failed to resolve href: %s", href) @@ -588,7 +591,7 @@ func (s *Server) refreshDiagnosticsOfDocument(doc *document, notify glsp.NotifyF if strutil.IsURL(link.Href) { continue } - target, err := s.noteForLink(link, doc, notebook) + target, err := s.noteForLink(link, notebook) if err != nil { s.logger.Err(err) continue