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>