zk-org / zk

A plain text note-taking assistant

Home Page:https://zk-org.github.io/zk/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Providing a Language Server (LSP)

mickael-menu opened this issue · comments

zk can provide a basic integration with any LSP-compatible text editor by shipping a Language Server.

PR #21 implements a proof of concept server showing promising results, but there's more to come:

  • Links

    • Auto-complete internal Markdown links with [[
    • Auto-complete the path portion of a Markdown link with [custom title]((
    • User configuration to specify the link format using a template
    • Open a note from an inline Markdown link or WikiLink (document link when supported and go to definition as an alternative)
    • Open a website from an inline external Markdown link (with textDocument/documentLink)
    • Open a reference link
    • Move the caret to the next link in the note with a code action, for quick navigation (with window.showDocument)
    • Preview the content of a linked note with a hover
    • Diagnostic (error) to show dead links
    • Diagnostic (hint) to show the title of a linked note next to the link
    • Browse backlinks with find references
    • Browse backlinks / outbound links with a tree-like call hierarchy (client support is still lacking)
    • Highlight WikiLinks using semantic tokens (client support is still lacking)
    • (Maybe?) Report DocumentLink for unlinked mentions, using aliases metadata
  • Tags

    • Auto-complete tags with # and : trigger characters
    • Rename a tag with a refactor code action
    • Highlight tags using semantic tokens (client support is still lacking)
    • View the list of all the notes for a particular tag when running the References action.
  • Notes

    • Code action to create (and link) a new note using the current selection as its title
    • Code action to create (and link) a new note using the current selection as its content (refactor.extract?)
    • Code action to rename the note title
    • User configuration to declare dynamic code actions to generate notes with custom group / template
    • Snippet support using zk templates
  • Expose zk commands as LSP commands, for easy client-side consumption

    • zk.init to create a new notebook
    • zk.index to index a notebook manually
    • zk.new to create a new note
    • zk.list to search for notes (returning a JSON)
    • zk.tag.list to return the list of tags
    • zk.info to provide detailed JSON metadata about a notebook (list of groups, templates, dirs, etc.)
  • Other

    • Optimizations for large (10k+) notebooks (esp. completion)

Feel free to share more ideas!

Tested this out, it's very cool!

I am seeing an issue using go to definition with neovim builtin lsp, but i'm not sure if that's a neovim problem or a zk problem. The error is Error executing vim.schedule lua callback: ...stalls/neovim/nightly/share/nvim/runtime/lua/vim/uri.lua:116: attempt to call method 'match' (a nil value)

Log
2021/04/04 21:00:24.323 DEBUG [zk.rpc] jsonrpc2: <-- result #26: textDocument/definit
ion: {"uri":{"start":{"line":7,"character":0},"end":{"line":7,"character":8}},"target
Uri":"file:///Users/mitchell/Dropbox/notes/zk/gznd.md","targetRange":{"start":{"line"
:0,"character":0},"end":{"line":0,"character":0}},"targetSelectionRage":{"start":{"li
ne":0,"character":0},"end":{"line":0,"character":0}}}

@mhanberg It was actually caused by a bug in a third-party dependency. I opened a PR but forgot to disable the faulty portion in zk. You can try again from the latest main or the following pre-built binaries:

Btw, I tried the builtin LSP but couldn't make the trigger characters work for the completion. Did you setup anything special for this?

I updated and go to def works now 👍.

Btw, I tried the builtin LSP but couldn't make the trigger characters work for the completion. Did you setup anything special for this?

I use nvim-compe for completion.

@mickael-menu first off, this is so great!

I've been using it with nvim-compe along with @mhanberg, too.

A couple items I've noticed.

  1. When attempting to initiate auto-complete of files with [[ or [ depending on the mode you want, it doesn't complete the file extension, which then breaks go to definition, as soon as I manually add the the file extension, go to definition works as expected.
  2. This is more of a question/confirmation of expected behaviour (the above might also be that, too); when auto-completing tags, should the \ escaping of space be converted back to ?

Other than those two minor items, this has been fantastic to use!

@megalithic

  1. When attempting to initiate auto-complete of files with [[ or [ depending on the mode you want, it doesn't complete the file extension, which then breaks go to definition, as soon as I manually add the the file extension, go to definition works as expected.

I set up the links for my own usage and I usually prefer to omit the extension. But I'll let users configure the format of the generated links in the config later on.

However, the link href is matched as a prefix of the actual path, so it should work without the extension or if you have a unique ID prefix. For example, [[202005201056]] would match 202005201056 Interesting subject.md. Could you share an example of link + note path pair which doesn't work? And what do you see in the LSP logs?

  1. This is more of a question/confirmation of expected behaviour (the above might also be that, too); when auto-completing tags, should the \ escaping of space be converted back to ?

This is expected, because a normal #hashtag can't contain spaces, so I added this ad-hoc escape syntax if an existing tag contains spaces. But if you enable Bear's multi-word tags syntax in the config, instead of using \ escape character the completed tag will be like #multi-word tag#
What tag syntax did you use so far supporting spaces?

Thanks @mickael-menu .. I'm still playing around with this to get a repro case for you. I think I might be using something wrong; meaning, I'm looking to be able to [[ then rely on "friendly" titles to complete on. I've also noticed that not all items in my main notebook are showing up in the completion menu. I'll get a loom or something going to demonstrate today.

Ahh, I'm wondering if certain characters in a filename or title might be breaking completion? |, :, and & are command items in some of my note file names and titles (i auto-extract calendar titles and use those from meeting note generation and pass that along to zk.nvim to generate the note, or open an existing note with the same file name).

Will check the logs to verify this.

When searching for a note (using zk edit --interactive via cli, not abstracted out via zk.nvim) that does contain one of the above characters, these are throw into the preview area of fzf:

image

I think I might be using something wrong; meaning, I'm looking to be able to [[ then rely on "friendly" titles to complete on

Yes right now the completion is on the note title (heading or YAML frontmatter) and not on the file path. I intend to add both in the completion filter later.

I'll open a new issue for the special characters.

Go to definition seems to be working when the current note is in the root of the notebook, but not when the note is in a sub-directory. I noticed this when implementing the "daily journal" example from the docs.

@mhanberg Thanks for spotting that, should be fixed in main

zk-v0.3.0-5-gdd561be-macos-arm64.zip

I merged in a way to specify the completion link format from the user configuration: #32

[format.markdown]
# Format used to generate links between notes.
# Either "wiki", "markdown" or a custom template. Default is "markdown".
link-format = "wiki"
# Indicates whether a link's path will be percent-encoded.
link-encode-path = false
# Indicates whether a link's path file extension will be removed.
link-drop-extension = true

Incidentally, internal link completion is triggered only with [[ now, not a single [. You need to setup your preferred link syntax in the zk config.

@mickael-menu .. one thing i've noticed recently (not sure if it's a zk lsp implementation or related to neovim's lspconfig and native LS client implementation), is that when trying to "select" a completion item that has spaces it will break the selection and you'll end up with just First\ instead of First\ Word or First Word. Is this something that a.) works on coc.nvim; and b.) works for you with nvim-lspconfig and nvim's native lsp client implementation, that you've seen?

Thanks!

Oh man, update; turns out bullets.vim was the culprit :( that's a bummer.

Soooo.. please ignore my above question. <CR> selection on an autocomplete item that has spaces, works just fine. :)

Ha that's interesting because I actually had the same issue with coc.nvim, which was considering spaces as the end of the completion item for some reason. I had to set this in its settings to make it work:

{
  // Important, otherwise link completion containing spaces and other special characters won't work.
  "suggest.invalidInsertCharacters": []
}

I created a Visual Studio Code client extension for zk, available at https://github.com/mickael-menu/zk-vscode

In case anyone else gets stuck when using Pandoc in Vim, just add get_language_id = function() return 'markdown' end to your config (for Neovim's built-in LSP). This forces the filetype that get passed to the LSP as markdown (otherwise it will send markdown.pandoc) so that the LSP can work.

E.g:

configs.zkls = {
  default_config = {
     cmd = {'zk', 'lsp', '--log', '/tmp/zk-lsp.log'},
     filetypes = {'markdown', 'markdown.pandoc'},
     get_language_id = function() return 'markdown' end,  -- force language ID to markdown so that LS will work
     root_dir = function() return vim.loop.cwd() end,
     settings = {},
  };
}

On a related note, does filtering the tag/note auto-completion work? If I enter the trigger character (# or [[), I get a popup with all my tags/notes, but as soon as I start typing to "filter" through the list, I just get normal (non-LSP) auto-completion. I'm using the built-in Neovim LSP client and nvim-compe, so not sure if it's an issue with one of them?

@ZachariasLenz Thanks, I'll add this to the documentation!

On a related note, does filtering the tag/note auto-completion work?

It depends what you expect but with coc.nvim I can filter though the auto-completion list with fuzzy-matching. It matches the notes' title and their path (which is hidden from the completion items).

as soon as I start typing to "filter" through the list, I just get normal (non-LSP) auto-completion

I'm not sure what you mean by non-LSP auto-completion? Would you be able to record a screencast?

@mickael-menu see the screencast for an example of what I mean:

scrrencast_lsp_completion.mp4

@ZachariasLenz Thanks, this definitely doesn't look right. I'm not sure what could be the problem as I'm not using NeoVim's built-in LSP yet. Do you have any idea @megalithic?

(Nice color scheme ;))

Here's how it looks like with coc.nvim
zk-autocomplete2.mov

I just merged some pretty exciting new LSP features.

I added two code actions to create a new note using the text selection as title. Either in the current directory, or the root/top directory. It will convert the selection to a link to the newly created note.

This feature builds on new custom LSP commands: zk.index and zk.new. Using your editor's API, you can directly call these commands which can be used to create keybindings around various note creation use cases. Here's a screencast:

lsp-actions.mov

You will need a bit of configuration to add user commands and shortcuts exposing zk.index and zk.new.

This is my coc.nvim config:

~/.config/nvim/init.vim
command! -nargs=0 ZkIndex :call CocAction("runCommand", "zk.index", expand("%:p"))
command! -nargs=? ZkNew :exec "edit ".CocAction("runCommand", "zk.new", expand("%:p"), <args>).path

nnoremap <leader>zi :ZkIndex<CR>
nnoremap <leader>zn :ZkNew {"title": input("Title: ")}<CR>
nnoremap <leader>zl :ZkNew {"dir": "log"}<CR>

(Note the cool keybinding which prompts for a title: nnoremap <leader>zn :ZkNew {"title": input("Title: ")}<CR>)

And here's with built-in Neovim LSP client:

~/.config/nvim/init.vim
command! -nargs=0 ZkIndex :lua require'lspconfig'.zk.index()
command! -nargs=? ZkNew :lua require'lspconfig'.zk.new(<args>)

lua << EOF

local lspconfig = require'lspconfig'
local configs = require'lspconfig/configs'

configs.zk = {
  default_config = {
    cmd = {'zk', 'lsp'};
    filetypes = {'markdown'};
    root_dir = lspconfig.util.root_pattern('.zk');
    settings = {};
  };
}

configs.zk.index = function()
  vim.lsp.buf.execute_command({
    command = "zk.index",
    arguments = {vim.api.nvim_buf_get_name(0)},
  })
end

configs.zk.new = function(...)
  vim.lsp.buf_request(0, 'workspace/executeCommand',
    {
        command = "zk.new",
        arguments = {
            vim.api.nvim_buf_get_name(0),
            ...
        },
    },
    function(_, _, result)
      if not (result and result.path) then return end
      vim.cmd("edit " .. result.path)
    end
  )
end

lspconfig.zk.setup({
  on_attach = function(client, bufnr)
    -- Key mappings
    local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
    local opts = { noremap=true, silent=true }
    buf_set_keymap("n", "<CR>", "<cmd>lua vim.lsp.buf.definition()<CR>", opts)
    buf_set_keymap("n", "K", "<cmd>lua vim.lsp.buf.hover()<CR>", opts)
    buf_set_keymap("n", "<leader>zi", ":ZkIndex<CR>", opts)
    buf_set_keymap("v", "<leader>zn", ":'<,'>lua vim.lsp.buf.range_code_action()<CR>", opts)
    buf_set_keymap("n", "<leader>zn", ":ZkNew {title = vim.fn.input('Title: ')}<CR>", opts)
    buf_set_keymap("n", "<leader>zl", ":ZkNew {dir = 'log'}<CR>", opts)
  end
})
EOF

zk now reports diagnostics for dead links and wiki-link titles.

The wiki-link titles are particularly useful with Neovim's 0.5 built-in LSP client, as they are displayed as virtual text. However I disabled this diagnostic by default as it's not so useful for other editors. You need to enable it in your zk config:

[lsp.diagnostics]
# Report titles of wiki-links as hints.
wiki-title = "hint"

Here's a screenshot after customizing the colors:

~/.config/nvim/init.vim
highlight LspDiagnosticsDefaultError ctermfg=red guifg=red
highlight LspDiagnosticsUnderlineError ctermfg=red guifg=red
highlight LspDiagnosticsDefaultHint ctermfg=yellow guifg=yellow
highlight LspDiagnosticsUnderlineHint cterm=none gui=none

Screenshot 2021-05-16 at 21 44 05

(Note the cool keybinding which prompts for a title: nnoremap <leader>zn :ZkNew {"title": input("Title: ")}<CR>)

I'm able to get the zn command to work, including the prompt for a title. However, there appears to be no sign of the entered title once the note is created (see recording below)

Screen.Recording.2021-05-17.at.11.33.27.mov

I suspect I might be doing something wrong ...

@jrekier Looks like your template is empty. In my zk notebook I have:

  • .zk/config.toml
    [note]
    template = "default.md"
  • .zk/templates/default.md
    # {{title}}
    
    {{content}}

You can find the available placeholders for the templates in the documentation.

indeed ... thanks !

Now I understand the use of templates better. Changed mine to use yml front matter:

  • .zk/templates/default.md
---
title: {{title}}
---
{{content}}

and it works wonders.
Cheers

Btw I found out that we can display diagnostics as virtual text with coc.nvim too, if you don't want to upgrade to Neovim 0.5.

Screenshot 2021-05-17 at 11 54 07

You will need this in :CocConfig:

  "diagnostic.virtualText": true,
  "diagnostic.virtualTextCurrentLineOnly": false

Also I suggest using quotes around your title if you use a YAML front matter, as special characters might throw off the parser.

Will there be auto completion for full markdown links as well? [ should trigger auto complete for markdown links with the canonical title as text and path filled in correctly as url

It also looks like [[ links get auto-completed with a third [ is this on purpose? And is there any way to autocomplete the filename instead of the note title?

And why do we need two ( (](() to trigger markdown path completion? The path completion itself also doesn't seem to work for me. I get all the options but when I select one, nothing happens.

(I'm working in neovim so it could be editor specific)

Will there be auto completion for full markdown links as well? [ should trigger auto complete for markdown links with the canonical title as text and path filled in correctly as url

Yes it's available already, but it is still triggered by [[ as I think it would be undesirable to have the auto-completion activated for any normal Markdown link (including external links, image embedding, etc.). You need to customize the link format generated in your config file.

[format.markdown]
link-format = "markdown"
link-drop-extension = true
link-encode-path = true

However you can have only a single link format completed with [[, so it wouldn't be very useful if you are mixing Wiki-links and regular Markdown links, for internal links. Is it something you need? Can you explain more your usage if it's the case?

It also looks like [[ links get auto-completed with a third [ is this on purpose?

No, but if you are using completion-nvim, I noticed it is not applying LSP's additionalTextEdits despite claiming it which is supposed to remove the extra [[. Maybe I missed something in the config. I actually have a lead that I could explore for this but it requires Neovim-specific LSP handler. Until then, nvim-compe or coc.nvim should work properly.

And is there any way to autocomplete the filename instead of the note title?

I'm adding the path to LSP's filterText which should let the editor filter-complete with the path too, even if it is not visible in the completion pop-up. However again this is highly dependent on your editor/plugins. Coc.nvim has been the most reliable for me as it implements a lot of the LSP spec.

However, I could see how it would be interesting to be able to customize the label of the completion pop-up. I'll think about it.

And why do we need two ( (](() to trigger markdown path completion? The path completion itself also doesn't seem to work for me.

This is actually an alternative to [[. Personally I only use regular markdown links and no wiki-links. Sometime I want to link to a note using its title, so I'll call [[. But often I want to customize the title of the link to put it in context of the current note. In this case I will type [custom title](( and this will complete the path to other notes without replacing my custom title.

I used (( for the same reason as using [[ instead of a single [: prevent triggering the completion when I don't want to link to an internal note.

I get all the options but when I select one, nothing happens.

Probably an editor/config issue, I noticed this issue sometime with conflicting plugins in Neovim.

Okay, I didn't know about these settings! And with nvim-compe it seems to work much better indeed.

I understand the philosophy better now and while I don't fully agree, I can live with it and it kinda makes sense 👍

Thanks for the extraordinary detailed help!

Hello, I'm the creator of a basic lsp for my Zettelkasten purposes : https://github.com/lsp-zettelkasten/lsp-zettelkasten
It seems we have a lot to share in common (hello @mickael-menu 😃 )!

I initially wanted a fully independent LSP for managing my notes. As I switched from obsidian to Neovim, I lost some good stuff such as automatic linking completion, tags management, etc.

I created the LSP aiming to allow the user to use it without installing something more than the server

I did managed to create the option to create links on the fly, by typing [[.

I'm now stuck at creating a tree-sitter parser for recognizing the links and tags, allowing me to propose tags based on current ones, and find links more quickly.

I love the idea of this lsp, which is leveraging the zk utility. Nevertheless, I would love to see a fully independent lsp emerge, from your lsp implementation (👋🏻 @mickael-menu ), mine, or a merge from both.

I'm open at helping and receiving help, because I'm convinced that what matters most is a centralized and participative implementation for the good of us, knowledge workers.

I have some ideas about leveraging tree-sitter in order to handle tags, highlighting, for our zettelkastens. Feel free to contact me at daniel.mathiot@insa-cvl.fr or here below.

Sincerely,
Daniel

Thanks for chiming in @danymat.

I love the idea of this lsp, which is leveraging the zk utility. Nevertheless, I would love to see a fully independent lsp emerge, from your lsp implementation (👋🏻 @mickael-menu ), mine, or a merge from both.

I definitely thinks there's room for several Zettelkasten-based LSP servers. Especially since our two implementations are quite different. Mine is heavier since it relies on a local database index, but most likely performs better on larger Zettelkästen. It makes sense too when using other zk features such as note generation. But there's definitely value in a more lightweight approach working out-of-the-box.

I'm open at helping and receiving help, because I'm convinced that what matters most is a centralized and participative implementation for the good of us, knowledge workers.

Feel free to take a look at how I solved particular problems regarding the LSP spec, and I would love to hear your ideas too if you tackled things differently. We're a bit in uncharted territory for LSP+Zettelkasten and there's room for interpretation with the LSP spec.

Like I said I think that's even better to have several implementations. One thing we need to communicate on IMHO is more on the Markdown syntax extensions and maybe on LSP details such as the completion trigger characters. Obsidian and Neuron are extending the default Markdown syntax for custom needs and there's a real risk to grow incompatible Zettelkasten formats. Since we're all here for the "future-proof" advantage Markdown brings, we need to be careful.

I have some ideas about leveraging tree-sitter in order to handle tags, highlighting, for our zettelkastens. Feel free to contact me at daniel.mathiot@insa-cvl.fr or here below.

I'd like to keep this issue focused on zk's LSP implementation. But if anyone wants to participate, you can open issues on Daniel's repository.

Hi. I'm having trouble in using autocomplete. Please help.
I'm using neovim 0.5 and have tried both nvim-compe and completion-nvim.

Say I want to complete the title sample file whose filename is 123abc.md. There are two ways

  1. [[ and then type sam.. and select the file using <CR>. This I expect to give [sample file](123abc.md) or equivalent.
  2. [Link](( and then sam.. and again select similarly. This I expect to give [Link](123abc.md) or equivalent.

For me, when I use nvim-compe, while I can trigger completion, when I press <CR> after selection, the filename doesn't complete. That is,

  • 1 gives [[sample (nothing more)
  • 2 gives [Link]((sample (not even the filename)

I have tried using compe#confirm mapping. Either way result is same.

With completion-nvim, <CR> creates the link [Link](((123abc.md) almost correctly if I select sample file by scrolling, but as soon as I type anything to filter the list, the completion popup window vanishes, forcing me to always scroll.

@physicophilic Hard to say, from my limited experience so far the various Neovim completion solutions are easy to break with conflicting settings. I would suggest stripping down your init.vim until you have something that works.

I'm not sure if this is the right place, but it seems most relevant. I'm trying to get zk working with vim and lsp and can't seem to get things setup correctly.

Changing the nvim versions, the lsp implemenation, and the coc.nvim to dev have made no difference. My autocomplete always leaves extrea "[[" in front of links. I've tried Markdown links and Wiki Links and both still do it. I haven't gotten hotkeys to follow links working yet, but I've been focused on getting correct link completion first.

I've compiled nvim from upstream based on megalithic/zk.nvim#25 (comment)
I've also switched coc.nvim to the master rather than release branch
I've removed basically all addons so that I'm just testing zk with a lsp. I started with the built in vim lsp but switched to coc.nvim as it seemed people were saying it was getting faster updates and I actually like some of the other things it can provide.

This is my full init.vim

call plug#begin()
" Color
Plug 'NLKNguyen/papercolor-theme'

" Coc.nvim
Plug 'neoclide/coc.nvim', {'branch': 'master', 'do': 'yarn install --frozen-lockfile'}

call plug#end()
" Done with plugins

" GUI Options
:set guioptions-=m  "remove menu bar
:set guioptions-=T  "remove toolbar
:set guioptions-=r  "remove right-hand scroll bar
:set guioptions-=L  "remove left-hand scroll bar

" Papercolor
set background=dark
colorscheme PaperColor

" Coc
let g:coc_global_extensions = ['coc-json', 'coc-git', 'coc-tsserver', 'coc-sh', 'coc-yaml']

"zk
" User command to index the current notebook.
"
" zk.index expects a notebook path as first argument, so we provide the current
" buffer path with expand("%:p").
command! -nargs=0 ZkIndex :call CocAction("runCommand", "zk.index", expand("%:p"))
nnoremap <leader>zi :ZkIndex<CR>

" User command to create and open a new note, to be called like this:
" :ZkNew {"title": "An interesting subject", "dir": "inbox", ...}
"
" Note the concatenation with the "edit" command to open the note right away.
command! -nargs=? ZkNew :exec "edit ".CocAction("runCommand", "zk.new", expand("%:p"), <args>).path

" Create a new note after prompting for its title.
nnoremap <leader>zn :ZkNew {"title": input("Title: ")}<CR>
" Create a new note in the directory journal/daily.
nnoremap <leader>zj :ZkNew {"dir": "journal/daily"}<CR>

" Faster gutter updates for git
set updatetime=100

" Setup hybrid line numbers
set number
set relativenumber

" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %

Versions:

vim --version
NVIM v0.6.0-dev+111-gf22326ef0
Build type: Debug
LuaJIT 2.1.0-beta3
Compilation: /usr/bin/cc -DNVIM_TS_HAS_SET_MATCH_LIMIT -g -Wall -Wextra -pedantic -Wno-unused-parameter -Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion -Wmissing-prototypes -Wimplicit-fallthrough -Wvla -fstack-protector-strong -fno-common -fdiagnostics-color=always -DINCLUDE_GENERATED_DECLARATIONS -D_GNU_SOURCE -DNVIM_MSGPACK_HAS_FLOAT32 -DNVIM_UNIBI_HAS_VAR_FROM -DMIN_LOG_LEVEL=1 -I/home/chris/src/neovim/build/config -I/home/chris/src/neovim/src -I/home/chris/src/neovim/.deps/usr/include -I/usr/include -I/home/chris/src/neovim/build/src/nvim/auto -I/home/chris/src/neovim/build/include
Compiled by chris@x1c

zk --version
zk 0.6.0-2-g977625b

coc.nvim:
commit 170b5fd2d904c0e9a7ace394510687447809d8dd

coc-settings.json

{
  // Important, otherwise link completion containing spaces and other special characters won't work.
  "suggest.invalidInsertCharacters": [],

  "languageserver": {
    "zk": {
      "command": "zk",
      "args": ["lsp", "--log", "/home/chris/tmp/zk.log"],
      "trace.server": "messages",
      "filetypes": ["markdown"]
    }
  }
}

zk-log from the lsp

2021/08/06 09:59:34.026 DEBUG [zk.rpc] jsonrpc2: --> notif: textDocument/didChange: {"textDocument":{"version":26,"uri":"file:///home/chris/tmp/zk2/lfbt.md"},"contentChanges":[{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":0}},"rangeLength":0,"text":"["}]}
2021/08/06 09:59:34.028 DEBUG [zk.rpc] jsonrpc2: --> request #12: textDocument/completion: {"textDocument":{"uri":"file:///home/chris/tmp/zk2/lfbt.md"},"position":{"line":6,"character":1},"context":{"triggerKind":2,"triggerCharacter":"["}}
2021/08/06 09:59:34.028 DEBUG [zk.rpc] jsonrpc2: <-- result #12: textDocument/completion: null
2021/08/06 09:59:34.155 DEBUG [zk.rpc] jsonrpc2: --> notif: textDocument/didChange: {"textDocument":{"version":27,"uri":"file:///home/chris/tmp/zk2/lfbt.md"},"contentChanges":[{"range":{"start":{"line":6,"character":1},"end":{"line":6,"character":1}},"rangeLength":0,"text":"["}]}
2021/08/06 09:59:34.159 DEBUG [zk.rpc] jsonrpc2: --> request #13: textDocument/completion: {"textDocument":{"uri":"file:///home/chris/tmp/zk2/lfbt.md"},"position":{"line":6,"character":2},"context":{"triggerKind":2,"triggerCharacter":"["}}
2021/08/06 09:59:34.160 DEBUG [zk.rpc] jsonrpc2: <-- result #13: textDocument/completion: [{"label":"Send test","kind":18,"filterText":"Send test lfbt.md","textEdit":{"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":2}},"newText":"[[lfbt]]"},"additionalTextEdits":[{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":2}},"newText":""}],"data":"/home/chris/tmp/zk2/lfbt.md"},{"label":"Test","kind":18,"filterText":"Test lvx3.md","textEdit":{"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":2}},"newText":"[[lvx3]]"},"additionalTextEdits":[{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":2}},"newText":""}],"data":"/home/chris/tmp/zk2/lvx3.md"}]
2021/08/06 09:59:35.027 DEBUG [zk.rpc] jsonrpc2: <-- notif: textDocument/publishDiagnostics: {"uri":"file:///home/chris/tmp/zk2/lfbt.md","diagnostics":[]}
2021/08/06 09:59:36.001 DEBUG [zk.rpc] jsonrpc2: --> request #14: completionItem/resolve: {"label":"Test","kind":18,"filterText":"Test lvx3.md","textEdit":{"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":2}},"newText":"[[lvx3]]"},"additionalTextEdits":[{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":2}},"newText":""}],"data":"/home/chris/tmp/zk2/lvx3.md"}
2021/08/06 09:59:36.001 DEBUG [zk.rpc] jsonrpc2: <-- result #14: completionItem/resolve: {"label":"Test","kind":18,"documentation":{"kind":"markdown","value":"# Test\n\nThis is a test zettel\n\n\n\n"},"filterText":"Test lvx3.md","textEdit":{"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":2}},"newText":"[[lvx3]]"},"additionalTextEdits":[{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":2}},"newText":""}],"data":"/home/chris/tmp/zk2/lvx3.md"}
2021/08/06 09:59:36.080 DEBUG [zk.rpc] jsonrpc2: --> notif: textDocument/didChange: {"textDocument":{"version":28,"uri":"file:///home/chris/tmp/zk2/lfbt.md"},"contentChanges":[{"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":2}},"rangeLength":0,"text":"[[lvx3]]"}]}
2021/08/06 09:59:36.106 DEBUG [zk.rpc] jsonrpc2: --> request #15: completionItem/resolve: {"label":"Send test","kind":18,"filterText":"Send test lfbt.md","textEdit":{"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":2}},"newText":"[[lfbt]]"},"additionalTextEdits":[{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":2}},"newText":""}],"data":"/home/chris/tmp/zk2/lfbt.md"}
2021/08/06 09:59:36.107 DEBUG [zk.rpc] jsonrpc2: <-- result #15: completionItem/resolve: {"label":"Send test","kind":18,"documentation":{"kind":"markdown","value":"# Send test\n\nThis is the 2nd test\n\nBacklinks:\n[[[[lvx3]]\n\n\n\n"},"filterText":"Send test lfbt.md","textEdit":{"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":2}},"newText":"[[lfbt]]"},"additionalTextEdits":[{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":2}},"newText":""}],"data":"/home/chris/tmp/zk2/lfbt.md"}
2021/08/06 09:59:36.184 DEBUG [zk.rpc] jsonrpc2: --> notif: textDocument/didChange: {"textDocument":{"version":29,"uri":"file:///home/chris/tmp/zk2/lfbt.md"},"contentChanges":[{"range":{"start":{"line":6,"character":5},"end":{"line":6,"character":8}},"rangeLength":3,"text":"fbt"}]}
2021/08/06 09:59:37.082 DEBUG [zk.rpc] jsonrpc2: <-- notif: textDocument/publishDiagnostics: {"uri":"file:///home/chris/tmp/zk2/lfbt.md","diagnostics":[{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":10}},"severity":1,"source":"zk","message":"not found"}]}
2021/08/06 09:59:38.035 DEBUG [zk.rpc] jsonrpc2: --> notif: textDocument/didChange: {"textDocument":{"version":30,"uri":"file:///home/chris/tmp/zk2/lfbt.md"},"contentChanges":[{"range":{"start":{"line":7,"character":0},"end":{"line":7,"character":0}},"rangeLength":0,"text":"\n"}]}
2021/08/06 09:59:39.036 DEBUG [zk.rpc] jsonrpc2: <-- notif: textDocument/publishDiagnostics: {"uri":"file:///home/chris/tmp/zk2/lfbt.md","diagnostics":[{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":10}},"severity":1,"source":"zk","message":"not found"}]}

I've finally found it, maybe I missed this in the documentation but from https://github-wiki-see.page/m/neoclide/coc.nvim/wiki/Completion-with-sources

For features like textEdit and additionalTextEdits(mostly used by automatic import feature) of LSP to work, you have to confirm completion, which is by default in vim. Read the next section for example key-mappings.

You can make CR work as expected and confirm with:
inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm() : "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"

@chris-sanders Glad you figured it out yourself. The LSP server is indeed using additionalTextEdits to remove the [[.

Will it be the PR to lsp-config or any instruction for setting it up with nvim lspconfig??

Will it be the PR to lsp-config or any instruction for setting it up with nvim lspconfig??

Probably not a PR to lsp-config, but we're working on a dedicated LSP plugin, see this discussion megalithic/zk.nvim#41

In the meantime, this should get you started:

~/.config/nvim/init.vim
-- Declare some custom Neovim commands as shortcuts to the zk functions.
command! -nargs=0 ZkIndex :lua require'lspconfig'.zk.index()
command! -nargs=? ZkNew :lua require'lspconfig'.zk.new(<args>)

lua << EOF

local lspconfig = require'lspconfig'
local configs = require'lspconfig/configs'

-- Initialize the zk language server
configs.zk = {
  default_config = {
    cmd = {'zk', 'lsp', '--log', '/tmp/zk-lsp.log'};
    filetypes = {'markdown'};
    root_dir = lspconfig.util.root_pattern('.zk');
    settings = {};
  };
}

-- Index the notebook of the current note.
configs.zk.index = function()
  vim.lsp.buf.execute_command({
    command = "zk.index",
    arguments = {vim.api.nvim_buf_get_name(0)},
  })
end

-- Create a new note in the current notebook.
configs.zk.new = function(...)
  vim.lsp.buf_request(0, 'workspace/executeCommand',
    {
        command = "zk.new",
        arguments = {
            vim.api.nvim_buf_get_name(0),
            ...
        },
    },
    function(_, _, result)
      if not (result and result.path) then return end
      vim.cmd("edit " .. result.path)
    end
  )
end

lspconfig.zk.setup({
  on_attach = function(client, bufnr)
    -- Key mappings
    local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
    local opts = { noremap=true, silent=false }
    buf_set_keymap("i", "<S-tab>", "<cmd>lua vim.lsp.buf.completion()<CR>", opts)
    -- Follow a Markdown link with <CR>.
    buf_set_keymap("n", "<CR>", "<cmd>lua vim.lsp.buf.definition()<CR>", opts)
    -- Preview a note with K when the cursor is on a link.
    buf_set_keymap("n", "K", "<cmd>lua vim.lsp.buf.hover()<CR>", opts)
    -- Create a new note using the current visual selection for the note title. This will replace the selection with a link to the note.
    buf_set_keymap("v", "<CR>", ":'<,'>lua vim.lsp.buf.range_code_action()<CR>", opts)
    -- Reindex the notebook. Usually the language server does this automatically, so it's not often needed.
    buf_set_keymap("n", "<leader>zi", ":ZkIndex<CR>", opts)
    -- Create a new note after prompting for a title.
    buf_set_keymap("n", "<leader>zn", ":ZkNew {title = vim.fn.input('Title: ')}<CR>", opts)
    -- Create a new daily note in my `log/` notebook directory.
    buf_set_keymap("n", "<leader>zl", ":ZkNew {dir = 'log'}<CR>", opts)
    -- Find the backlinks for the note linked under the cursor.
    buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
  end
})

EOF

I'm looking to take what @megalithic had already done and expand upon it, probably utilize Telescope as much as possible in areas the LSP isn't functional or capable (i.e.: orphan listing). I've gotten a bit of it done.

Found a bug (nvim + zk.lsp)

If you trying to create link using lua vim.lsp.buf.definition command with Cyrillic symbols, it creates ref with ������� blocks.

To reproduce it, write some Cyrillic text - example: русский, visualize it and push <CR>.

@VolkovIlia Would you mind opening a dedicated issue? It's easier to track it then.

Is it any opportunity to make the reference style exactly like Obsidian does. Out of the box [ref](file) works fine, but referring to sub-titles does not make any scenes. Also, did not find how to trigger completion for sub-titles: [reference#subtitle](file) ....

BTW I use nvim-complection, cause nvim-compe is deprecated now...

P.S. nvim-compe also not working with #completion out of box, may you share config if it works for you...

If you do end up supporting #65 (comment) as a link generation option, I'd love for the title rename LSP action to also find backlinks and update the title there as well. (Assuming it's an exact match; if there is a different phrase used than the title then that's probably intentional by the user.)

BTW I use nvim-complection, cause nvim-compe is deprecated now...

nvim-compe successor https://github.com/hrsh7th/nvim-compe#warning is nvim-cmp so it will be great if this is supported. it works already, sorry for the noise.

I see that back-links through find references are implemented! Nice! Should they be checked off in the issue tracker? I was under the impression they weren't there which made me hesitate about adopting this otherwise awesome tool.

One more thing - would it be possible to find references for the current zettel by default (if a link isn't under cursor)? Otherwise I need to find one back-link manually first to find the others.

EDIT: What I mean by this is falling back on the doc indentifier if the position doesn't reveal anything.

Also now that the LSP suppports creating/deleting/renaming files, can zk also support renaming/moving zettels to a different directory and all references to them?

@wurosh

I see that back-links through find references are implemented! Nice! Should they be checked off in the issue tracker? I was under the impression they weren't there which made me hesitate about adopting this otherwise awesome tool.

One more thing - would it be possible to find references for the current zettel by default (if a link isn't under cursor)? Otherwise I need to find one back-link manually first to find the others.

That's actually why I didn't check this item yet, I had more in mind getting the backlinks of the current note. I'll take a look to see if this can be done when the caret is not over a link, I think there was a blocker last time I checked.

@wurosh + @nogweii

Also now that the LSP suppports creating/deleting/renaming files, can zk also support renaming/moving zettels to a different directory and all references to them?

Yes I would like to have this feature eventually. It won't be quick to implement though.

@VolkovIlia

Is it any opportunity to make the reference style exactly like Obsidian does. Out of the box [ref](file) works fine, but referring to sub-titles does not make any scenes. Also, did not find how to trigger completion for sub-titles: [reference#subtitle](file) ....

How is the link format exactly in Obsidian? Links with anchors (#subtitle) should work in zk.

Completion of subtitles is not implemented. I'll add it to the list but have no plan on implementing it myself soon.

@VolkovIlia

Actually re-reading your example, it looks like you're adding the anchor in the title portion of the link, instead of the path one. That's unusual, is it what Obsidian does? And how should zk behave with these? Currently the title portion of the link is not really used except for display.

Anchors in the path portion of a link work with zk.

@wurosh

One more thing - would it be possible to find references for the current zettel by default (if a link isn't under cursor)? Otherwise I need to find one back-link manually first to find the others.

Done! It's available in main. I have a few other items on my plate before the next release.

@wurosh

One more thing - would it be possible to find references for the current zettel by default (if a link isn't under cursor)? Otherwise I need to find one back-link manually first to find the others.

Done! It's available in main. I have a few other items on my plate before the next release.

And just like that my life gained a hard dependency on zk. Thanks again @mickael-menu.

@mickael-menu fyi neovim/nvim-lspconfig#1249

Sweet! From a previous conversation I had with mjlbach, I wasn't sure a zk config would be approved for nvim-lspconfig. Thanks for submitting it!

For zk.new is there is a way to set the notes directory? Here is my use case, I have a single place where I store my notes inside it. And I want to be able to create a note from anywhere inside of it, currently, this doesn't work because the LSP always tries to look for the closest .zk folder & it zk.new will not work if that's not the case.

So I have to navigate to my notes directory to be able to use zk.new. I'm following the same exact setup mentioned here #22 (comment) (maybe I'm also missing how to make this work as I want, so any pointers are welcome)

@ahmedelgabri The problem is that Neovim (by design) starts zk's LSP server only when the current directory and file is part of a notebook, because of this in the config:

configs.zk = {
  default_config = {
    cmd = {'zk', 'lsp', '--log', '/tmp/zk-lsp.log'};
    filetypes = {'markdown'};
    root_dir = lspconfig.util.root_pattern('.zk');
    settings = {};
  };
}

So the zk.new command won't be available if you're not in a notebook. Maybe you could automate moving to your notebook before calling zk.new.

@mickael-menu I changed root_dir to be vim.loop.cwd so that's always the current directory of the current file, which means zk.new will always be available inside markdown files. But still, it doesn't work & the logs show this error

2021/10/10 18:01:19.578 DEBUG [zk.server] zk: warning: open failed: stat /Users/ahmed/.dotfiles/README.md/.zk: not a directory
2021/10/10 18:01:27.062 DEBUG [zk.rpc] jsonrpc2: --> request #2: workspace/executeCommand: {"arguments":["/Users/ahmed/.dotfiles/README.md",{"dir":"","title":"fooooooooooooooooo"}],"command":"zk.new"}
2021/10/10 18:01:27.063 DEBUG [zk.rpc] jsonrpc2: <-- error #2: workspace/executeCommand: {"code":-32600,"message":"open failed: stat /Users/ahmed/.dotfiles/README.md/.zk: not a directory","data":null}
{
  cmd = { 'zk', 'lsp', '--log', '/tmp/zk-lsp.log' },
  root_dir = function(fname)
    return vim.loop.cwd()
  end,
}

@ahmedelgabri I pushed a fix on main, hope it will help you out.

@mickael-menu I think you forgot to push that commit :), nothing is on main after 0.7.0 release

Damn you're right 😄

is there anyway for the autocompletion feature to insert just the simple note filename (without the extension nor the path)?

Thanks!

is there anyway for the autocompletion feature to insert just the simple note filename (without the extension nor the path)?

Thanks!

Scratch that, the following worked like a charm 🪄

[format.markdown]
link-format = "[[{{filename}}]]"

Got some problems with autocompletion.
nvim: 5.1
completion: COQ.nvim

Completion works but there is few bugs:

  1. Completion triggers by [[ but the resulting output is [[Title](ref) expected [Title](ref)
  2. After deleting reference after [[ completion does not trigger till restart nvim.
  3. After any deletion completion breaks.

I saw you using nvim-compe but nvim-compe deprecated, nvim-complection (I used) is archived. Is this plugin hardcoded for proper behavior in compe? If no, can you give some suggestions for making proper bug report and fixing this behavior in other plugins (nvim-cmp, coq_nvim)

I use nvim-cmp & I never had any issues with completion myself (also previously with nvim-compe). Just a guess here, do you have any brackets or snippets engine plugins or something like this that might be conflicting?

I use nvim-cmp & I never had any issues with completion myself (also previously with nvim-compe). Just a guess here, do you have any brackets or snippets engine plugins or something like this that might be conflicting?

I've deleted snippets engine but issue still here(. I will change autocomplete engine to nvim-cmp but it's sad because coq nvim is awesome.

@mickael-menu not sure why but running the 0.7 release I can't find references to the current note when the cursor isn't hovering over another reference. regular references work just fine. This is with neovim's native lsp - is the issue reproducible with other clients?

@wurosh

not sure why but running the 0.7 release I can't find references to the current note when the cursor isn't hovering over another reference

I'm not sure why, it still works for me with 0.7 and Neovim native LSP client. I'm using this binding:

    buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)

Maybe you have something conflicting with the binding?


@VolkovIlia

Is this plugin hardcoded for proper behavior in compe? If no, can you give some suggestions for making proper bug report and fixing this behavior in other plugins (nvim-cmp, coq_nvim)

Completion works but there is few bugs:

  1. Completion triggers by [[ but the resulting output is [[Title](ref) expected [Title](ref)

It should cater to any LSP client, although there are some workarounds specific to make things work with VSCode. Maybe coq.nvim is not implementing the whole spec? In particular, it needs support for AdditionalTextEdits.

  1. After deleting reference after [[ completion does not trigger till restart nvim.
  2. After any deletion completion breaks.

These should be bugs in coq.nvim or Neovim. The LSP server doesn't have any direct control over the UX.

Because auto-completion with [[ required some hacky workarounds, I'm considering adding an option to auto-complete with only [ and avoid doing any substitution/replacement. Maybe that would help.

@wurosh

not sure why but running the 0.7 release I can't find references to the current note when the cursor isn't hovering over another reference

I'm not sure why, it still works for me with 0.7 and Neovim native LSP client. I'm using this binding:

    buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)

Maybe you have something conflicting with the binding?

@VolkovIlia

Is this plugin hardcoded for proper behavior in compe? If no, can you give some suggestions for making proper bug report and fixing this behavior in other plugins (nvim-cmp, coq_nvim)
Completion works but there is few bugs:

  1. Completion triggers by [[ but the resulting output is [[Title](ref) expected [Title](ref)

It should cater to any LSP client, although there are some workarounds specific to make things work with VSCode. Maybe coq.nvim is not implementing the whole spec? In particular, it needs support for AdditionalTextEdits.

  1. After deleting reference after [[ completion does not trigger till restart nvim.
  2. After any deletion completion breaks.

These should be bugs in coq.nvim or Neovim. The LSP server doesn't have any direct control over the UX.

Because auto-completion with [[ required some hacky workarounds, I'm considering adding an option to auto-complete with only [ and avoid doing any substitution/replacement. Maybe that would help.

Now I am using cmp-nvim and it working fine with [[ <CR>, but if I use [[ <key L> I got the result with [[title](ref). Mb [ is better trigger for compl plugins...

@mickael-menu even when running the command directly (:lua vim.lsp.buf.references()) I get the following logs:

[ERROR][2021-11-09 16:40:30] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-09 16:51:15] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-09 16:51:23] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:26:12] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:29:01] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:29:05] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:29:20] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:29:24] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:29:36] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:32:45] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:32:52] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:33:23] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:33:49] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:34:12] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:34:33] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:35:53] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-10 23:36:12] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-11 08:59:13] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-11 08:59:22] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-11 09:13:58] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"
[ERROR][2021-11-11 11:13:24] .../vim/lsp/rpc.lua:401	"rpc"	"zk"	"stderr"	"\r\r"

No such problem when hovering over a reference

@wurosh

I see that back-links through find references are implemented! Nice! Should they be checked off in the issue tracker? I was under the impression they weren't there which made me hesitate about adopting this otherwise awesome tool.
One more thing - would it be possible to find references for the current zettel by default (if a link isn't under cursor)? Otherwise I need to find one back-link manually first to find the others.

That's actually why I didn't check this item yet, I had more in mind getting the backlinks of the current note. I'll take a look to see if this can be done when the caret is not over a link, I think there was a blocker last time I checked.

@wurosh + @nogweii

Also now that the LSP suppports creating/deleting/renaming files, can zk also support renaming/moving zettels to a different directory and all references to them?

Yes I would like to have this feature eventually. It won't be quick to implement though.

@VolkovIlia

Is it any opportunity to make the reference style exactly like Obsidian does. Out of the box [ref](file) works fine, but referring to sub-titles does not make any scenes. Also, did not find how to trigger completion for sub-titles: [reference#subtitle](file) ....

How is the link format exactly in Obsidian? Links with anchors (#subtitle) should work in zk.

Completion of subtitles is not implemented. I'll add it to the list but have no plan on implementing it myself soon.

Any Progress on this? Especially subtitle completion and Obsidian/Vimwiki link compatibility?

I put together a small video, demonstrating the differences of zk lsp gotoDefinition vs :VimWikiFollowLink

zk.mov

Jumping to exact subheadings of other files (or the current file, e.g. TOC listings) would be much appreciated features!

@tmerse I keep my notes short and atomic, so I don't have much use for jumping to subheadings myself. But I'm open for contributions if you're up for it.

@mickael-menu : Fair point on keeping the the files small. Unfortunately I'am not familiar with go, but I may look into the source when I find some free time, if not just for the learning experience :)

Thanks for providing this, I think lsp-backed markdown is a great idea!

I added two new commands in #114:

I added two new commands in #114:

* [`zk.list`](https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist) to search for notes.

* [`zk.tag.list`](https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zktaglist) to retrieve the list of tags.

This is so exciting!! Thanks for the hard work @mickael-menu 😄

Why do the LSP commands need "A path to any file or directory in the notebook, to locate it."? I think the language server should at least default to the rootUri.

Why do the LSP commands need "A path to any file or directory in the notebook, to locate it."? I think the language server should at least default to the rootUri.

I think that would be helpful to run fuzzy finders like Telescope without having a note from the zettelkasten opened.

Hmm I agree that this might be useful. After further looking at the source code, I guess it makes sense, since this server is designed to handle multiple notebooks, and does not use the rootUri at all.

This doesn't work so well with nvim-lspconfig, since it'll start one server instance per root directory anyways.

Why do the LSP commands need "A path to any file or directory in the notebook, to locate it."? I think the language server should at least default to the rootUri.

Some commands have a different effect depending where you are located in the notebook (the links produced or the directory where a note will be created), like with the regular zk CLI commands.

However defaulting on the notebook root if not explicitly overridden sounds reasonable. I'm not sure if this would be best handled at the level of the LSP server or the zk-nvim Lua wrapper though?

This doesn't work so well with nvim-lspconfig, since it'll start one server instance per root directory anyways.

Yes that's a pickle... I circumvented this with a binding that goes to my notebook "index" file, but that would be nice to run the note picker from wherever.

I've made some changes, this should now work in neovim with a single instance of the zk server. Please refer to the updated readme.

https://github.com/kabouzeid/zk-nvim/tree/telescope

Hello!
Is it planned to add auto-complete on tags in the YAML frontmatter?
It works well when added with # but I use them only in the frontmatter.

@tissieres I answered there #144

thought I'd add (since I hadn't seen this discussed above) that with default neovim lsp omnifunc used for completion, the additionalTextEdits aren't currently applied, so starting with [[ to trigger completion and then selecting an entry, say "Test", gives you [[[[Test]] 😞.

Currently trying out nvim-cmp, which as mentioned above fixes this issue, but hopefully that helps anyone else out with this problem (until it's implemented) in the future!

@stefanvanburen there is also https://github.com/mfussenegger/nvim-lsp-compl if you find cmp too bloated, and want a more minimal completion plugin which supports additionalTextEdits. Personally I like cmp though.

@kabouzeid thanks! hadn't seen that one - was under the impression that cmp was the main neovim autocompletion plugin nowadays, will take a look!

Considering that there are often issues with the additionalTextEdits, I merged in a PR that disable them by default. You can still opt-in manually for clients like VS Code1 requirint it for link completion to work properly.

Let me know if it works for you @stefanvanburen.

Footnotes

  1. For VS Code I detected the client name in the LSP server to enable additionalTextEdits automatically, but other clients might need it too.

As regards pandoc integration, I don't know if this solves the same problem that @ZachariasLenz was having, but my markdown files were already subsumed into a pandoc filetype (which is managed by a different plugin). So I simply changed the relevant line in coc-settings.json to

"filetypes": ["markdown", "pandoc"]

And now the LSP works perfectly with my pandoc files.

I don't know if this was mentioned but I didn't see any other relevant issues. It appears the LSP attempts to check wikilink syntax within code blocks. Which is probably a rare issue but still doesn't strike me as appropriate behavior.
I only noticed this due to the multi-line string syntax Lua uses.

image

From now on let's open a dedicated GitHub issue for LSP bug reports or LSP feature requests. This issue will be used to follow the evolution of the LSP implementation.

I've been having issues getting autocomplete to work with Neovim 0.7 and coc.nvim. It works exactly as expected if the config has link-format: 'wiki' but in all other cases, the autocomplete never even shows up. I checked the logs from zk lsp and in the broken cases, it does seem like messaging is working as expected(though I am a total novice to the inner workings of the lsp, I mostly mean there seems to be messages and responses as expected, but it could be failing somewhere in the communication chain that I'm not looking), there is a message with the autocomplete options and can even verify that the newText value is of the correct link-format however it does not seem to propagate to the editor UI. Is this expected for coc.nvim? I'm not using the zk plugin that interfaces with the native lsp and have gotten this issue even when I take virtually everything out of my vim.init.

Any ideas?

I'm using markdown link format, with nvim, and coc-nvim for auto-completion. I just upgraded form 0.5.0 to 0.7.0 and 0.7.2 and all 3 the autocomplete is working for me. However, I also have a Mac running 0.7.0 with the same setup and it's not working, I didn't notice until I tested today.

That's to say the setup should work, you should probably open a dedicated GitHub issue with your version details for further troubleshooting.

Anyone managed to make the LSP work with Kakoune (kak-lsp)?

Wow, this project is awesome, nice work!

Anyone managed to make the LSP work with Kakoune (kak-lsp)?

Yes, I managed to get it working with kak-lsp. Try adding this config to your kak-lsp.toml(by default ~/.config/kak-lsp/kak-lsp.toml):

[language.markdown]
filetypes = ["markdown"]
roots = [".zk"]
command = "zk"
args = ["lsp"]

Note that it's very important to call the config entry as language.markdown, using language.zk-markdown will break it. I had to find it out the hard way, zk checks file languageId, which kak-lsp takes from the configuration entries.

The title issue mentions that Open a website from an inline external Markdown link has been implemented, but I didn't see docs on how to use it. Could someone point me the way? I assume this means that if I have [link](http://somewhere) that I can tell vim to open that link in my browser, or presumably with xdg-open.

The title issue mentions that Open a website from an inline external Markdown link has been implemented, but I didn't see docs on how to use it.

It was a mistake, but I implemented it quickly in #261. However, this uses LSP documentLink which is the only way AFAIK to report external URLs with LSP. Unfortunately I don't think NeoVim uses documentLink at the moment, but it work with VS Code for example.

Personally with NeoVim I've been using gx with a cursor on an URL.

Ah, I had nvim-tree disabling the netrw functionality, but gx works for me on this. Thanks for the pointer.

I seem to be experiencing the issue mentioned above where goto definition doesn't work outside of the root directory. I also notice that when running :LspInfo I see that the zk "root directory" is set as "Running in single file mode". Would this have something to do with that? What's the right way to set the root path to the notebook? ZK_NOTEBOOK_DIR is already present in the directory.

@zalegrala I think that "Running in single file mode" is expected, I have the same thing. I can't reproduce the issue though, opening a note from a sub directory or a directory outside the notebook.

I have this in my ~/.zshrc:

export ZK_NOTEBOOK_DIR=~/Notes

just wanna stop by and say thanks for the continual work! im a big fan and with the current feature set, i'm able to clean all my markdown notes from 7+ years ago (written in markdown, hoping for zk to come around). very much appreciated, and hoping to contribute soon as i learn more Go

@mickael-menu Yep, thanks for the note. I've got ZK_NOTEBOOK_DIR set in my environment also, but using gd in vim for go-to-definition doesn't seem to work reliably. I had a marksman plugin that would would, so I was a little confused about which plugin was doing what, but disabling that one and relying just on the zk plugin seems to disable the functionality.

@zalegrala Ha yes, I'm not sure gd is actually using the LSP's go to definition.

If you use zk-nvim (but this should partly work with just the zk LSP server) you need to declare a list of mappings.

The one you want is:

-- Open the link under the caret.
map("n", "<CR>", "<Cmd>lua vim.lsp.buf.definition()<CR>", opts)

Ah yes, gd does seem to be defined locally. I've got this currently, so I think I'm in-line with the approach @mickael-menu.

local keymap = vim.api.nvim_buf_set_keymap
keymap(bufnr, "n", "gd", "<cmd>lua vim.lsp.buf.definition()<CR>", opts)