feat(13.1-A): list rewriters — removeDone, renumber, changeSymbol/Level

Closes the four-command list-rewriter cluster from SPEC §13.1.

Server-side (commands.rs ops module):
- `parse_symbol` / `render_marker` — round-trip between
  `:VimwikiListChangeSymbol` arg shapes (`-`, `1.`, `a)`, `i)`,
  `Dash`, `Numeric`, …) and the rendered marker text. `render_marker`
  knows how to spell `a/b/…/z/aa` and `i/ii/iv/v/…/MMM` for the
  alphabetic + roman variants.
- `remove_done_edit` — walks every list (recursively through
  blockquotes and sublists), emits delete TextEdits for items whose
  checkbox is `Done` or `Rejected`. Item span gets extended through
  the trailing newline so we don't leave behind empty lines. Accepts
  an optional `position` to scope the operation to the item under
  cursor + its descendants.
- `renumber_edit` — finds the list containing the cursor line (or
  every list when `whole_file: true`), re-sequences numeric
  markers in-place. Unordered lists are left alone.
- `change_symbol_edit` — rewrites the leading marker on a single
  item, or every item in a list when `whole_list: true`. Uses
  `render_marker` so ordered variants get the right index.
- `change_level_edit` — re-indents the marker line (or every line of
  the item subtree when `whole_subtree: true`) by ±2 spaces per
  level. Dedent clamps at column 0.
- `find_list_at_line` + `find_marker_span` — pure helpers reused by
  the three above.

Editor glue:
- `lua/nuwiki/commands.lua` / `autoload/nuwiki/commands.vim` —
  removed all four "not yet implemented" stubs and wired them to the
  real LSP commands. Lua also exposes `list_change_lvl(direction)`
  for the `:VimwikiListChangeLvl decrease|increase` compat entry.
- Keymaps for `glh` / `gll` / `gLh` / `gLl` (list level single +
  subtree), `glr` / `gLr` (renumber list + whole-file),
  `gl<Space>` / `gL<Space>` (remove done items) now hit the real
  commands instead of printing a "deferred" notification.

Tests: 16 new in `cluster_a_list_rewriters.rs` covering
symbol parsing, marker rendering (alpha + roman + numeric),
removeDone shape, scoped removeDone, no-match cases, renumber
sequencing, whole-file walk, changeSymbol single + whole-list,
changeLevel single + subtree + clamp, and COMMANDS list completeness.
Total 402 Rust tests pass; clippy clean; keymap harness still at
20/20.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-12 14:37:11 +00:00
parent cebc806ce3
commit 9d34c8baa2
6 changed files with 983 additions and 23 deletions
+37 -3
View File
@@ -437,9 +437,43 @@ local function _not_yet(name)
end
end
M.list_change_lvl = _not_yet(':VimwikiListChangeLvl')
M.list_renumber = _not_yet(':VimwikiRenumber')
M.list_remove_done = _not_yet(':VimwikiRemoveDone')
-- §13.1 Cluster A — list rewriters.
function M.list_remove_done()
exec('nuwiki.list.removeDone', uri_args())
end
function M.list_renumber()
exec('nuwiki.list.renumber', pos_args())
end
function M.list_renumber_all()
local args = pos_args()[1]
args.whole_file = true
exec('nuwiki.list.renumber', { args })
end
function M.list_change_symbol(symbol, whole_list)
local args = pos_args()[1]
args.symbol = symbol
args.whole_list = whole_list and true or false
exec('nuwiki.list.changeSymbol', { args })
end
function M.list_change_level(delta, whole_subtree)
local args = pos_args()[1]
args.delta = delta
args.whole_subtree = whole_subtree and true or false
exec('nuwiki.list.changeLevel', { args })
end
-- Vimwiki's `:VimwikiListChangeLvl decrease|increase 0` keeps a single
-- entry point. Forward to changeLevel.
function M.list_change_lvl(direction)
local delta = (direction == 'increase' or direction == 'indent') and 1 or -1
M.list_change_level(delta, false)
end
M.table_insert = _not_yet(':VimwikiTable')
M.table_move_column_left = _not_yet(':VimwikiTableMoveColumnLeft')
M.table_move_column_right = _not_yet(':VimwikiTableMoveColumnRight')
+16 -8
View File
@@ -220,14 +220,22 @@ function M.attach(bufnr, mappings)
map('x', 'glp', cmd.cycle_list_item, { desc = 'nuwiki: decrement checkbox' }, bufnr)
map('n', 'glx', cmd.reject_list_item, { desc = 'nuwiki: reject checkbox' }, bufnr)
map('x', 'glx', cmd.reject_list_item, { desc = 'nuwiki: reject checkbox' }, bufnr)
map('n', 'glh', deferred(':VimwikiListDecreaseLvl'), { desc = 'nuwiki: list dedent (deferred)' }, bufnr)
map('n', 'gll', deferred(':VimwikiListIncreaseLvl'), { desc = 'nuwiki: list indent (deferred)' }, bufnr)
map('n', 'gLh', deferred(':VimwikiListDecreaseLvlSubtree'), { desc = 'nuwiki: list dedent subtree (deferred)' }, bufnr)
map('n', 'gLl', deferred(':VimwikiListIncreaseLvlSubtree'), { desc = 'nuwiki: list indent subtree (deferred)' }, bufnr)
map('n', 'glr', deferred(':VimwikiRenumberList'), { desc = 'nuwiki: renumber list (deferred)' }, bufnr)
map('n', 'gLr', deferred(':VimwikiRenumberAllLists'), { desc = 'nuwiki: renumber all lists (deferred)' }, bufnr)
map('n', 'gl<Space>', deferred(':VimwikiRemoveSingleCB'), { desc = 'nuwiki: remove checkbox (deferred)' }, bufnr)
map('n', 'gL<Space>', deferred(':VimwikiRemoveCBInList'), { desc = 'nuwiki: remove all checkboxes (deferred)' }, bufnr)
map('n', 'glh', function() cmd.list_change_level(-1, false) end,
{ desc = 'nuwiki: list dedent' }, bufnr)
map('n', 'gll', function() cmd.list_change_level(1, false) end,
{ desc = 'nuwiki: list indent' }, bufnr)
map('n', 'gLh', function() cmd.list_change_level(-1, true) end,
{ desc = 'nuwiki: list dedent subtree' }, bufnr)
map('n', 'gLl', function() cmd.list_change_level(1, true) end,
{ desc = 'nuwiki: list indent subtree' }, bufnr)
map('n', 'glr', cmd.list_renumber,
{ desc = 'nuwiki: renumber list' }, bufnr)
map('n', 'gLr', cmd.list_renumber_all,
{ desc = 'nuwiki: renumber all lists' }, bufnr)
map('n', 'gl<Space>', cmd.list_remove_done,
{ desc = 'nuwiki: remove done items' }, bufnr)
map('n', 'gL<Space>', cmd.list_remove_done,
{ desc = 'nuwiki: remove done items (whole doc)' }, bufnr)
map('n', 'o', open_below_with_bullet, { desc = 'nuwiki: open below + bullet' }, bufnr)
map('n', 'O', open_above_with_bullet, { desc = 'nuwiki: open above + bullet' }, bufnr)
end