29 Commits

Author SHA1 Message Date
gffranco 4c187fee3c fix(tables): don't split a cell on a | inside a link/code/escape
CI / editor tests (push) Successful in 46s
Table auto-alignment scanned for cell separators with a naive find('|'),
so a cell containing a vimwiki link `[[url|title]]` was split at the link's
internal pipe — mangling both the link (`[[url` / `title]]`) and the table
(a phantom extra column). Same bug in both the Lua (Neovim) and VimL (Vim)
table code, in both table_cell_starts and parse_table_row.

Add a shared cell-separator scanner (cell_bar_positions) that treats `|` as
literal — not a separator — when it's inside `[[…]]` wikilinks, `{{…}}`
transclusions, `` `…` `` inline code, or backslash-escaped (`\|`), matching
vimwiki. Both scan functions in each client now use it.

Regression tests added on both clients (cr.table_link_cell_pipe_not_a_separator);
full harness green (Neovim 308, Vim 302).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 11:57:16 +00:00
gffranco 87d14310fc feat(config): P3 config batch — group 2 (create_link, dir_link, auto_header)
- create_link (default true): server resolve_target_uri now only synthesises a
  missing-page URI when create_link is set; when off, following a link to a
  non-existent page returns no location (no-op).
- dir_link: a [[dir/]] link now resolves to <dir>/<dir_link><ext> when dir_link
  is set, else opens the directory itself. Uses the already-parsed
  LinkTarget.is_directory.
- auto_header (default off): new wiki pages get a `= Stem =` header derived from
  the filename, skipping the wiki index + diary index. Client-side BufNewFile
  autocmd in both clients (init.lua + plugin/nuwiki.vim), with auto_header
  handlers in both command layers (trailing-slash-robust root matching).

Tests: cmd.auto_header_inserts + cmd.auto_header_skips_diary_index (nvim) /
cmd.auto_header_skips_index (vim). Full rust suite + both harnesses green
(Neovim 307, Vim 301/18/21).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 12:19:37 +00:00
gffranco 724712121d feat(parity): close the entire P3 Mappings section
Both remaining mapping gaps (client-side, both clients):

- Visual <CR>: upstream binds it to NormalizeLinkVisualCR (== visual `+`).
  Added `x <CR>` -> normalize_link(true) (wrap the selection as a wikilink)
  in both clients.

- Insert <S-CR>: upstream's multiline-list-item continuation (VimwikiReturn
  2 2 -> kbd_cr with no new marker). New smart_shift_return (both clients,
  <expr> insert mapping): on a list item returns <CR> + spaces aligning under
  the item text (marker width + 1, +4 for a `[ ] ` checkbox), no marker; off a
  list item, a plain <CR>. Mirrors smart_return's auto-indent handling.

Tests: map.visual_cr_wraps_selection + map.insert_shift_cr_multiline
(test-keymaps.lua, the latter exercising the handler directly since <S-CR>
doesn't round-trip headless feedkeys), and map.visual_cr_wraps_selection +
cr.shift_cr_multiline{,_checkbox} (test-keymaps-vim.vim). Docs (README +
doc/nuwiki.txt) and the gap doc updated. Neovim 305, Vim 299/18/21 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 11:04:56 +00:00
gffranco 6deba47106 fix(search): graceful no-match + NuwikiSearch alias (re-audit follow-up)
CI / cargo fmt --check (push) Successful in 28s
CI / cargo clippy (push) Successful in 29s
CI / cargo test (push) Successful in 35s
CI / editor keymaps (push) Successful in 1m25s
Re-audit of the just-landed command work found one real bug I introduced
and a convention gap:

- VimwikiSearch / VWS raised a raw E480 on a no-match search; upstream
  reports it gracefully. Both clients now catch it (try/catch in Vim,
  pcall in Neovim) and emit "nuwiki: no match for <pat>".

- Added a NuwikiSearch alias alongside VimwikiSearch/VWS (every other
  command carries a Nuwiki* form).

Gap-doc note corrected: nuwiki's search populates + opens the location
list (shows all matches) where upstream jumps to the first match — logged
as a minor presentation divergence rather than claiming exact parity.

Config + mappings re-audits came back clean (no new gaps, no regressions;
table-mapping rewire verified non-recursive, gLH/gLL/gLR present).

Tests: cmd.VimwikiSearch_no_match_graceful, surface.{Vimwiki,Nuwiki}Search.
Neovim 301, Vim 294/18/21 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 01:28:44 +00:00
gffranco a11b742fc1 feat(parity): close the entire P3 Commands section
CI / cargo fmt --check (push) Successful in 17s
CI / cargo clippy (push) Successful in 24s
CI / cargo test (push) Successful in 42s
CI / editor keymaps (push) Successful in 1m40s
All six remaining command gaps (client-side; no server change):

- VimwikiRenameFile: bare -> -nargs=? (arg accepted-ignored; rename still
  delegates to the LSP rename prompt). No more E488.

- VimwikiVar / NuwikiVar: get/set the client config (upstream vimwiki#vars#cmd).
  No arg prints config (Vim: g:nuwiki_*; Neovim: resolved setup() opts), one arg
  gets a key, two+ sets it. Global command, both clients.

- VimwikiReturn / NuwikiReturn: command form of the smart <CR> continuation —
  enters insert at EOL and fires the <CR> mapping (return_cmd / vimwiki_return).
  Upstream's mode-flag args accepted but unused.

- VimwikiTableAlignQ vs AlignW: corrected — upstream's gqq/gww are identical on
  a table; the only difference is the non-table fallback (native `normal! gqq`
  vs `gww`). New table_align_or_cmd(cmd) aligns on a table row, else runs
  `normal! <cmd>`. Q/gqq/gq1 -> gqq; W/gww/gw1 -> gww; NuwikiTableAlign -> gqq.

- VimwikiSearch / VWS: scope the lvimgrep to the current wiki's root (resolved
  client-side) over <root>/**/*<ext>, not CWD `**`; empty pattern reuses the
  last search. Both clients.

- VimwikiIndex family: add global Vimwiki/NuwikiIndex + TabIndex entry points
  (plugin/nuwiki.vim + init.lua _setup_global_commands, with -count), so a wiki
  opens from any buffer. Buffer-local copies still shadow inside wiki buffers.

Tests: surface.{Vimwiki,Nuwiki}{Return,Var}, cmd.VimwikiVar_sets_*,
cmd.global_entry_points (both harnesses). Docs (README + doc/nuwiki.txt) and the
gap doc updated. Neovim 299, Vim 291/18/21 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 01:23:07 +00:00
gffranco 3865b8bf0e fix(parity): fifth-pass re-audit — VimwikiGoto nargs, autowriteall, table_auto_fmt
CI / cargo fmt --check (push) Successful in 26s
CI / cargo clippy (push) Successful in 37s
CI / cargo test (push) Successful in 40s
CI / editor keymaps (push) Successful in 1m35s
Closes the actionable fifth-pass findings (gap doc updated):

- VimwikiGoto / NuwikiGoto: -nargs=1 -> -nargs=* in all four defs. Was a
  real bug — `:VimwikiGoto` raised E471, `:VimwikiGoto My Page` raised E488,
  and the handler's empty-arg prompt fallback was unreachable. Both clients
  already prompt on empty, so -nargs=* (keeping -complete=pages) restores
  upstream behavior.

- autowriteall (upstream default ON): while a wiki buffer is current, mirror
  Vim's global 'autowriteall' (auto-save on page switch / :make), restoring
  the prior value on leave. Neovim via ftplugin.lua setup_autowriteall
  (BufEnter/BufLeave) gated by the `autowriteall` setup option; Vim via the
  NuwikiAutoWriteAll augroup gated by g:nuwiki_autowriteall.

- table_auto_fmt (upstream default ON): re-align the table under the cursor
  on InsertLeave. Both clients, gated by `table_auto_fmt` / g:nuwiki_table_auto_fmt,
  guarded on the cursor line containing `|` before the async table_align.

Also logged (no code): VimwikiRenameFile missing -nargs=? (subsumed by the
LSP-rename divergence), table_reduce_last_col, user_htmls, hl_headers/
hl_cb_checked, and a commentstring value-mismatch note. Mappings audit clean.

The Neovim harness disables table_auto_fmt in setup (its async re-align would
perturb the deterministic table-nav keystroke cases); its wiring is verified
on a throwaway scratch buffer instead. Docs (README + doc/nuwiki.txt) updated.
Tests: cmd.VimwikiGoto_accepts_multiword, config.autowriteall_applied,
config.table_auto_fmt_autocmd. Neovim 293, Vim 285/18/21 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 00:59:33 +00:00
gffranco c161f9d21a feat(parity): P3 quick-wins — ShowVersion, gLH/gLL/gLR, Search/Align nargs
CI / cargo fmt --check (push) Successful in 21s
CI / cargo clippy (push) Successful in 26s
CI / cargo test (push) Successful in 36s
CI / editor keymaps (push) Successful in 1m47s
Closes four low-risk P3 parity items (gap doc updated):

- VimwikiShowVersion / NuwikiShowVersion: new global command (both clients)
  echoing g:nuwiki_version (0.1.0) + the host editor, via
  nuwiki#commands#show_version / commands.show_version.

- gLH / gLL / gLR: upstream's case-variant aliases of gLh/gLl/gLr (dedent /
  indent whole item, renumber all lists) added in both clients.

- VimwikiSearch / VWS: -nargs=1 -> -nargs=* (Vim + Neovim), so a multi-word
  search no longer raises E488 and an empty invocation reuses the last search
  pattern. (The lvimgrep-vs-vimwiki-engine difference stays open.)

- VimwikiTableAlignQ / AlignW / NuwikiTableAlign: bare -> -nargs=?, so
  `:VimwikiTableAlignQ 2` no longer raises E488 (optional column arg is
  accepted-and-ignored; the gqq-align vs gww-align-without-resize split
  stays open).

Docs (doc/nuwiki.txt + README) updated for the command and the aliases.
Tests: surface.{Vimwiki,Nuwiki}ShowVersion, map[n].gL{H,L,R} (both
harnesses), cmd.search_and_tablealign_nargs (vim). Neovim 291, Vim
282/18/21 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 00:28:51 +00:00
gffranco 9441fe918c fix(parity): close the 2026-06-02 re-audit config/command findings
CI / cargo fmt --check (push) Successful in 19s
CI / cargo clippy (push) Successful in 37s
CI / cargo test (push) Successful in 29s
CI / editor keymaps (push) Successful in 1m36s
Implements the remaining fourth-pass findings (gap doc updated):

- list_margin: rework to upstream's buffer-side meaning. Drop the
  nuwiki-only HTML em-margin (renderer field/method + render_page_html
  param removed) and prepend max(0, list_margin) leading spaces to every
  generated bullet in build_toc_text / build_links_text /
  build_tag_links_text / diary::build_index_body; headings stay at col 0.
  From<RawWiki> derives 0 for markdown wikis when unset. Negatives can't
  resolve 'shiftwidth' server-side, so they collapse to zero indent
  (documented divergence).

- diary_months: per-wiki Vec<String> (default 12 English names), threaded
  into the diary-index month labels; missing/empty slots fall back to the
  English name.

- diary_caption_level: widen u8 -> i8 so vimwiki's -1 (min: -1) parses;
  build_index_body clamps < 0 to base tree level 0.

- VimwikiRemoveDone: regain upstream's -range. All four defs are now
  -bang -range, dispatched via remove_done(bang, range, l1, l2) in both
  clients: ! -> whole buffer, explicit range -> new list_remove_done_range
  ({range:[l1-1,l2-1]}), else current list. Server remove_done_edit gained
  an Option<(u32,u32)> range that filters whole-doc victims by start line.

markdown_header_style is deferred: the generators emit vimwiki syntax only
(caption_line never writes markdown headers), so there's no markdown header
to attach the style to. Logged as the "generated-content is vimwiki-only"
intentional divergence pending a later markdown generated-content effort.

Tests: list_margin indent, markdown list_margin-0 default, diary_months
custom + fallback, negative caption_level clamp/parse, ranged remove-done
(server + both keymap harnesses). 553 lsp/core tests pass; clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 10:50:38 +00:00
gffranco 079e7246ac fix(lists): VimwikiToggleRejectedListItem -range parity (P3)
CI / cargo fmt --check (push) Successful in 7m3s
CI / cargo clippy (push) Successful in 17m14s
CI / cargo test (push) Successful in 31m54s
CI / editor keymaps (push) Successful in 1m51s
Upstream's :VimwikiToggleRejectedListItem is -range and binds glx in
visual mode; nuwiki's four defs were bare, so a ranged invocation raised
E481 and acted cursor-only. Same -range class already fixed for
ToggleListItem/Increment/Decrement -- ToggleRejected was missed.

All four defs (Vim+Neovim x Vimwiki*/Nuwiki*) are now -range, routed
through a new reject_list_item_range(l1, l2) looping over_range in both
clients, mirroring toggle_list_item_range. Visual glx stays cursor-only,
consistent with its <C-Space>/gln/glp siblings.

Also logs the 2026-06-02 re-audit findings in development/vimwiki-gap.md:
RemoveDone lost -range (low pri); config gaps list_margin
semantics/markdown-default, diary_months, markdown_header_style,
diary_caption_level=-1; and the path_html/template_path default-location
divergences. Mappings audit came back clean.

Tests: cmd.reject_list_item_range (test-keymaps.lua),
cmd.VimwikiToggleRejectedListItem_accepts_range (test-keymaps-vim.vim).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 01:02:48 +00:00
gffranco 88114a65a4 test: land the vim diary -count cases + dedup the lua one (follow-up to 2da2168)
CI / cargo fmt --check (push) Successful in 32s
CI / cargo clippy (push) Successful in 35s
CI / cargo test (push) Successful in 27s
CI / editor keymaps (push) Successful in 1m25s
2da2168's diary test edits landed unevenly: the lua
cmd.VimwikiMakeDiaryNote_has_count case got inserted twice, and the two vim
cases (cmd.Vimwiki{MakeDiaryNote,DiaryIndex}_accepts_count) the commit message
referenced never landed (the Edit had no-matched). Remove the lua duplicate and
add the two vim cases before the harness wrap-up. lua 284, vim 274/18/21, all
0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:35:41 +00:00
gffranco 2da2168d88 fix(diary): complete the -count wiki selector (repair 874bdd0)
CI / cargo fmt --check (push) Successful in 30s
CI / cargo clippy (push) Successful in 38s
CI / cargo test (push) Successful in 40s
CI / editor keymaps (push) Successful in 1m37s
874bdd0 committed the diary -count feature with several Edits that had
silently no-matched, leaving the tree non-compiling and the clients
inconsistent (CI run 236 failed). This completes it:

- commands.rs: add the `wiki` field to OptionalUriArg (the previous edit
  targeted a wrong struct name) and pass None to the six resolve_diary_wiki
  callers that take no selector (date/list/step paths). Server builds clean.
- autoload/nuwiki/commands.vim + lua/nuwiki/commands.lua: actually thread the
  count through s:diary_open / _diary_open and the diary_today/today_tab/
  yesterday/tomorrow/index handlers (these edits had failed before, so the
  ftplugin defs were calling handlers that ignored/rejected the arg).
- Add the test cases the prior commit referenced but never landed:
  cmd.VimwikiMakeDiaryNote_has_count (test-keymaps.lua) +
  cmd.Vimwiki{MakeDiaryNote,DiaryIndex}_accepts_count (test-keymaps-vim.vim).
- Fix the OptUriArg→OptionalUriArg name in the gap-doc note.

Verified with CI flags: workspace test/clippy/fmt clean; lua 284, vim 272/18/21,
all 0 failed; the three new diary cases pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:25:08 +00:00
gffranco 874bdd0c02 feat(diary): -count wiki selector for diary-note + index commands (P3)
CI / cargo fmt --check (push) Successful in 25s
CI / cargo clippy (push) Failing after 34s
CI / cargo test (push) Failing after 33s
CI / editor keymaps (push) Has been skipped
Closes the last command-cluster gap. Upstream's diary-note family
(:Vimwiki{Make,TabMake,MakeYesterday,MakeTomorrow}DiaryNote + VimwikiDiaryIndex,
and the Nuwiki* forms) carry -count=0 where the count selects the wiki number;
nuwiki's were bare. Implemented as a real end-to-end selector, reusing existing
infrastructure:

- Server (commands.rs): OptUriArg gained an optional `wiki` selector;
  resolve_diary_wiki(backend, uri, wiki) now prefers it (via the existing
  resolve_wiki_selector, which already handles a 0-indexed wiki number) over
  the buffer URI. Used by diary_open_relative + diary_open_index.

- Clients: s:diary_open / _diary_open (both) and diary_today/today_tab/
  yesterday/tomorrow/index take a count and send {wiki: count-1} when >0. All
  22 diary-note + DiaryIndex command defs across the 4 contexts are now
  -count=0 passing <count>. diary_next/prev ignore the count.

Tests: cmd.VimwikiMakeDiaryNote_has_count (test-keymaps.lua) +
cmd.Vimwiki{MakeDiaryNote,DiaryIndex}_accepts_count (test-keymaps-vim.vim).
Workspace test/clippy/fmt clean with CI flags; lua 284, vim 272/18/21.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:16:03 +00:00
gffranco f616915581 feat(commands): ChangeSymbolTo -range, GenerateLinks path filter, NuwikiGenerateTags
CI / cargo fmt --check (push) Successful in 29s
CI / cargo clippy (push) Successful in 34s
CI / cargo test (push) Successful in 45s
CI / editor keymaps (push) Failing after 1m43s
Closes the three new command gaps from the 2026-05-31 re-audit (all real,
client-side, both clients × Vimwiki/Nuwiki):

- VimwikiChangeSymbolTo / ListChangeSymbolI / NuwikiChangeSymbol are now
  -range -nargs=1 via a new list_change_symbol_range(symbol,l1,l2) helper that
  loops over_range; was -nargs=1 only → E481 on a visual selection.
  ChangeSymbolInListTo/InList stay range-less.
  Bonus: the Neovim VimwikiChangeSymbolInListTo + NuwikiChangeSymbolInList defs
  passed whole_list=false, changing only the current item — corrected to true.

- VimwikiGenerateLinks / NuwikiGenerateLinks are now -nargs=?; with an arg the
  client dispatches the existing server command nuwiki.links.generateForPath
  ({path}) for real subtree-scoped link generation, else nuwiki.links.generate.
  Was bare → E488 on an arg.

- Added NuwikiGenerateTags (Vim + Neovim) mirroring VimwikiGenerateTags, with
  -nargs=? -complete=…tags — closes the :Vimwiki*↔:Nuwiki* alias asymmetry.

Tests: cmd.ChangeSymbolTo_range_sets_marker, cmd.GenerateLinks_accepts_optional_path,
cmd.NuwikiGenerateTags_exists (test-keymaps.lua, 283 pass) +
cmd.VimwikiChangeSymbolTo_accepts_range, cmd.VimwikiGenerateLinks_accepts_path,
cmd.NuwikiGenerateTags_exists (test-keymaps-vim.vim, 272/18/21). fmt clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 21:48:31 +00:00
gffranco 23f5a74086 test: add the Neovim *Link wrap cases referenced by 2b3bc48
CI / cargo fmt --check (push) Successful in 22s
CI / cargo clippy (push) Successful in 21s
CI / cargo test (push) Successful in 36s
CI / editor keymaps (push) Successful in 1m22s
The previous commit's test-insert Edit silently no-matched (wrong anchor
text), so cmd.VimwikiFollowLink_wraps_bare_word and
cmd.VimwikiSplitLink_wraps_bare_word were referenced in the commit message and
gap doc but never added. Add them now at the correct anchor; the lua harness
goes 278 → 280, both new cases pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 21:06:26 +00:00
gffranco 4710ba03c8 feat(commands): VimwikiListChangeLvl -range -nargs=+ (P3 parity)
CI / cargo fmt --check (push) Successful in 17s
CI / cargo clippy (push) Successful in 28s
CI / cargo test (push) Successful in 50s
CI / editor keymaps (push) Successful in 1m58s
Upstream is `-range -nargs=+` (change_level(line1, line2, direction,
plus_children)); nuwiki was -nargs=? and range-less, so `:1,3VimwikiListChangeLvl
increase 0` raised E481/E488 and the level change never spanned a selection.

All four defs (Vim+Neovim × Vimwiki+Nuwiki) are now -range -nargs=+ and forward
<line1>, <line2>, <f-args>. list_change_lvl(line1, line2, direction,
[plus_children]) (both clients) parses the required direction + optional subtree
flag and applies the change to every list item in the range via the existing
over_range helper.

Tests: cmd.ListChangeLvl_range_indents (test-keymaps.lua) +
cmd.VimwikiListChangeLvl_accepts_range_and_args (test-keymaps-vim.vim).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 20:16:10 +00:00
gffranco a7f7e8e61f feat(commands): VimwikiTable -nargs=* + Index/TabIndex -count=0 (P3 parity)
CI / cargo fmt --check (push) Successful in 34s
CI / cargo clippy (push) Successful in 21s
CI / cargo test (push) Successful in 30s
CI / editor keymaps (push) Successful in 1m34s
Two command-attribute parity fixes (audited against upstream vimwiki master):

- VimwikiTable / NuwikiTable were -nargs=1 and called table_insert() with no
  args, so `:VimwikiTable 4 3` raised E488 and cols/rows were unreachable.
  All four defs (Vim+Neovim × Vimwiki+Nuwiki) are now -nargs=* and forward
  <f-args>; the backing table_insert already parsed cols (a:1) + rows (a:2).

- VimwikiIndex/TabIndex (and Nuwiki forms) switch from bare -count to
  upstream's -count=0. Behavior is unchanged (both default count to 0;
  wiki_index already maps a count to the 1-indexed wiki number) — this just
  matches the upstream declaration exactly.

Tests: cmd.VimwikiTable_passes_cols_and_rows (test-keymaps.lua — asserts a
4-col/3-row table) and cmd.VimwikiTable_accepts_cols_rows (test-keymaps-vim.vim
— no E488). gap doc updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 20:10:53 +00:00
gffranco 2a8e2b9ea9 fix(keymaps): correct Neovim global diary tab/tomorrow maps (map_prefix audit)
CI / cargo fmt --check (push) Failing after 27s
CI / cargo clippy (push) Successful in 33s
CI / cargo test (push) Successful in 37s
CI / editor keymaps (push) Successful in 1m33s
A map_prefix parity audit against upstream vimwiki found the Neovim global
entry-point block in lua/nuwiki/init.lua carried the same collision the Vim
global + buffer-local maps were already fixed for: <prefix><Leader>t was
bound to tomorrow and <prefix><Leader>m (tomorrow) was missing entirely.

Now <prefix><Leader>t opens today in a new tab and <prefix><Leader>m is
tomorrow — consistent with plugin/nuwiki.vim, the buffer-local maps, and
upstream (VimwikiTabMakeDiaryNote / VimwikiMakeTomorrowDiaryNote).

Adds global_maps.diary_tab_and_tomorrow_targets to test-keymaps.lua (queries
in a scratch buffer so buffer-local maps don't shadow the globals). Logs the
fix plus a new "RSS feed structure fidelity" gap (the audit confirmed the
custom_wiki2html arg contract and base_url scope are faithful; only the RSS
document shape diverges) in development/vimwiki-gap.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 19:22:52 +00:00
gffranco feedd30c4d feat(keymaps): configurable map_prefix for the wiki command family (P2)
CI / cargo fmt --check (push) Failing after 33s
CI / cargo clippy (push) Successful in 31s
CI / cargo test (push) Successful in 41s
CI / editor keymaps (push) Successful in 1m49s
Mirror vimwiki's g:vimwiki_map_prefix. The whole <Leader>w* family was
hardcoded across the map layer; it is now built from a configurable prefix:

- Neovim: `map_prefix` setup() option (default '<Leader>w'), read by
  lua/nuwiki/keymaps.lua (buffer-local) and lua/nuwiki/init.lua (global
  entry points).
- Vim: g:nuwiki_map_prefix, applied via :exe in plugin/nuwiki.vim (global)
  and ftplugin/vimwiki.vim (buffer-local).

Setting a custom prefix relocates <prefix>{w,t,s,i,n,d,r,c,h,hh,ha} and
<prefix><Leader>{w,y,t,m,i}, leaving nothing under the old <Leader>w*.
Non-prefix maps (<CR>, gl*, headers, …) are untouched.

Tests: new test-keymaps-vim-prefix.vim harness (21 cases, wired into
test-keymaps-vim.sh) + map_prefix.relocates_wiki_family in test-keymaps.lua.
Docs: README, doc/nuwiki.txt, lua config comment, vimwiki-gap.md ticked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 19:18:06 +00:00
gffranco db9c1c5c11 feat: real range/bang/visual handling for the deferred command gaps
CI / cargo fmt --check (push) Successful in 27s
CI / cargo clippy (push) Successful in 22s
CI / cargo test (push) Successful in 53s
CI / editor keymaps (push) Successful in 1m29s
Implements the four items previously left as "needs handler work" — all
fully wired, not cosmetic.

- ToggleListItem / IncrementListItem / DecrementListItem are now -range
  (both clients). The client loops the per-line op over [<line1>,<line2>]
  (toggle_list_item_range / list_cycle_symbol_range). The server's edits are
  version-less single-line WorkspaceEdits, so each line applies independently
  — no server protocol change. `:'<,'>VimwikiToggleListItem` toggles the whole
  selection.
- VimwikiRebuildTags gains -bang: `:…RebuildTags!` passes { all: true } and
  the server (tags_rebuild) re-indexes every configured wiki via
  wikis_snapshot(), not just the current one.
- VimwikiNormalizeLink is -nargs=?: with `1` (upstream's visual flag; the
  x-mode `+` mapping now passes it) it wraps the '< / '> selection as
  [[selection]] (new wrap_visual_as_wikilink in both clients).
- VimwikiCheckLinks is -range: a ranged invocation filters the broken-link
  report to the current buffer's selected lines (client-side filter in
  results_to_qf / check_links).

Tests: cmd.toggle_list_item_range + cmd.normalize_link_visual_wraps_selection
(test-keymaps.lua), normalize.visual_wraps_selection (test-keymaps-vim.vim).
README + doc/nuwiki.txt + gap doc updated. fmt/clippy clean; nvim 274,
vim 266+18, all Rust tests + config-parity green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:57:03 +00:00
gffranco 212b300fb4 fix(client): small mapping/command-attribute parity gaps
CI / cargo fmt --check (push) Successful in 37s
CI / cargo clippy (push) Successful in 24s
CI / cargo test (push) Successful in 33s
CI / editor keymaps (push) Successful in 1m44s
Clean, fully-wired parity fixes (skipping the accept-but-ignore ones):

- <D-CR> (macOS Cmd+Return) → follow_link_drop, alongside <C-S-CR>, in both
  clients. Upstream binds both to VimwikiTabDropLink.
- plugin/nuwiki.vim global map block: fix the same diary collision the
  buffer-local maps had — <Leader>w<Leader>t now opens today in a new tab and
  <Leader>w<Leader>m (tomorrow) is added.
- Neovim TabIndex: add -count to NuwikiTabIndex and switch both
  Vimwiki/NuwikiTabIndex from vim.v.count (always 0 in command context) to
  <count>, so a count is actually honored.
- Converge VimwikiTableMoveColumn{Left,Right}: the Vim-branch commands now call
  the table_move_column_left/right aliases, matching the Neovim branch.
- VimwikiColorize/NuwikiColorize: -nargs=1 → -nargs=* (all four defs) for
  upstream parity; a bare :VimwikiColorize now prompts for the colour.

Docs (README + doc/nuwiki.txt) updated; mapping surfaces gain <D-CR> and
<Leader>w<Leader>m in both harnesses. vim 265+18, nvim 272, all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:28:06 +00:00
gffranco 086455e19b fix(client): P2 diary tab collision + <M-CR> badd-link parity
CI / cargo fmt --check (push) Successful in 36s
CI / cargo clippy (push) Successful in 40s
CI / cargo test (push) Successful in 32s
CI / editor keymaps (push) Successful in 1m35s
Two upstream-parity keymap fixes (confirmed against upstream
ftplugin/vimwiki.vim):

1. <Leader>w<Leader>t collision — nuwiki bound both <Leader>w<Leader>t and
   <Leader>w<Leader>m to tomorrow's diary. Upstream: <Leader>w<Leader>t opens
   today's diary in a NEW TAB, <Leader>w<Leader>m opens tomorrow. <Leader>w
   <Leader>t now calls diary_today_tab; <Leader>w<Leader>m stays tomorrow.

2. <M-CR> badd-link — adding a link target to the buffer list was mouse-only
   (<MiddleMouse>) / command-only (:VimwikiBaddLink). Upstream binds
   <M-CR> -> VimwikiBaddLink. Added normal-mode <M-CR> -> badd_link to the
   links group of both clients.

Both clients (lua/nuwiki/keymaps.lua, ftplugin/vimwiki.vim); README + doc/
nuwiki.txt updated. Tests: map[n].<M-CR> in both harnesses;
diary.leader_t_opens_today_in_tab / diary.leader_m_opens_tomorrow (vim).
nvim 270, vim 263+18, all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 16:21:49 +00:00
gffranco 15ba774a28 feat(client): conceal colour spans down to their coloured text
CI / cargo fmt --check (push) Successful in 25s
CI / cargo clippy (push) Successful in 37s
CI / cargo test (push) Successful in 37s
CI / editor keymaps (push) Successful in 1m48s
A :VimwikiColorize'd word showed the literal
`<span style="color:NAME">TEXT</span>` markup. Now the tags are concealed
and TEXT is painted in NAME, so the buffer shows just the coloured word —
matching the HTML export.

New autoload/nuwiki/colors.vim: nuwiki#colors#refresh() scans the buffer
and, per distinct colour, defines a syntax region that conceals the
`<span …>` / `</span>` tags (concealends) and highlights the body with the
span's actual colour (guifg always; ctermfg for named colours). Idempotent
(clears the group before redefining) and tracked in b:nuwiki_color_seen.

Refresh is driven from three places so it's both correct and immediate:
- syntax/vimwiki.vim: initial pass + re-establish after :colorscheme reload
  (resets the per-buffer cache since :syntax clear drops the regions);
- ftplugin TextChanged/InsertLeave autocmd for spans that arrive via paste/
  undo/external edits;
- colorize() itself calls refresh() right after wrapping, so a freshly
  colorized word conceals instantly (TextChanged doesn't fire reliably mid
  command / in headless ex-mode).

The LSP @vimwikiColor token no longer links to Constant, so in Neovim it
doesn't override the real per-span colour on the concealed text. Pure syntax
+ :highlight — works identically in Vim, coc.nvim, and Neovim, no LSP needed.

Tests: colorize.conceal_hides_tags_shows_text (both harnesses) and
colorize.command_conceals_immediately (vim). Sample wiki's colorize section
notes the conceal. nvim 269, vim 259+18, config-parity green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 16:01:21 +00:00
gffranco 2facb40265 fix(client): VimwikiColorize accepts a range (no more E481 on selection)
CI / cargo fmt --check (push) Successful in 31s
CI / cargo clippy (push) Successful in 24s
CI / cargo test (push) Successful in 39s
CI / editor keymaps (push) Successful in 1m31s
Selecting text and running :VimwikiColorize {color} raised
"E481: No range allowed" — Vim prepends '<,'> to the command when invoked
from a visual selection, but the command was defined without -range.

All four colorize command defs (Vim + Neovim, Vimwiki* + Nuwiki*) are now
-range and forward the range count to the handler. A ranged (visual)
invocation wraps the '< / '> selection; a bare invocation wraps the cword.
The x-mode <Leader>wc mapping passes the visual flag explicitly.

The Vim-branch colorize() gained selection support (it was cword-only),
matching the Neovim branch, so both clients wrap a visual selection
identically. visual_selection_range() (Lua) no longer gates on
vim.fn.visualmode() — the explicit visual flag now carries that intent, and
the marks check guards unset selections.

Tests: cmd.Colorize_range_wraps_selection (nvim) and
colorize.{command_wraps_cword,visual_wraps_selection,ranged_command_no_error}
(vim). nvim 268, vim 257+18, all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 15:37:09 +00:00
gffranco 66bfd61a63 fix(client): VimwikiColorize passes its {color} arg on Neovim + visual fix
CI / cargo fmt --check (push) Successful in 18s
CI / cargo clippy (push) Successful in 27s
CI / cargo test (push) Successful in 29s
CI / editor keymaps (push) Successful in 1m23s
The Neovim command defs for :VimwikiColorize / :NuwikiColorize were
-nargs=1 but called colorize() without <q-args>, so the colour name was
silently dropped and the user was prompted instead (the Vim branch passed
it correctly). Pass <q-args>.

While verifying, found a second bug in the Lua colorize(): it inferred
visual-vs-normal from vim.fn.visualmode(), which returns the *last* visual
mode used in the session along with stale '< / '> marks. So running
:VimwikiColorize in normal mode after any earlier visual selection wrapped
that leftover selection instead of the word under the cursor (produced an
empty, misplaced span). colorize(color, visual) now takes an explicit
visual flag, passed only by the x-mode <Leader>wc mapping; the command and
the normal-mode mapping always wrap the cword.

Tests: cmd.VimwikiColorize_uses_arg, cmd.NuwikiColorize_uses_arg,
cmd.Colorize_ignores_stale_visual_selection, colorize.visual_wraps_selection
in test-keymaps.lua. nvim suite 267, vim suite 254+18, all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 15:18:31 +00:00
gffranco cca2043294 test(client): cover bare gl/gL remove-checkbox + command-driven remove-done
Swap the gl<Space>/gL<Space> surface assertions for bare gl/gL; add behavioral
cases for gl (item) and gL (whole list) remove-checkbox, and drive remove-done
through :NuwikiRemoveDone / :NuwikiRemoveDone! now that it is command-only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 08:41:27 -03:00
gffranco 8a99765e02 test(client): assert gl/gL list change-symbol mappings
Add the 16 gl<sym>/gL<sym> keys to the lists mapping_surface in both
keymap harnesses.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 08:10:10 -03:00
gffranco 82b6bc9c60 test(client): cover Vim/Neovim link-follow command surface + tab-drop
Add SplitLink/VSplitLink/TabnewLink/TabDropLink/GoBackLink to both
keymap harness command lists, plus a smoke check that
nuwiki.commands.follow_link_drop is callable.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 07:54:25 -03:00
gffranco 63ef1b59a2 docs(parity): document new commands and extend keymap harness coverage
CI / cargo fmt --check (push) Successful in 27s
CI / cargo clippy (push) Successful in 44s
CI / cargo test (push) Successful in 47s
CI / editor keymaps (push) Successful in 1m30s
Update the README command tables for the full :Nuwiki*/:Vimwiki* surface
and add command-registration assertions (removeCheckbox, catUrl, and the
other parity entry points) to both the Vim and Neovim keymap harnesses.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 17:36:05 -03:00
gffranco 8ab6015405 Major clean up and improvements to vimwiki compatibility and documentation.
CI / cargo fmt --check (push) Successful in 33s
CI / cargo clippy (push) Successful in 23s
CI / cargo test (push) Successful in 33s
CI / editor keymaps (push) Successful in 1m25s
Reviewed-on: #1
2026-05-30 18:35:40 +00:00