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>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
" 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
|
||||
Reference in New Issue
Block a user