zk-org / zk

A plain text note-taking assistant
https://zk-org.github.io/zk/
GNU General Public License v3.0
1.63k stars 118 forks source link

Providing a Language Server (LSP) #22

Open mickael-menu opened 3 years ago

mickael-menu commented 3 years ago

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:

Feel free to share more ideas!

mhanberg commented 3 years ago

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}}}
mickael-menu commented 3 years ago

@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?

mhanberg commented 3 years ago

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.

megalithic commented 3 years ago

@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!

mickael-menu commented 3 years ago

@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?

megalithic commented 3 years ago

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.

megalithic commented 3 years ago

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

mickael-menu commented 3 years ago

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.

mhanberg commented 3 years ago

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.

mickael-menu commented 3 years ago

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

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

mickael-menu commented 3 years ago

I merged in a way to specify the completion link format from the user configuration: https://github.com/mickael-menu/zk/pull/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.

megalithic commented 3 years ago

@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!

megalithic commented 3 years ago

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. :)

mickael-menu commented 3 years ago

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": []
}
mickael-menu commented 3 years ago

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

ghost commented 3 years ago

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 = {},
  };
}
ghost commented 3 years ago

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?

mickael-menu commented 3 years ago

@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?

ghost commented 3 years ago

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

https://user-images.githubusercontent.com/81169491/116593769-fd597000-a910-11eb-8c80-f9fd4d892c9c.mp4

mickael-menu commented 3 years ago

@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 https://user-images.githubusercontent.com/58686775/116608753-dc564680-a933-11eb-9977-116022ac27f9.mov
mickael-menu commented 3 years ago

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:

https://user-images.githubusercontent.com/58686775/117876567-cdf91a80-b2a3-11eb-98c5-b5f07aaed16f.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 ```vim command! -nargs=0 ZkIndex :call CocAction("runCommand", "zk.index", expand("%:p")) command! -nargs=? ZkNew :exec "edit ".CocAction("runCommand", "zk.new", expand("%:p"), ).path nnoremap zi :ZkIndex nnoremap zn :ZkNew {"title": input("Title: ")} nnoremap zl :ZkNew {"dir": "log"} ```

(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 ```lua command! -nargs=0 ZkIndex :lua require'lspconfig'.zk.index() command! -nargs=? ZkNew :lua require'lspconfig'.zk.new() 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", "", "lua vim.lsp.buf.definition()", opts) buf_set_keymap("n", "K", "lua vim.lsp.buf.hover()", opts) buf_set_keymap("n", "zi", ":ZkIndex", opts) buf_set_keymap("v", "zn", ":'<,'>lua vim.lsp.buf.range_code_action()", opts) buf_set_keymap("n", "zn", ":ZkNew {title = vim.fn.input('Title: ')}", opts) buf_set_keymap("n", "zl", ":ZkNew {dir = 'log'}", opts) end }) EOF ```
mickael-menu commented 3 years ago

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 ```viml 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
jrekier commented 3 years ago

(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)

https://user-images.githubusercontent.com/9407736/118467264-f352b200-b703-11eb-9774-78f933009704.mov

I suspect I might be doing something wrong ...

mickael-menu commented 3 years ago

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

jrekier commented 3 years ago

indeed ... thanks !

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

and it works wonders. Cheers

mickael-menu commented 3 years ago

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.

entropitor commented 3 years ago

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)

mickael-menu commented 3 years ago

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.

entropitor commented 3 years ago

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!

danymat commented 3 years ago

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

mickael-menu commented 3 years ago

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.

physicophilic commented 3 years ago

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,

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.

mickael-menu commented 3 years ago

@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.

chris-sanders commented 3 years ago

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 https://github.com/megalithic/zk.nvim/issues/25#issuecomment-847664064 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"}]}
chris-sanders commented 3 years ago

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>"

mickael-menu commented 3 years ago

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

VolkovIlia commented 3 years ago

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

mickael-menu commented 3 years ago

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 https://github.com/megalithic/zk.nvim/discussions/41

In the meantime, this should get you started:

~/.config/nvim/init.vim ```lua -- 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() 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", "", "lua vim.lsp.buf.completion()", opts) -- Follow a Markdown link with . buf_set_keymap("n", "", "lua vim.lsp.buf.definition()", opts) -- Preview a note with K when the cursor is on a link. buf_set_keymap("n", "K", "lua vim.lsp.buf.hover()", 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", "", ":'<,'>lua vim.lsp.buf.range_code_action()", opts) -- Reindex the notebook. Usually the language server does this automatically, so it's not often needed. buf_set_keymap("n", "zi", ":ZkIndex", opts) -- Create a new note after prompting for a title. buf_set_keymap("n", "zn", ":ZkNew {title = vim.fn.input('Title: ')}", opts) -- Create a new daily note in my `log/` notebook directory. buf_set_keymap("n", "zl", ":ZkNew {dir = 'log'}", opts) -- Find the backlinks for the note linked under the cursor. buf_set_keymap('n', 'gr', 'lua vim.lsp.buf.references()', opts) end }) EOF ```
eric-hansen commented 3 years ago

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.

VolkovIlia commented 3 years ago

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>.

mickael-menu commented 3 years ago

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

VolkovIlia commented 3 years ago

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...

nogweii commented 3 years ago

If you do end up supporting https://github.com/mickael-menu/zk/issues/65#issuecomment-899318486 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.)

ahmedelgabri commented 3 years ago

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.

cyruseuros commented 2 years ago

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.

cyruseuros commented 2 years ago

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?

mickael-menu commented 2 years ago

@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.

mickael-menu commented 2 years ago

@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.

mickael-menu commented 2 years ago

@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.

cyruseuros commented 2 years ago

@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.