6983daa637
The Vim follow-link path delegated to the LSP client's jump UI
(:LspDefinition / coc jumpDefinition), which broke two ways for wiki
link-following:
1. **No create-on-follow (vim-lsp + coc).** vim-lsp's location handler
readfile()s the target to build a quickfix entry; for a not-yet-created
page that throws E484 and aborts the jump, so <CR> on [[NewPage]] did
nothing. The server was correct throughout — textDocument/definition
returns a *synthesised* location for missing pages (verified over
JSON-RPC).
2. **Wrong window placement (coc).** Without an explicit open command coc
fell back to coc.preferences.jumpCommand (e.g. a tab command).
Stop delegating: nuwiki#commands#follow_link_or_create() /
follow_link_drop() now resolve textDocument/definition directly and open
the URI themselves via a shared s:open_definition(open_cmd) helper — :edit
for <CR>, `tab drop` for <C-S-CR>. :edit opens a buffer for a missing path
(save creates it, matching vimwiki) and gives exact current-window
placement regardless of the user's coc jumpCommand. Removes
s:jump_definition / s:drop_from_response.
Also fix the coc action name: CocAction('getDefinition') does not exist
(E605 "Action getDefinition does not exist") — the registered action is
'definitions'. Fixed in s:open_definition and badd_link.
coc config delivery: the setup guidance shipped without
initializationOptions, so coc users never sent wiki_root and the server
resolved links against its default root (existing pages flagged broken,
follow-to-create landed in the cwd). The printed snippet
(autoload/nuwiki/lsp.vim) now emits initializationOptions populated with
the resolved settings, and the README coc snippet documents it as required.
Add development/start-vim-coc.sh — a coc.nvim dev launcher (sibling of
start-vim.sh) that wires coc's prebuilt release branch + a generated
coc-settings.json (with initializationOptions), deliberately omitting
vim-lsp so the coc path is exercised; doubles as a reproducer.
Tests: new cr.follow_opens_missing_page_in_current_window case in
test-keymaps-vim.vim (stubs CocAction to a missing page, asserts
current-window :edit). Keymap suite 254+18 green; config-parity (Vim +
Neovim) green. Neovim path unchanged and re-confirmed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
109 lines
3.9 KiB
VimL
109 lines
3.9 KiB
VimL
" autoload/nuwiki/lsp.vim — Vim (non-Neovim) LSP client wiring.
|
|
"
|
|
" Preference order:
|
|
" 1. vim-lsp (matoto/vim-lsp)
|
|
" 2. coc.nvim
|
|
" 3. Print an error if neither is available.
|
|
|
|
" Resolve the plugin root at script-load time. `<sfile>` inside a
|
|
" function later returns the *calling* script's path, not this file's
|
|
" — capturing it here is the reliable way.
|
|
let s:plugin_root = fnamemodify(resolve(expand('<sfile>:p')), ':h:h:h')
|
|
|
|
let s:started = 0
|
|
|
|
function! nuwiki#lsp#start() abort
|
|
if s:started
|
|
return
|
|
endif
|
|
let s:started = 1
|
|
|
|
let l:bin = s:bin_path()
|
|
if !executable(l:bin)
|
|
echohl ErrorMsg
|
|
echom 'nuwiki: language server not found at ' . l:bin
|
|
echom 'Run :NuwikiInstall to install the binary'
|
|
echohl None
|
|
return
|
|
endif
|
|
|
|
if exists('g:lsp_loaded')
|
|
" vim-lsp — its autoload functions aren't triggered by `exists('*…')`,
|
|
" but its plugin/lsp.vim sets `g:lsp_loaded = 1` once requirements
|
|
" (json_encode + timers + lambda) are met, so that's the reliable
|
|
" presence check.
|
|
call lsp#register_server({
|
|
\ 'name': 'nuwiki',
|
|
\ 'cmd': {server_info -> [l:bin]},
|
|
\ 'allowlist': ['vimwiki'],
|
|
\ 'initialization_options': s:settings(),
|
|
\ 'config': { 'settings': { 'nuwiki': s:settings() } },
|
|
\ })
|
|
" vim-lsp auto-enables servers when 'g:lsp_auto_enable' is on
|
|
" (default) — no manual `lsp#enable()` needed.
|
|
return
|
|
endif
|
|
|
|
if exists(':CocConfig') == 2 || exists('*coc#config')
|
|
" coc.nvim — coc reads its server list from coc-settings.json.
|
|
" We can't inject it dynamically without owning the file, so just point
|
|
" the user at the snippet. `initializationOptions` carries wiki_root etc.
|
|
" to the server exactly like the vim-lsp registration above — without it
|
|
" the server resolves links against its default root, so existing pages
|
|
" look broken and follow-to-create lands in the wrong directory.
|
|
echohl WarningMsg
|
|
echom 'nuwiki: coc.nvim detected. Add this to your coc-settings.json:'
|
|
echom ' "languageserver": {'
|
|
echom ' "nuwiki": {'
|
|
echom ' "command": "' . l:bin . '",'
|
|
echom ' "filetypes": ["vimwiki"],'
|
|
echom ' "initializationOptions": ' . json_encode(s:settings())
|
|
echom ' }'
|
|
echom ' }'
|
|
echohl None
|
|
return
|
|
endif
|
|
|
|
echohl ErrorMsg
|
|
echom 'nuwiki: no supported LSP client found.'
|
|
echom 'Install vim-lsp (https://github.com/prabirshrestha/vim-lsp)'
|
|
echom 'or coc.nvim (https://github.com/neoclide/coc.nvim).'
|
|
echohl None
|
|
endfunction
|
|
|
|
function! s:bin_path() abort
|
|
if exists('g:nuwiki_binary_path') && filereadable(g:nuwiki_binary_path)
|
|
return g:nuwiki_binary_path
|
|
endif
|
|
let l:suffix = has('win32') ? '.exe' : ''
|
|
return s:plugin_root . '/bin/nuwiki-ls' . l:suffix
|
|
endfunction
|
|
|
|
function! s:settings() abort
|
|
let l:cfg = {
|
|
\ 'wiki_root': get(g:, 'nuwiki_wiki_root', '~/vimwiki'),
|
|
\ 'file_extension': get(g:, 'nuwiki_file_extension', '.wiki'),
|
|
\ 'syntax': get(g:, 'nuwiki_syntax', 'vimwiki'),
|
|
\ 'log_level': get(g:, 'nuwiki_log_level', 'warn'),
|
|
\ 'diagnostic': {
|
|
\ 'link_severity': get(g:, 'nuwiki_link_severity', 'warn'),
|
|
\ },
|
|
\ }
|
|
" Include the per-wiki list when configured via g:nuwiki_wikis so the
|
|
" server knows each wiki's root, diary path, etc. Without this it only
|
|
" sees wiki_root and resolves links relative to that directory instead
|
|
" of the individual wiki's root.
|
|
if exists('g:nuwiki_wikis') && !empty(g:nuwiki_wikis)
|
|
let l:cfg['wikis'] = g:nuwiki_wikis
|
|
endif
|
|
return l:cfg
|
|
endfunction
|
|
|
|
" Public accessor for the `initialization_options` payload. Mirrors the
|
|
" Neovim client's `require('nuwiki.lsp').init_options()` so the config
|
|
" parity harness can inspect the exact dict each client sends to the
|
|
" server.
|
|
function! nuwiki#lsp#settings() abort
|
|
return s:settings()
|
|
endfunction
|