Files
nuwiki/autoload/nuwiki/complete.vim
T
gffranco 3b3d8ca782
CI / cargo fmt --check (push) Successful in 37s
CI / cargo clippy (push) Successful in 39s
CI / cargo test (push) Successful in 37s
CI / editor keymaps (push) Successful in 1m29s
feat(commands): command-line completion for Goto/Colorize/tag commands (P3)
Upstream attaches -complete= to several commands; nuwiki had none, so <Tab>
at the : line never completed page/tag/colour names. New
autoload/nuwiki/complete.vim adds pure client-side, synchronous completers
(config + filesystem, never the LSP — so they work under vim-lsp, coc and
Neovim), wired via -complete=customlist into all command contexts:

- nuwiki#complete#pages → VimwikiGoto/NuwikiGoto (glob wiki roots for page names)
- nuwiki#complete#colors → VimwikiColorize/NuwikiColorize (color_dic keys +
  colours already used in buffer color:… spans)
- nuwiki#complete#tags → VimwikiSearchTags/GenerateTagLinks/GenerateTags (+Nuwiki)
  (scan wiki files for :tag: runs — the tag index is server-side and a
  synchronous completer can't query it, so we read the same source it indexes)

Documented divergence: no file completer for VimwikiRenameFile — nuwiki
delegates renaming to the LSP rename request (no filename arg to complete),
unlike upstream which renames itself.

Tests: complete.{pages_globs_and_filters,tags_scans_wiki_files,
colors_from_buffer_spans} (test-keymaps-vim.vim). Both harnesses green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 20:40:22 +00:00

87 lines
3.6 KiB
VimL

" autoload/nuwiki/complete.vim — command-line completion for the
" :Vimwiki*/:Nuwiki* commands (mirrors upstream vimwiki's -complete= specs).
"
" Pure client-side and synchronous: candidates come from config and the
" filesystem, never the LSP, so a `-complete=customlist,{fn}` attribute can
" call these directly under vim-lsp, coc, and Neovim alike.
"
" NOTE on files/RenameFile: upstream's :VimwikiRenameFile takes a new-name arg
" with file completion because upstream performs the rename itself. nuwiki
" delegates renaming to the LSP rename request (`:LspRename` / coc `rename`),
" which drives its own interactive prompt — there is no filename argument to
" complete, so no file completer is provided (documented divergence).
" Page-name completion (VimwikiGoto). Globs every configured wiki root for its
" `*<ext>` files and returns their root-relative names with the extension
" stripped, filtered by {arglead}. Mirrors upstream complete_links_raw.
function! nuwiki#complete#pages(arglead, cmdline, cursorpos) abort
let l:names = {}
for l:w in nuwiki#commands#wiki_list()
let l:root = substitute(get(l:w, 'root', ''), '/\+$', '', '')
if l:root ==# '' | continue | endif
let l:ext = get(l:w, 'ext', '.wiki')
for l:f in glob(l:root . '/**/*' . l:ext, 0, 1)
let l:rel = l:f[len(l:root) + 1 :]
if l:rel ==# '' | continue | endif
let l:rel = l:rel[: -len(l:ext) - 1]
let l:names[l:rel] = 1
endfor
endfor
return filter(sort(keys(l:names)), 'stridx(v:val, a:arglead) == 0')
endfunction
" Colour completion (VimwikiColorize) — keys from any configured `color_dic`
" (per-wiki `g:nuwiki_wikis[].color_dic` or the scalar `g:nuwiki_color_dic`)
" plus colours already used in `color:NAME` spans in the current buffer.
function! nuwiki#complete#colors(arglead, cmdline, cursorpos) abort
let l:set = {}
for l:w in get(g:, 'nuwiki_wikis', [])
for l:k in keys(get(l:w, 'color_dic', {}))
let l:set[l:k] = 1
endfor
endfor
for l:k in keys(get(g:, 'nuwiki_color_dic', {}))
let l:set[l:k] = 1
endfor
for l:line in getline(1, '$')
let l:start = 0
while 1
let l:m = matchstrpos(l:line, 'color:\s*\zs[^"'';)]\+', l:start)
if l:m[1] < 0 | break | endif
let l:set[trim(l:m[0])] = 1
let l:start = l:m[2]
endwhile
endfor
return filter(sort(keys(l:set)), 'stridx(v:val, a:arglead) == 0')
endfunction
" Tag completion (VimwikiSearchTags / VimwikiGenerateTagLinks). The tag index
" lives in the LSP server, which a synchronous completer can't query, so we
" harvest `:tag:` tokens by scanning the configured wikis' files directly —
" the same source the server indexes. Runs only on <Tab> at the `:` line.
function! nuwiki#complete#tags(arglead, cmdline, cursorpos) abort
let l:set = {}
for l:w in nuwiki#commands#wiki_list()
let l:root = substitute(get(l:w, 'root', ''), '/\+$', '', '')
if l:root ==# '' | continue | endif
let l:ext = get(l:w, 'ext', '.wiki')
for l:f in glob(l:root . '/**/*' . l:ext, 0, 1)
for l:line in readfile(l:f)
" Tags come in colon-delimited runs like `:foo:bar:` (no spaces).
" Match a whole run, then split out each tag (adjacent tags share a
" colon, so a per-tag scan would miss every other one).
let l:start = 0
while 1
let l:m = matchstrpos(l:line, ':\%([^:[:space:]]\+:\)\+', l:start)
if l:m[1] < 0 | break | endif
for l:t in split(l:m[0], ':')
if l:t !=# '' | let l:set[l:t] = 1 | endif
endfor
let l:start = l:m[2]
endwhile
endfor
endfor
endfor
return filter(sort(keys(l:set)), 'stridx(v:val, a:arglead) == 0')
endfunction