feat(coc): auto-register the language server with coc.nvim
CI / cargo fmt --check (push) Successful in 47s
CI / cargo clippy (push) Successful in 46s
CI / cargo test (push) Successful in 56s
CI / editor keymaps (push) Successful in 1m30s

coc users had to hand-maintain a coc-settings.json `languageserver.nuwiki`
entry, which didn't track g:nuwiki_wikis / g:vimwiki_list / the global
shorthand and meant editing JSON per wiki. nuwiki now registers itself
programmatically: on the first .wiki buffer it calls
coc#config('languageserver.nuwiki', {…}) with the s:settings() payload
(same config the vim-lsp path sends). coc reacts to the languageserver
config change (onDidChangeConfiguration → registerClientsByConfig) and
starts the server for the open buffer.

Details:
- Reliable coc detection via :CocConfig (exists('*coc#config') can't be
  trusted — it doesn't trigger autoload in Vim 9.2). The coc#config call
  is wrapped in try/catch and autoloads coc.vim itself; falls back to the
  printed snippet only if coc genuinely isn't there.
- Deferred to User CocNvimInit when coc's node service isn't up yet.
- Opt out with g:nuwiki_no_coc_register (then we just print the snippet).

Dogfooded in start-vim-coc.sh: dropped the manual coc-settings.json
languageserver block; the harness now relies on auto-registration from
g:nuwiki_* (real-user flow). New harness test-coc-register-vim (7 checks,
stubbed coc#config) asserts the injected payload incl. the folded global
shorthand; wired into CI. README coc section rewritten (zero-config).
Rust 573 passed, clippy clean, all harnesses green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 00:07:50 +00:00
parent a4643bdacb
commit ac14cdd838
6 changed files with 203 additions and 61 deletions
+61 -16
View File
@@ -136,22 +136,7 @@ function! nuwiki#lsp#start() abort
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
call s:register_with_coc(l:bin)
return
endif
@@ -162,6 +147,66 @@ function! nuwiki#lsp#start() abort
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