feat(vim): close keymap gap with Neovim (47 → 63 maps)
CI / cargo fmt --check (push) Successful in 30s
CI / cargo clippy (push) Successful in 1m8s
CI / cargo test (push) Successful in 1m14s

The previous commit registered the parity surface on Neovim but only
ported ~75% to plain Vim. Filling the remaining 16:

autoload/nuwiki/commands.vim — new functions:
- `wiki_ui_select` — Vim has no `vim.ui.select`, so route through
  `inputlist()` after fetching the wiki list via the LSP.
- `open_below_with_bullet` / `open_above_with_bullet` — port of the
  Lua `o` / `O` continuation that preserves the list marker (and a
  `[ ]` checkbox when present) on the new line.
- `next_header` / `prev_header` / `next_sibling_header` /
  `prev_sibling_header` / `parent_header` — port of the Lua heading
  jumper. Pure VimL, no LSP round-trip.

ftplugin/vimwiki.vim (Vim path) new mappings:
- `<Leader>ws` → `wiki_ui_select`
- `]=` / `[=` → next / prev sibling header
- `]u` / `[u` → parent header
- `o` / `O` → bullet continuation
- `gl<Space>` / `gL<Space>` → :VimwikiRemove*CB stubs
- `gq1` / `gw1` → :VimwikiTableAlignQ1/W1 stubs
- x-mode variants for `+`, `<Leader>wc`, `gln`, `glp`, `glx`

Replaced the regex-based `]]` / `[[` (which just searched `^\s*=\+\s`)
with calls into the new heading nav so they skip non-heading `=`
runs and respect heading levels.

Verified end-to-end: `silent map <buffer>` reports 63 maps on Vim,
matching Neovim's 63. All 377 Rust tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-12 00:50:49 +00:00
parent 9e6faa5554
commit d58a34a2d7
2 changed files with 135 additions and 2 deletions
+117
View File
@@ -65,6 +65,123 @@ function! nuwiki#commands#wiki_index(count) abort
\ function('s:open_uri_from')) \ function('s:open_uri_from'))
endfunction endfunction
" Vim equivalent of the Lua `wiki_ui_select` — receives the list, asks
" via `inputlist()` (no `vim.ui.select` on plain Vim), then opens.
function! nuwiki#commands#wiki_ui_select() abort
call s:exec('nuwiki.wiki.select', [{}],
\ function('s:wiki_pick'))
endfunction
function! s:wiki_pick(notification) abort
let l:rows = get(get(a:notification, 'response', {}), 'result', [])
if type(l:rows) != type([]) || empty(l:rows)
echom 'nuwiki: no wikis configured'
return
endif
let l:prompt = ['Pick a wiki:']
let l:i = 0
for l:w in l:rows
let l:i += 1
call add(l:prompt, l:i . '. ' . get(l:w, 'name', '?')
\ . ' (' . get(l:w, 'root', '?') . ')')
endfor
let l:choice = inputlist(l:prompt)
if l:choice < 1 || l:choice > len(l:rows)
return
endif
let l:wiki_id = get(l:rows[l:choice - 1], 'id', l:choice - 1)
call s:exec('nuwiki.wiki.openIndex', [{ 'wiki': l:wiki_id }],
\ function('s:open_uri_from'))
endfunction
" Pure-VimL bullet-continuation for `o` / `O` — mirrors the Lua side
" so re-pressing the key keeps the list marker (and checkbox if any).
function! nuwiki#commands#open_below_with_bullet() abort
let l:line = getline('.')
let l:match = matchlist(l:line, '^\(\s*\)\([-*#]\)\s')
if empty(l:match)
call feedkeys('o', 'n')
return
endif
let l:prefix = l:match[1] . l:match[2] . ' '
if l:line =~# '^\s*[-*#]\s\+\[[ xXoO.\-]\]'
let l:prefix .= '[ ] '
endif
call feedkeys('o' . l:prefix, 'n')
endfunction
function! nuwiki#commands#open_above_with_bullet() abort
let l:line = getline('.')
let l:match = matchlist(l:line, '^\(\s*\)\([-*#]\)\s')
if empty(l:match)
call feedkeys('O', 'n')
return
endif
let l:prefix = l:match[1] . l:match[2] . ' '
call feedkeys('O' . l:prefix, 'n')
endfunction
" ===== Heading navigation (pure VimL) =====
function! s:heading_level(line) abort
let l:lead = matchstr(a:line, '^\s*\zs=\+\ze\s')
if l:lead ==# ''
return 0
endif
let l:trail = matchstr(a:line, '\s\zs=\+\ze\s*$')
if len(l:trail) != len(l:lead)
return 0
endif
return len(l:lead)
endfunction
function! s:current_heading_level() abort
let l:lnum = line('.')
while l:lnum > 0
let l:lvl = s:heading_level(getline(l:lnum))
if l:lvl > 0
return [l:lvl, l:lnum]
endif
let l:lnum -= 1
endwhile
return [0, 0]
endfunction
function! s:jump_heading(direction, predicate) abort
let l:total = line('$')
let l:i = line('.') + a:direction
while l:i >= 1 && l:i <= l:total
let l:lvl = s:heading_level(getline(l:i))
if l:lvl > 0 && a:predicate(l:lvl, l:i)
call cursor(l:i, 1)
return
endif
let l:i += a:direction
endwhile
endfunction
function! nuwiki#commands#next_header() abort
call s:jump_heading(1, {l, n -> 1})
endfunction
function! nuwiki#commands#prev_header() abort
call s:jump_heading(-1, {l, n -> 1})
endfunction
function! nuwiki#commands#next_sibling_header() abort
let [l:lvl, _] = s:current_heading_level()
call s:jump_heading(1, {l, n -> l <= l:lvl})
endfunction
function! nuwiki#commands#prev_sibling_header() abort
let [l:lvl, _] = s:current_heading_level()
call s:jump_heading(-1, {l, n -> l <= l:lvl})
endfunction
function! nuwiki#commands#parent_header() abort
let [l:lvl, _] = s:current_heading_level()
if l:lvl <= 1
return
endif
call s:jump_heading(-1, {l, n -> l < l:lvl})
endfunction
function! nuwiki#commands#wiki_tab_index(count) abort function! nuwiki#commands#wiki_tab_index(count) abort
let l:args = a:count > 0 ? [{ 'wiki': a:count - 1 }] : [{}] let l:args = a:count > 0 ? [{ 'wiki': a:count - 1 }] : [{}]
call s:exec('nuwiki.wiki.tabOpenIndex', l:args, call s:exec('nuwiki.wiki.tabOpenIndex', l:args,
+18 -2
View File
@@ -113,6 +113,7 @@ if !has('nvim')
" Wiki prefix " Wiki prefix
nnoremap <silent><buffer> <Leader>ww :call nuwiki#commands#diary_today()<CR> nnoremap <silent><buffer> <Leader>ww :call nuwiki#commands#diary_today()<CR>
nnoremap <silent><buffer> <Leader>wt :call nuwiki#commands#diary_today()<CR> nnoremap <silent><buffer> <Leader>wt :call nuwiki#commands#diary_today()<CR>
nnoremap <silent><buffer> <Leader>ws :call nuwiki#commands#wiki_ui_select()<CR>
nnoremap <silent><buffer> <Leader>wi :call nuwiki#commands#diary_index()<CR> nnoremap <silent><buffer> <Leader>wi :call nuwiki#commands#diary_index()<CR>
nnoremap <silent><buffer> <Leader>w<Leader>w :call nuwiki#commands#diary_today()<CR> nnoremap <silent><buffer> <Leader>w<Leader>w :call nuwiki#commands#diary_today()<CR>
nnoremap <silent><buffer> <Leader>w<Leader>y :call nuwiki#commands#diary_yesterday()<CR> nnoremap <silent><buffer> <Leader>w<Leader>y :call nuwiki#commands#diary_yesterday()<CR>
@@ -129,10 +130,12 @@ if !has('nvim')
nnoremap <silent><buffer> <Tab> /\[\[<CR>:nohlsearch<CR> nnoremap <silent><buffer> <Tab> /\[\[<CR>:nohlsearch<CR>
nnoremap <silent><buffer> <S-Tab> ?\[\[<CR>:nohlsearch<CR> nnoremap <silent><buffer> <S-Tab> ?\[\[<CR>:nohlsearch<CR>
nnoremap <silent><buffer> + :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiNormalizeLink not yet implemented — see SPEC §13.1'<bar>echohl None<CR> nnoremap <silent><buffer> + :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiNormalizeLink not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
xnoremap <silent><buffer> + :<C-u>echohl WarningMsg<bar>echom 'nuwiki: :VimwikiNormalizeLink not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> <Leader>wn :call nuwiki#commands#wiki_goto_page('')<CR> nnoremap <silent><buffer> <Leader>wn :call nuwiki#commands#wiki_goto_page('')<CR>
nnoremap <silent><buffer> <Leader>wd :call nuwiki#commands#delete_file()<CR> nnoremap <silent><buffer> <Leader>wd :call nuwiki#commands#delete_file()<CR>
nnoremap <silent><buffer> <Leader>wr :call nuwiki#commands#rename_file()<CR> nnoremap <silent><buffer> <Leader>wr :call nuwiki#commands#rename_file()<CR>
nnoremap <silent><buffer> <Leader>wc :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiColorize not yet implemented — see SPEC §13.1'<bar>echohl None<CR> nnoremap <silent><buffer> <Leader>wc :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiColorize not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
xnoremap <silent><buffer> <Leader>wc :<C-u>echohl WarningMsg<bar>echom 'nuwiki: :VimwikiColorize not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
" Diary nav " Diary nav
nnoremap <silent><buffer> <C-Down> :call nuwiki#commands#diary_next()<CR> nnoremap <silent><buffer> <C-Down> :call nuwiki#commands#diary_next()<CR>
@@ -145,20 +148,31 @@ if !has('nvim')
xnoremap <silent><buffer> <C-@> :<C-u>call nuwiki#commands#toggle_list_item()<CR> xnoremap <silent><buffer> <C-@> :<C-u>call nuwiki#commands#toggle_list_item()<CR>
nnoremap <silent><buffer> gnt :call nuwiki#commands#next_task()<CR> nnoremap <silent><buffer> gnt :call nuwiki#commands#next_task()<CR>
nnoremap <silent><buffer> gln :call nuwiki#commands#cycle_list_item()<CR> nnoremap <silent><buffer> gln :call nuwiki#commands#cycle_list_item()<CR>
xnoremap <silent><buffer> gln :<C-u>call nuwiki#commands#cycle_list_item()<CR>
nnoremap <silent><buffer> glp :call nuwiki#commands#cycle_list_item()<CR> nnoremap <silent><buffer> glp :call nuwiki#commands#cycle_list_item()<CR>
xnoremap <silent><buffer> glp :<C-u>call nuwiki#commands#cycle_list_item()<CR>
nnoremap <silent><buffer> glx :call nuwiki#commands#reject_list_item()<CR> nnoremap <silent><buffer> glx :call nuwiki#commands#reject_list_item()<CR>
xnoremap <silent><buffer> glx :<C-u>call nuwiki#commands#reject_list_item()<CR>
nnoremap <silent><buffer> glh :echohl WarningMsg<bar>echom 'nuwiki: list level not yet implemented — see SPEC §13.1'<bar>echohl None<CR> nnoremap <silent><buffer> glh :echohl WarningMsg<bar>echom 'nuwiki: list level not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> gll :echohl WarningMsg<bar>echom 'nuwiki: list level not yet implemented — see SPEC §13.1'<bar>echohl None<CR> nnoremap <silent><buffer> gll :echohl WarningMsg<bar>echom 'nuwiki: list level not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> gLh :echohl WarningMsg<bar>echom 'nuwiki: list level subtree not yet implemented — see SPEC §13.1'<bar>echohl None<CR> nnoremap <silent><buffer> gLh :echohl WarningMsg<bar>echom 'nuwiki: list level subtree not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> gLl :echohl WarningMsg<bar>echom 'nuwiki: list level subtree not yet implemented — see SPEC §13.1'<bar>echohl None<CR> nnoremap <silent><buffer> gLl :echohl WarningMsg<bar>echom 'nuwiki: list level subtree not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> glr :echohl WarningMsg<bar>echom 'nuwiki: list renumber not yet implemented — see SPEC §13.1'<bar>echohl None<CR> nnoremap <silent><buffer> glr :echohl WarningMsg<bar>echom 'nuwiki: list renumber not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> gLr :echohl WarningMsg<bar>echom 'nuwiki: list renumber-all not yet implemented — see SPEC §13.1'<bar>echohl None<CR> nnoremap <silent><buffer> gLr :echohl WarningMsg<bar>echom 'nuwiki: list renumber-all not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> gl<Space> :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiRemoveSingleCB not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> gL<Space> :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiRemoveCBInList not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> o :call nuwiki#commands#open_below_with_bullet()<CR>
nnoremap <silent><buffer> O :call nuwiki#commands#open_above_with_bullet()<CR>
" Headers " Headers
nnoremap <silent><buffer> = :call nuwiki#commands#heading_add()<CR> nnoremap <silent><buffer> = :call nuwiki#commands#heading_add()<CR>
nnoremap <silent><buffer> - :call nuwiki#commands#heading_remove()<CR> nnoremap <silent><buffer> - :call nuwiki#commands#heading_remove()<CR>
nnoremap <silent><buffer> ]] /^\s*=\+\s<CR>:nohlsearch<CR> nnoremap <silent><buffer> ]] :call nuwiki#commands#next_header()<CR>
nnoremap <silent><buffer> [[ ?^\s*=\+\s<CR>:nohlsearch<CR> nnoremap <silent><buffer> [[ :call nuwiki#commands#prev_header()<CR>
nnoremap <silent><buffer> ]= :call nuwiki#commands#next_sibling_header()<CR>
nnoremap <silent><buffer> [= :call nuwiki#commands#prev_sibling_header()<CR>
nnoremap <silent><buffer> ]u :call nuwiki#commands#parent_header()<CR>
nnoremap <silent><buffer> [u :call nuwiki#commands#parent_header()<CR>
" HTML export " HTML export
nnoremap <silent><buffer> <Leader>wh :call nuwiki#commands#export_current()<CR> nnoremap <silent><buffer> <Leader>wh :call nuwiki#commands#export_current()<CR>
@@ -167,7 +181,9 @@ if !has('nvim')
" Tables (deferred §13.1) " Tables (deferred §13.1)
nnoremap <silent><buffer> gqq :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiTableAlignQ not yet implemented — see SPEC §13.1'<bar>echohl None<CR> nnoremap <silent><buffer> gqq :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiTableAlignQ not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> gq1 :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiTableAlignQ1 not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> gww :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiTableAlignW not yet implemented — see SPEC §13.1'<bar>echohl None<CR> nnoremap <silent><buffer> gww :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiTableAlignW not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> gw1 :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiTableAlignW1 not yet implemented — see SPEC §13.1'<bar>echohl None<CR>
nnoremap <silent><buffer> <A-Left> :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiTableMoveColumnLeft not yet implemented'<bar>echohl None<CR> nnoremap <silent><buffer> <A-Left> :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiTableMoveColumnLeft not yet implemented'<bar>echohl None<CR>
nnoremap <silent><buffer> <A-Right> :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiTableMoveColumnRight not yet implemented'<bar>echohl None<CR> nnoremap <silent><buffer> <A-Right> :echohl WarningMsg<bar>echom 'nuwiki: :VimwikiTableMoveColumnRight not yet implemented'<bar>echohl None<CR>
endif endif