feat(13.1-B): table rewriters — insert, align, moveColumn

Closes the table-rewriter cluster from SPEC §13.1.

Server-side (ops module):
- `render_blank_table(cols, rows)` — pure templating: header row,
  separator `|--|--|--|`, then `rows` empty data rows. Wired through
  `table_insert` which dispatches a `TextEdit` at the cursor.
- `table_align_edit` — locates the `TableNode` containing the cursor
  line, computes max width per column across every row, re-emits the
  table with each cell space-padded to its column's width. The
  parser drops `|---|---|` separator rows but sets
  `TableNode.has_header`; the renderer re-inserts a padded separator
  after the header so the result still parses.
- `table_move_column_edit` — column-under-cursor swap with the
  left or right neighbour (`dir = "left" | "right"`). Cursor column
  is computed by counting pipe separators before the cursor's byte
  offset on the row's line. Column widths swap alongside the data so
  the post-swap table stays aligned. No-ops cleanly when the swap
  would fall off either edge.

Editor glue:
- `lua/nuwiki/commands.lua` / `autoload/nuwiki/commands.vim` — the
  three "not yet implemented" stubs are replaced with real LSP
  dispatchers. `table_insert` accepts optional `cols`/`rows`
  arguments (defaults: 3×2).
- Default keymaps `gqq` / `gq1` / `gww` / `gw1` now call
  `table_align`; `<A-Left>` / `<A-Right>` call
  `table_move_column_left` / `_right`. No more "deferred"
  notifications on the table keys.

Tests: 8 new in `cluster_b_table_rewriters.rs` — blank-table shape
(3×2 + 1×1), column-width alignment with separator-row repad, swap-
right shape, swap-left clamp at column 0, no-table-found fallbacks,
COMMANDS list completeness. Total 410 Rust tests pass; clippy clean;
Neovim keymap harness still 20/20.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-12 14:41:51 +00:00
parent 9d34c8baa2
commit 4245424d2f
6 changed files with 539 additions and 20 deletions
+41 -4
View File
@@ -513,14 +513,51 @@ function! nuwiki#commands#list_change_lvl(...) abort
let l:delta = (l:dir ==# 'increase' || l:dir ==# 'indent') ? 1 : -1
call nuwiki#commands#list_change_level(l:delta, 0)
endfunction
function! nuwiki#commands#table_insert() abort
call s:notify_deferred(':VimwikiTable')
" §13.1 Cluster B — table rewriters.
function! nuwiki#commands#table_insert(...) abort
let l:cols = a:0 >= 1 ? str2nr(a:1) : 3
let l:rows = a:0 >= 2 ? str2nr(a:2) : 2
if l:cols <= 0
let l:cols = 3
endif
if l:rows <= 0
let l:rows = 2
endif
let l:p = s:cursor_position()
let l:args = [{
\ 'uri': l:p['textDocument']['uri'],
\ 'position': l:p['position'],
\ 'cols': l:cols,
\ 'rows': l:rows,
\ }]
call s:exec('nuwiki.table.insert', l:args)
endfunction
function! nuwiki#commands#table_align() abort
let l:p = s:cursor_position()
let l:args = [{ 'uri': l:p['textDocument']['uri'], 'position': l:p['position'] }]
call s:exec('nuwiki.table.align', l:args)
endfunction
function! nuwiki#commands#table_move_left() abort
call s:notify_deferred(':VimwikiTableMoveColumnLeft')
let l:p = s:cursor_position()
let l:args = [{
\ 'uri': l:p['textDocument']['uri'],
\ 'position': l:p['position'],
\ 'dir': 'left',
\ }]
call s:exec('nuwiki.table.moveColumn', l:args)
endfunction
function! nuwiki#commands#table_move_right() abort
call s:notify_deferred(':VimwikiTableMoveColumnRight')
let l:p = s:cursor_position()
let l:args = [{
\ 'uri': l:p['textDocument']['uri'],
\ 'position': l:p['position'],
\ 'dir': 'right',
\ }]
call s:exec('nuwiki.table.moveColumn', l:args)
endfunction
function! nuwiki#commands#colorize(color) abort
call s:notify_deferred(':VimwikiColorize')