9d6d28a1b6
The g:vimwiki_* drop-in only fed the LSP payload (lsp.vim s:settings). The buffer-side commands — <Leader>ww (wiki_index), :VimwikiSearch, auto_chdir, diary, completion — resolve the wiki list independently via s:wiki_cfg / nuwiki#commands#wiki_list, which read only g:nuwiki_wikis / g:nuwiki_wiki_root. So with a g:vimwiki_list config the server knew the wikis but <Leader>ww fell back to the default ~/vimwiki and opened an empty index. Extract the resolution into a single source of truth, autoload/nuwiki/config.vim (nuwiki#config#wikis / #scalar_globals), which resolves g:nuwiki_wikis or an upstream g:vimwiki_list and folds the global scalar defaults. lsp.vim (payload), commands.vim, and diary.vim all route through it — also dedups the s:wiki_cfg copy that lived in both commands.vim and diary.vim. Regression guard in test-vimwiki-compat-vim: nuwiki#commands#wiki_list() must resolve the g:vimwiki_list roots (21 checks). All Vim harnesses + config-parity goldens green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
158 lines
5.5 KiB
VimL
158 lines
5.5 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')
|
|
call s:register_with_coc(l:bin)
|
|
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
|
|
|
|
" ===== coc.nvim integration =====
|
|
"
|
|
" Register the nuwiki language server with coc *programmatically* via
|
|
" coc#config, so users don't have to hand-maintain a coc-settings.json entry
|
|
" per wiki. The config (wiki roots, per-wiki keys, the vimwiki/nuwiki global
|
|
" shorthand) comes from s:settings() — the same payload the vim-lsp path sends.
|
|
" coc reacts to the `languageserver` config change, registers the server, and
|
|
" starts it for the open vimwiki buffer.
|
|
"
|
|
" Opt out with `let g:nuwiki_no_coc_register = 1` to manage the entry in
|
|
" coc-settings.json yourself (we then just print the snippet).
|
|
function! s:register_with_coc(bin) abort
|
|
if get(g:, 'nuwiki_no_coc_register', 0)
|
|
call s:print_coc_snippet(a:bin)
|
|
return
|
|
endif
|
|
let s:coc_bin = a:bin
|
|
if get(g:, 'coc_service_initialized', 0)
|
|
call s:coc_register()
|
|
else
|
|
" coc hasn't finished starting its node service yet — defer until it has,
|
|
" otherwise the updateConfig notification is sent to a service that isn't
|
|
" listening.
|
|
augroup nuwiki_coc_register
|
|
autocmd!
|
|
autocmd User CocNvimInit ++once call s:coc_register()
|
|
augroup END
|
|
endif
|
|
endfunction
|
|
|
|
function! s:coc_register() abort
|
|
let l:cfg = s:settings()
|
|
" Call coc#config directly — `exists('*coc#config')` can't be trusted because
|
|
" it doesn't trigger autoloading, so we let the call autoload coc.vim and
|
|
" fall back to the manual snippet only if coc genuinely isn't there.
|
|
try
|
|
call coc#config('languageserver.nuwiki', {
|
|
\ 'command': s:coc_bin,
|
|
\ 'filetypes': ['vimwiki'],
|
|
\ 'initializationOptions': l:cfg,
|
|
\ 'settings': { 'nuwiki': l:cfg },
|
|
\ })
|
|
catch /^Vim\%((\a\+)\)\=:E11[78]/
|
|
call s:print_coc_snippet(s:coc_bin)
|
|
endtry
|
|
endfunction
|
|
|
|
function! s:print_coc_snippet(bin) abort
|
|
echohl WarningMsg
|
|
echom 'nuwiki: coc.nvim detected. Add this to your coc-settings.json:'
|
|
echom ' "languageserver": {'
|
|
echom ' "nuwiki": {'
|
|
echom ' "command": "' . a:bin . '",'
|
|
echom ' "filetypes": ["vimwiki"],'
|
|
echom ' "initializationOptions": ' . json_encode(s:settings())
|
|
echom ' }'
|
|
echom ' }'
|
|
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'),
|
|
\ },
|
|
\ }
|
|
" Wiki list comes from the shared resolver (nuwiki#config#wikis), so the
|
|
" server payload and the buffer-side commands agree on which wikis exist —
|
|
" native g:nuwiki_wikis or an upstream g:vimwiki_list, globals already folded.
|
|
let l:wikis = nuwiki#config#wikis()
|
|
if !empty(l:wikis)
|
|
let l:cfg['wikis'] = l:wikis
|
|
else
|
|
" Single-wiki shorthand: fold the global scalars into the top-level payload
|
|
" so the server's single-wiki desugaring honours them.
|
|
call extend(l:cfg, nuwiki#config#scalar_globals(), 'force')
|
|
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
|