parity(2): insert-mode list bindings (<C-D>/<C-T>/<C-L><C-?>)
Match upstream vimwiki's insert-mode list editing: <C-D> list_change_level(-1) dedent current item <C-T> list_change_level(+1) indent current item <C-L><C-J> list_cycle_symbol(+1) cycle marker forward <C-L><C-K> list_cycle_symbol(-1) cycle marker backward <C-L><C-M> list_toggle_or_add_chk toggle if has checkbox, else add `[ ]` Cycle order matches vimwiki's canonical run: - → * → # → 1. → 1) → a) → A) → i) → I) → (wrap) Both Lua and VimL paths wired. Lua callbacks fire directly (no `<C-o>` dance) since list_change_level / changeSymbol mutate the buffer via the LSP applyEdit pipeline, which works cleanly in insert mode. VimL keeps the `<C-o>:call …<CR>` idiom since that's the standard there. Harness adds 5 cases covering the new insert-mode bindings plus one direct LSP roundtrip for changeSymbol — surfaced a long-standing stale-binary footgun in test-keymaps.sh (rebuilt only when bin was missing; now rebuilds every run since incremental cargo is fast). Harness also captures server log_messages and dumps them on failure so future swallowed-error bugs (Err → log + Ok(None)) are visible. Gates: 421 Rust / 25 Neovim / 12 Vim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -515,6 +515,73 @@ function M.list_change_lvl(direction)
|
||||
M.list_change_level(delta, false)
|
||||
end
|
||||
|
||||
--- Cycle the list marker forward (`direction = 1`) or backward
|
||||
--- (`direction = -1`). Pure client-side: detects the current line's
|
||||
--- marker via regex, picks the next symbol in vimwiki's canonical
|
||||
--- order, and dispatches `list.changeSymbol`.
|
||||
local _symbol_order = { '-', '*', '#', '1.', '1)', 'a)', 'A)', 'i)', 'I)' }
|
||||
|
||||
local function detect_current_symbol()
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
-- Match optional indent, marker, then whitespace.
|
||||
local indent, marker = line:match('^(%s*)([%-%*%#]) ')
|
||||
if marker then return marker end
|
||||
local n
|
||||
indent, n, marker = line:match('^(%s*)(%d+)([%.%)]) ')
|
||||
if marker then return '1' .. marker end
|
||||
-- Roman lower
|
||||
indent, marker = line:match('^(%s*)([ivxlcdm]+)%) ')
|
||||
if marker then return 'i)' end
|
||||
-- Roman upper
|
||||
indent, marker = line:match('^(%s*)([IVXLCDM]+)%) ')
|
||||
if marker then return 'I)' end
|
||||
-- Alpha lower (single letter or short run)
|
||||
indent, marker = line:match('^(%s*)([a-z]+)%) ')
|
||||
if marker then return 'a)' end
|
||||
indent, marker = line:match('^(%s*)([A-Z]+)%) ')
|
||||
if marker then return 'A)' end
|
||||
-- Suppress unused warning
|
||||
local _ = indent
|
||||
return nil
|
||||
end
|
||||
|
||||
function M.list_cycle_symbol(direction)
|
||||
local current = detect_current_symbol()
|
||||
if not current then return end
|
||||
local idx
|
||||
for i, s in ipairs(_symbol_order) do
|
||||
if s == current then idx = i break end
|
||||
end
|
||||
if not idx then return end
|
||||
local next_idx = ((idx - 1 + (direction or 1)) % #_symbol_order) + 1
|
||||
M.list_change_symbol(_symbol_order[next_idx], false)
|
||||
end
|
||||
|
||||
--- `<C-L><C-M>` (insert mode) — toggle the checkbox on the current
|
||||
--- item if any, OR insert `[ ]` after the marker if the line is a
|
||||
--- plain list item without one. Pure client-side.
|
||||
function M.list_toggle_or_add_checkbox()
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
-- Already has a checkbox? Let the server's toggle handle it.
|
||||
if line:match('%s*[%-%*%#]%s+%[[%sxXoO%.%-]%]') or
|
||||
line:match('%s*%w+[%.%)]%s+%[[%sxXoO%.%-]%]') then
|
||||
M.toggle_list_item()
|
||||
return
|
||||
end
|
||||
-- Looks like a list item without a checkbox — insert `[ ] ` after
|
||||
-- the marker.
|
||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local insert_at = nil
|
||||
local function try(pattern)
|
||||
local start_, finish = line:find(pattern)
|
||||
if start_ then return finish end
|
||||
end
|
||||
insert_at = try('^%s*[%-%*%#] ') or try('^%s*%w+[%.%)] ')
|
||||
if not insert_at then return end
|
||||
local new_line = line:sub(1, insert_at) .. '[ ] ' .. line:sub(insert_at + 1)
|
||||
vim.api.nvim_buf_set_lines(0, row - 1, row, false, { new_line })
|
||||
end
|
||||
|
||||
-- §13.1 Cluster B — table rewriters.
|
||||
|
||||
function M.table_insert(cols, rows)
|
||||
|
||||
Reference in New Issue
Block a user