fix(search): graceful no-match + NuwikiSearch alias (re-audit follow-up)
CI / cargo fmt --check (push) Successful in 28s
CI / cargo clippy (push) Successful in 29s
CI / cargo test (push) Successful in 35s
CI / editor keymaps (push) Successful in 1m25s

Re-audit of the just-landed command work found one real bug I introduced
and a convention gap:

- VimwikiSearch / VWS raised a raw E480 on a no-match search; upstream
  reports it gracefully. Both clients now catch it (try/catch in Vim,
  pcall in Neovim) and emit "nuwiki: no match for <pat>".

- Added a NuwikiSearch alias alongside VimwikiSearch/VWS (every other
  command carries a Nuwiki* form).

Gap-doc note corrected: nuwiki's search populates + opens the location
list (shows all matches) where upstream jumps to the first match — logged
as a minor presentation divergence rather than claiming exact parity.

Config + mappings re-audits came back clean (no new gaps, no regressions;
table-mapping rewire verified non-recursive, gLH/gLL/gLR present).

Tests: cmd.VimwikiSearch_no_match_graceful, surface.{Vimwiki,Nuwiki}Search.
Neovim 301, Vim 294/18/21 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 01:28:44 +00:00
parent a11b742fc1
commit 6deba47106
6 changed files with 35 additions and 8 deletions
+5
View File
@@ -205,7 +205,12 @@ function! nuwiki#commands#search(args) abort
endif endif
let l:ext = l:ext[0] ==# '.' ? l:ext : '.' . l:ext let l:ext = l:ext[0] ==# '.' ? l:ext : '.' . l:ext
let l:glob = l:root ==# '' ? '**' : fnameescape(l:root) . '**/*' . l:ext let l:glob = l:root ==# '' ? '**' : fnameescape(l:root) . '**/*' . l:ext
try
execute 'lvimgrep /' . escape(l:pat, '/') . '/j ' . l:glob execute 'lvimgrep /' . escape(l:pat, '/') . '/j ' . l:glob
catch /E480/
echohl WarningMsg | echom 'nuwiki: no match for ' . l:pat | echohl None
return
endtry
lopen lopen
endfunction endfunction
+13 -1
View File
@@ -112,7 +112,7 @@ let s:both_forms = [
\ 'RebuildTags', '2HTML', '2HTMLBrowse', 'All2HTML', 'Rss', \ 'RebuildTags', '2HTML', '2HTMLBrowse', 'All2HTML', 'Rss',
\ 'NormalizeLink', 'RenumberList', 'RenumberAllLists', \ 'NormalizeLink', 'RenumberList', 'RenumberAllLists',
\ 'ListToggle', 'IncrementListItem', 'DecrementListItem', \ 'ListToggle', 'IncrementListItem', 'DecrementListItem',
\ 'CatUrl', 'ShowVersion', 'Return', 'Var', \ 'CatUrl', 'ShowVersion', 'Return', 'Var', 'Search',
\ ] \ ]
for s:suffix in s:both_forms for s:suffix in s:both_forms
for s:prefix in ['Nuwiki', 'Vimwiki'] for s:prefix in ['Nuwiki', 'Vimwiki']
@@ -692,6 +692,18 @@ call s:record(
\ 'cmd.search_and_tablealign_nargs', \ 'cmd.search_and_tablealign_nargs',
\ 'err=' . s:attr_err) \ 'err=' . s:attr_err)
" A no-match search must be caught (friendly message), not raise a raw E480.
let s:nm_err = ''
try
VimwikiSearch zzznomatchxyzqqq
catch /E480/
let s:nm_err = v:exception
catch
" other errors (no wiki files, etc.) are fine — only E480 is the regression.
endtry
call s:record(s:nm_err ==# '' ? 1 : 0,
\ 'cmd.VimwikiSearch_no_match_graceful', 'err=' . s:nm_err)
" ===== :VimwikiGoto -nargs=* ===== " ===== :VimwikiGoto -nargs=* =====
" Was -nargs=1, so a page name with a space raised E488 (and the empty-arg " Was -nargs=1, so a page name with a space raised E488 (and the empty-arg
" prompt fallback was unreachable). Now -nargs=*: a multi-word arg must parse. " prompt fallback was unreachable). Now -nargs=*: a multi-word arg must parse.
+1 -1
View File
@@ -139,7 +139,7 @@ vim.defer_fn(function()
'RebuildTags', '2HTML', '2HTMLBrowse', 'All2HTML', 'Rss', 'RebuildTags', '2HTML', '2HTMLBrowse', 'All2HTML', 'Rss',
'NormalizeLink', 'RenumberList', 'RenumberAllLists', 'NormalizeLink', 'RenumberList', 'RenumberAllLists',
'ListToggle', 'IncrementListItem', 'DecrementListItem', 'ListToggle', 'IncrementListItem', 'DecrementListItem',
'CatUrl', 'ShowVersion', 'Return', 'Var', 'CatUrl', 'ShowVersion', 'Return', 'Var', 'Search',
} }
for _, suffix in ipairs(both_forms) do for _, suffix in ipairs(both_forms) do
for _, prefix in ipairs({ 'Nuwiki', 'Vimwiki' }) do for _, prefix in ipairs({ 'Nuwiki', 'Vimwiki' }) do
+8 -4
View File
@@ -269,10 +269,14 @@ fix site.
through `nuwiki#commands#search` / `commands.search` (both clients), which through `nuwiki#commands#search` / `commands.search` (both clients), which
resolves the wiki whose root contains the current file (else the first resolves the wiki whose root contains the current file (else the first
configured wiki, else CWD) and `lvimgrep`s `<root>/**/*<ext>` into the location configured wiki, else CWD) and `lvimgrep`s `<root>/**/*<ext>` into the location
list; an empty pattern reuses the last search (`@/`). The `-nargs=*` attr fix list; an empty pattern reuses the last search (`@/`); a no-match is caught and
(2026-06-03) is folded in. _(nuwiki uses Vim's `lvimgrep` rather than a bespoke reported (no raw `E480`). Added a `NuwikiSearch` alias alongside
engine — the same mechanism vimwiki uses — so this is full behavioral parity.)_ `VimwikiSearch`/`VWS`. The `-nargs=*` attr fix (2026-06-03) is folded in.
Covered by `cmd.search_and_tablealign_nargs` (`test-keymaps-vim.vim`). nuwiki uses Vim's `lvimgrep` — the same mechanism vimwiki uses. **Minor
presentation divergence:** nuwiki populates + opens the location list (`/j`,
then `:lopen`) showing all matches, whereas upstream jumps to the first match
and leaves the list closed. Covered by `cmd.search_and_tablealign_nargs`
(`test-keymaps-vim.vim`).
- [x] **`VimwikiChangeSymbolTo` / `VimwikiListChangeSymbolI` lack `-range`** - [x] **`VimwikiChangeSymbolTo` / `VimwikiListChangeSymbolI` lack `-range`**
_(new, 2026-05-31 re-audit; fixed same day)_ — upstream both carry _(new, 2026-05-31 re-audit; fixed same day)_ — upstream both carry
`-range -nargs=1`; nuwiki had `-nargs=1` only, so a visual-range invocation `-range -nargs=1`; nuwiki had `-nargs=1` only, so a visual-range invocation
+2
View File
@@ -95,6 +95,7 @@ if !has('nvim')
command! -buffer VimwikiPrevLink call nuwiki#commands#link_prev() command! -buffer VimwikiPrevLink call nuwiki#commands#link_prev()
command! -buffer VimwikiBaddLink call nuwiki#commands#badd_link() command! -buffer VimwikiBaddLink call nuwiki#commands#badd_link()
command! -buffer -nargs=* VimwikiSearch call nuwiki#commands#search(<q-args>) command! -buffer -nargs=* VimwikiSearch call nuwiki#commands#search(<q-args>)
command! -buffer -nargs=* NuwikiSearch call nuwiki#commands#search(<q-args>)
command! -buffer -nargs=* VWS call nuwiki#commands#search(<q-args>) command! -buffer -nargs=* VWS call nuwiki#commands#search(<q-args>)
command! -buffer -nargs=* -complete=customlist,nuwiki#complete#pages VimwikiGoto call nuwiki#commands#wiki_goto_page(<q-args>) command! -buffer -nargs=* -complete=customlist,nuwiki#complete#pages VimwikiGoto call nuwiki#commands#wiki_goto_page(<q-args>)
@@ -450,6 +451,7 @@ command! -buffer -nargs=* -complete=customlist,nuwiki#complete#pages VimwikiGoto
command! -buffer VimwikiBacklinks lua vim.lsp.buf.references() command! -buffer VimwikiBacklinks lua vim.lsp.buf.references()
command! -buffer VWB lua vim.lsp.buf.references() command! -buffer VWB lua vim.lsp.buf.references()
command! -buffer -nargs=* VimwikiSearch lua require('nuwiki.commands').search(<q-args>) command! -buffer -nargs=* VimwikiSearch lua require('nuwiki.commands').search(<q-args>)
command! -buffer -nargs=* NuwikiSearch lua require('nuwiki.commands').search(<q-args>)
command! -buffer -nargs=* VWS lua require('nuwiki.commands').search(<q-args>) command! -buffer -nargs=* VWS lua require('nuwiki.commands').search(<q-args>)
command! -buffer VimwikiDeleteFile lua require('nuwiki.commands').delete_file() command! -buffer VimwikiDeleteFile lua require('nuwiki.commands').delete_file()
+5 -1
View File
@@ -314,7 +314,11 @@ function M.search(args)
end end
if not ext:match('^%.') then ext = '.' .. ext end if not ext:match('^%.') then ext = '.' .. ext end
local glob = root == '' and '**' or (vim.fn.fnameescape(root) .. '**/*' .. ext) local glob = root == '' and '**' or (vim.fn.fnameescape(root) .. '**/*' .. ext)
vim.cmd('lvimgrep /' .. vim.fn.escape(pat, '/') .. '/j ' .. glob) local ok = pcall(vim.cmd, 'lvimgrep /' .. vim.fn.escape(pat, '/') .. '/j ' .. glob)
if not ok then
vim.notify('nuwiki: no match for ' .. pat, vim.log.levels.WARN)
return
end
vim.cmd('lopen') vim.cmd('lopen')
end end