4a19f180f2f3b892e00d691e410b45b6b9fea746
58 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5d1ac09245 |
feat(config): P3 config batch — group 4 (valid_html_tags, emoji, color_tag_template)
- valid_html_tags: HTML export now passes the allowlisted inline tags through verbatim (b/i/sub/sup/kbd/div/center/strong/em/...) and escapes the rest, via a render-time tag-aware escaper (write_escaped_allowing/match_allowed_tag) — mirroring upstream's s:safe_html_line regex rather than a parser change. `span` is always allowed so colour spans render. - emoji_enable: render-time `:alias:` -> glyph substitution (curated common set), default on; with_emoji builder + substitute_emoji/emoji_for. - color_tag_template: :VimwikiColorize now wraps via a configurable template (g:nuwiki_color_tag_template / setup color_tag_template), splitting on __CONTENT__ with __COLORFG__ -> colour; both clients. Colour spans render in export via the valid_html_tags span passthrough. Default template reproduces the prior `<span style="color:NAME">` output (harness colorize tests green). Renderer gets with_valid_html_tags + with_emoji; export.rs wires both from HtmlConfig. Tests: valid_html_tags passthrough + escape, emoji on/off (html_export.rs). Full rust suite + both harnesses green (Neovim 307, Vim 301/18/21); clippy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
b2f2fc88bd |
feat(config): P3 config batch — group 1 (clean config + plumbing)
Config plumbing for the whole config batch (HtmlConfig + WikiConfig fields, RawWiki deserialization, From/defaults) plus these behaviors: - rss_name / rss_max_items: HtmlConfig fields (wired into write_rss in the RSS group). - toc_link_format: build_toc_text emits [[#anchor]] (no description) for 1, [[#anchor|title]] for 0. - generated_links_caption: build_links_text emits [[page|FirstHeading]] from a page->heading map (ops::page_captions) when enabled. - table_reduce_last_col: column_widths clamps the last column to width 1 when set; threaded through table_align_edit/table_move_column_edit + commands. - color_dic now ships a populated default palette (red/green/blue/...). - commentstring aligned to upstream's no-space `%%%s`. - auto_chdir (default off): :lcd into the owning wiki root on buffer enter; both clients (ftplugin.lua setup_auto_chdir + Vim NuwikiAutoChdir augroup), with config.wiki_root_for / nuwiki#commands#wiki_root_for resolvers. Also seeded HtmlConfig fields for later groups (valid_html_tags, list/text_ignore_newline, emoji_enable, user_htmls, color_tag_template) and WikiConfig (create_link, dir_link, bullet_types, cycle_bullets). Tests: toc_link_format, generated_links_caption, table_reduce_last_col, config defaults + JSON round-trip for every new key. Full rust suite + both keymap harnesses green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
03005d0931 |
fix(insert): pumvisible() guard on smart_return/smart_shift_return (audit follow-up)
The mappings re-audit confirmed the two new bindings (visual <CR> normalize, insert <S-CR> multiline item) are correct — column math matches upstream's s:text_begin, auto-indent handling sound, no parity gaps or regressions. It flagged one low-severity item shared with the pre-existing smart_return: neither guarded the completion popup. Upstream maps <CR>/<S-CR> as `pumvisible() ? '<CR>' : …`. Added that guard to both smart_return and smart_shift_return (both clients) so a <CR>/<S-CR> accepts the completion instead of continuing the list when the popup is open. Left as a documented minor divergence: <S-CR> on an *empty* bullet emits the aligned no-marker continuation rather than upstream's "blank line above, keep marker" (niche). Neovim 305, Vim 299/18/21 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
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>
|
||
|
|
305324c6e9 |
Merge remote-tracking branch 'origin/calendar-support' into feature-gap
# Conflicts: # development/vimwiki-gap.md |
||
|
|
6deba47106 |
fix(search): graceful no-match + NuwikiSearch alias (re-audit follow-up)
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>
|
||
|
|
a11b742fc1 |
feat(parity): close the entire P3 Commands section
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>
|
||
|
|
c161f9d21a |
feat(parity): P3 quick-wins — ShowVersion, gLH/gLL/gLR, Search/Align nargs
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>
|
||
|
|
9441fe918c |
fix(parity): close the 2026-06-02 re-audit config/command findings
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>
|
||
|
|
079e7246ac |
fix(lists): VimwikiToggleRejectedListItem -range parity (P3)
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> |
||
|
|
21f583beef |
docs(calendar): fix stale comments and integration docs
- diary.vim: correct calendar_action doc comment (dir is used for split direction; only week is unused) - calendar-vim-integration.md: use real nuwiki var names (g:nuwiki_use_calendar / g:nuwiki_no_calendar / g:nuwiki_wikis), document auto-detect wiring and calendar-window close behavior; drop the non-existent refresh-on-close autocmd - vimwiki-gap.md: remove stale 'no calendar.vim integration' entry now that the integration is implemented |
||
|
|
87ba4c1764 |
test(calendar): add Vim + Neovim integration harnesses
Add headless harnesses covering the calendar-vim integration, wired into CI alongside the existing keymap/config suites: - test-calendar-vim.sh/.vim (+ -optout.vim): pure-VimL diary hooks (calendar_sign markers, calendar_action path resolution from wiki root, calendar window close), plugin/nuwiki.vim hook auto-wiring that overrides calendar-vim's defaults, and opt-out via g:nuwiki_use_calendar and g:nuwiki_no_calendar. Uses a stub calendar-vim on the runtimepath. - test-calendar.sh/.lua: Neovim setup() wiring + window-close under the real window API, and opt-out via use_calendar = false. Fixes surfaced by the suite: - diary.vim: new diary entries set filetype 'vimwiki' (was the raw extension, e.g. 'wiki'); the stray FileType autocmd also blocked the calendar window from closing. - init.lua: drop the redundant Neovim FileType autocmd (plugin/nuwiki.vim already wires both editors) and translate use_calendar=false into g:nuwiki_no_calendar so the opt-out actually disables wiring. |
||
|
|
7a3e11cfeb |
feat(calendar): integrate calendar-vim with wiki diary paths
Wire g:calendar_action/g:calendar_sign to nuwiki diary hooks that resolve diary paths from the wiki root config instead of calendar-vim's default ~/diary. Auto-detected on FileType vimwiki when calendar-vim is present; opt out with g:nuwiki_use_calendar=0 or g:nuwiki_no_calendar. - autoload/nuwiki/diary.vim: calendar_action/calendar_sign using wiki cfg; open diary in the previous window and close the calendar window after. - autoload/vimwiki/diary.vim: vimwiki# aliases for drop-in compatibility. - plugin/nuwiki.vim + lua/nuwiki/init.lua: auto-wire hooks, overwriting calendar-vim's defaults while respecting user-set custom hooks. - lua/nuwiki/config.lua: add use_calendar option (on by default). - development/start-*.sh + _common.sh: clone calendar-vim, fix vimrc var expansion, pass wiki root to the Vim/Neovim clients. |
||
|
|
2da2168d88 |
fix(diary): complete the -count wiki selector (repair 874bdd0)
|
||
|
|
f616915581 |
feat(commands): ChangeSymbolTo -range, GenerateLinks path filter, NuwikiGenerateTags
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>
|
||
|
|
3b3d8ca782 |
feat(commands): command-line completion for Goto/Colorize/tag commands (P3)
Upstream attaches -complete= to several commands; nuwiki had none, so <Tab>
at the : line never completed page/tag/colour names. New
autoload/nuwiki/complete.vim adds pure client-side, synchronous completers
(config + filesystem, never the LSP — so they work under vim-lsp, coc and
Neovim), wired via -complete=customlist into all command contexts:
- nuwiki#complete#pages → VimwikiGoto/NuwikiGoto (glob wiki roots for page names)
- nuwiki#complete#colors → VimwikiColorize/NuwikiColorize (color_dic keys +
colours already used in buffer color:… spans)
- nuwiki#complete#tags → VimwikiSearchTags/GenerateTagLinks/GenerateTags (+Nuwiki)
(scan wiki files for :tag: runs — the tag index is server-side and a
synchronous completer can't query it, so we read the same source it indexes)
Documented divergence: no file completer for VimwikiRenameFile — nuwiki
delegates renaming to the LSP rename request (no filename arg to complete),
unlike upstream which renames itself.
Tests: complete.{pages_globs_and_filters,tags_scans_wiki_files,
colors_from_buffer_spans} (test-keymaps-vim.vim). Both harnesses green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
efea225240 |
fix(commands): VimwikiTable default 5 cols (parity) + map audit findings
Verification audit of the command-attribute pass confirmed all four changes (Table, Index/TabIndex, ListChangeLvl, SplitLink) faithful with no regressions, and surfaced three pre-existing items: - VimwikiTable no-arg default cols was 3 vs upstream's 5 (rows 2 already matched, confirmed against vimwiki#tbl#create). Aligned both backing fns (autoload + lua) to default 5 cols. - Mapped (not fixed here — core <CR> behavior, out of attribute scope): the Neovim lua follow_link_or_create double-calls definition() with dead code and never wraps a bare word into [[link]] (the Vim side does); and the Neovim Split/VSplitLink dispatch to raw definition() instead of follow_link_or_create. Both logged in development/vimwiki-gap.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
4710ba03c8 |
feat(commands): VimwikiListChangeLvl -range -nargs=+ (P3 parity)
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> |
||
|
|
db9c1c5c11 |
feat: real range/bang/visual handling for the deferred command gaps
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>
|
||
|
|
9de8543385 |
fix(client): colour-span conceal must skip unallocatable colours
A literal `<span style="color:…">` in prose (the sample wiki's own colorize instructions used one, with a `…` ellipsis as the colour) was matched by the scanner and fed to `highlight guifg=…`, which raised E254 on the un-silenced guifg line. That aborted the whole nuwiki#colors#refresh(), so on the Vim clients NO spans got concealed (start-vim) and follow-link crashed mid FileType autocmd (start-vim-coc). Neovim happened to dodge it depending on which buffer was scanned. s:define() now: - validates the colour (only #hex or an alphabetic name) and skips anything else — rgb()/hsl() functions and prose examples no longer create bogus conceal regions or errors; - runs both `highlight` calls under `silent!`, so a valid-format but unknown name can't abort the refresh either (tags still conceal, text just isn't recoloured). Also reworded the sample wiki's colorize note so it no longer embeds a literal span tag. Test: colorize.skips_unallocatable_colour (vim) — an rgb() span before a real one: refresh doesn't error, the rgb span isn't concealed, the real span still is. nvim 269, vim 260+18, all green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
15ba774a28 |
feat(client): conceal colour spans down to their coloured text
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> |
||
|
|
2facb40265 |
fix(client): VimwikiColorize accepts a range (no more E481 on selection)
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>
|
||
|
|
6983daa637 |
fix(follow-link): resolve+open definitions ourselves on the Vim clients
The Vim follow-link path delegated to the LSP client's jump UI
(:LspDefinition / coc jumpDefinition), which broke two ways for wiki
link-following:
1. **No create-on-follow (vim-lsp + coc).** vim-lsp's location handler
readfile()s the target to build a quickfix entry; for a not-yet-created
page that throws E484 and aborts the jump, so <CR> on [[NewPage]] did
nothing. The server was correct throughout — textDocument/definition
returns a *synthesised* location for missing pages (verified over
JSON-RPC).
2. **Wrong window placement (coc).** Without an explicit open command coc
fell back to coc.preferences.jumpCommand (e.g. a tab command).
Stop delegating: nuwiki#commands#follow_link_or_create() /
follow_link_drop() now resolve textDocument/definition directly and open
the URI themselves via a shared s:open_definition(open_cmd) helper — :edit
for <CR>, `tab drop` for <C-S-CR>. :edit opens a buffer for a missing path
(save creates it, matching vimwiki) and gives exact current-window
placement regardless of the user's coc jumpCommand. Removes
s:jump_definition / s:drop_from_response.
Also fix the coc action name: CocAction('getDefinition') does not exist
(E605 "Action getDefinition does not exist") — the registered action is
'definitions'. Fixed in s:open_definition and badd_link.
coc config delivery: the setup guidance shipped without
initializationOptions, so coc users never sent wiki_root and the server
resolved links against its default root (existing pages flagged broken,
follow-to-create landed in the cwd). The printed snippet
(autoload/nuwiki/lsp.vim) now emits initializationOptions populated with
the resolved settings, and the README coc snippet documents it as required.
Add development/start-vim-coc.sh — a coc.nvim dev launcher (sibling of
start-vim.sh) that wires coc's prebuilt release branch + a generated
coc-settings.json (with initializationOptions), deliberately omitting
vim-lsp so the coc path is exercised; doubles as a reproducer.
Tests: new cr.follow_opens_missing_page_in_current_window case in
test-keymaps-vim.vim (stubs CocAction to a missing page, asserts
current-window :edit). Keymap suite 254+18 green; config-parity (Vim +
Neovim) green. Neovim path unchanged and re-confirmed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
f65d861f72 |
feat(client): add Vim split/tab/back link-follow commands + true tab-drop
The plain-Vim client only defined VimwikiFollowLink; the split/vsplit/
tabnew/tabdrop/back command surface existed only in the Neovim branch.
Add :Vimwiki{Split,VSplit,Tabnew,TabDrop,GoBack}Link (+ :Nuwiki* aliases)
to the Vim branch, backed by a new nuwiki#commands#follow_link_drop()
helper that runs `:tab drop` to reuse an already-open tab.
Both clients now implement real tab-drop: open_uri gains a 'tabdrop'
case and M.follow_link_drop(); the Neovim TabDropLink commands and the
<C-S-CR> mappings (Vim + Lua) are repointed off the old tabnew cheat.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
5ee72c40e2 |
feat(client): send diagnostic.link_severity from both clients
Neovim adds a `diagnostic = { link_severity = 'warn' }` default so the value
is actually included in the payload. Vim reads the flat g:nuwiki_link_severity
global and nests it into the same `diagnostic` dict, keeping the two clients'
server-bound payloads identical.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
b922f0d612 |
test(config): verify Vim/Neovim config payload parity
Expose the init_options payload builders publicly in both clients
(M.init_options/M.server_settings in Lua, nuwiki#lsp#settings() in Vim) so
they can be inspected. Add editor harnesses that dump each client's
server-bound config as deterministic key=value lines and diff against a
shared golden file: nvim == golden and vim == golden together prove the two
clients send identical config. Add a server-side test asserting the Vim flat
shape and the Neovim {nuwiki:{...}} wrapper desugar to the same WikiConfig.
Wire both harnesses into CI.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
9bebd86577 |
feat(client): wire full Vimwiki command-parity surface
Register the named :Vimwiki*/:Nuwiki* entry points that previously
existed only as mappings or were missing entirely — including
RemoveSingleCB/RemoveCBInList, CatUrl, TabMakeDiaryNote,
NormalizeLink, Renumber{List,AllLists}, TableAlign, ChangeSymbol(InList),
ListToggle, Increment/DecrementListItem, and the DeleteLink/RenameLink/
GenerateTags compat aliases. Both the Vim (vim-lsp/coc) and Neovim
client functions are added to back them.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
cd9d587aab |
Add missing :Nuwiki* aliases and drop dead deferred-stub code
Every :Vimwiki* command now has a canonical :Nuwiki* counterpart (tables, colorize, clipboard paste, list-level/remove-done, and the Neovim-only split/tab link-follow variants). Remove the now-unused "not yet implemented" stub helpers (_not_yet, deferred, s:notify_deferred) and the stale "deferred" comments, since every command is implemented and server-backed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
8ab6015405 |
Major clean up and improvements to vimwiki compatibility and documentation.
Reviewed-on: #1 |
||
|
|
9a751037ce |
fix(vim): redraw after :NuwikiExportBrowse shells out to the browser
A silent `:!xdg-open`/`:!open` swaps to the shell's alternate screen and returns without repainting, leaving the editor UI garbled until the next redraw. Force a full repaint after launching the browser. Neovim already avoids this via async jobstart. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
7f6d811a47 |
fix(wiki): build wiki picker list from config so it works before opening a file
The picker fetched the wiki list via workspace/executeCommand, but the LSP only starts once a vimwiki buffer exists — so a wiki could not be selected until one was already open (chicken-and-egg). Read the list straight from config instead (g:nuwiki_wikis / scalar fallback, the same source as open_wiki_path) and open the chosen index directly; that auto-starts the server via the FileType autocmd. - Vim: new public nuwiki#commands#wiki_list(); wiki_ui_select() uses it + inputlist() + :edit. Global :VimwikiUISelect / :NuwikiUISelect commands. - Neovim: config.wiki_cfg(n) + config.wiki_list() (init.lua delegates); commands.wiki_ui_select() uses them + vim.ui.select + :edit; global VimwikiUISelect / NuwikiUISelect user commands registered in setup(). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
0dfe0910fc |
fix(tables): cycle Tab into the next row instead of inserting one
Pressing <Tab> past the last cell unconditionally appended a new row below, even when there was already a next row to jump into. Tabbing through a header → separator → body table from the header row inserted a blank row between header and separator instead of landing in the first body cell. After the final cell, walk forward from the current row to the end of the table, skip any separator row, and jump to the first cell of the next data row. Only insert a fresh row when the cursor is on the table's last row (or only separator rows follow). Applied to both the Vim (autoload/nuwiki/commands.vim) and Neovim (lua/nuwiki/ commands.lua) sides so the two harnesses stay in sync; covered by new keymap tests in scripts/test-keymaps-vim.vim and test-keymaps.lua. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
8d11f7daef |
fix(lsp): send g:nuwiki_wikis to the server so per-wiki roots are known
The server received only wiki_root (the parent directory) and had no
knowledge of the per-wiki sub-roots configured in g:nuwiki_wikis / the
setup() wikis list. It therefore resolved all links relative to the
parent root, causing every link in a sub-wiki to appear broken.
Vim path (autoload/nuwiki/lsp.vim):
s:settings() now includes a 'wikis' key when g:nuwiki_wikis is set,
so the initialization_options and settings payloads carry the full
per-wiki config (root, diary_rel_path, file_extension, …).
Lua path (lua/nuwiki/lsp.lua):
Add resolved_opts() which merges vim.g.nuwiki_wikis into
config.options.wikis when the user configures via VimL rather than
setup({wikis=…}). init_options(), server_settings(), and the
pre-0.11 root_dir_for() fallback all use resolved_opts() so the
server receives the correct per-wiki roots in every code path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
b3e2a72023 |
fix(lsp): add coc.nvim dispatch path to all Vim-side LSP calls
Commands were hardwired to vim-lsp (lsp#send_request, :LspDefinition,
:LspReferences, :LspRename). Users running coc.nvim got "vim-lsp not
loaded" on every command despite the plugin correctly detecting coc.
Changes:
autoload/nuwiki/commands.vim
- Add s:has_coc() (checks CocActionAsync exists)
- Add s:coc_wrap() adapter — converts coc's (err, result) callback into
the vim-lsp notification shape {response:{result:…}} so all existing
on_notification handlers work unchanged
- s:exec(): try vim-lsp first, fall back to CocActionAsync('runCommand',
…) with arguments spread as positional params, then error if neither
- Add s:jump_definition() helper — :LspDefinition vs CocActionAsync
- Add nuwiki#commands#backlinks() — :LspReferences vs CocActionAsync
- badd_link(): coc path uses CocAction('getDefinition') to resolve the
target URI without navigating
- follow_link_or_create(): replace inline :LspDefinition checks with
s:jump_definition()
- rename_file(): :LspRename vs CocActionAsync('rename')
ftplugin/vimwiki.vim
- VimwikiFollowLink / NuwikiFollowLink: dispatch through
nuwiki#commands#follow_link_or_create() instead of :LspDefinition
- VimwikiBacklinks / NuwikiBacklinks / VWB: dispatch through
nuwiki#commands#backlinks() instead of :LspReferences
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
2c0cefb5c5 |
fix(mappings): respect g:nuwiki_wikis in global entry-point helpers
The global <Leader>ww / diary helpers read g:nuwiki_wiki_root directly, so they always opened the root-level index.wiki even when the user had configured per-wiki roots via g:nuwiki_wikis (e.g. personal_wiki.root = '~/.vimwiki/personal_wiki'). Vim path (autoload): replace the three open_*_path functions with a shared s:wiki_cfg(n) helper that checks g:nuwiki_wikis[n] first, then falls back to the scalar g:nuwiki_* vars and built-in defaults. Lua path (init.lua): replace the separate _wiki_index_path /_diary_path locals with a unified _wiki_cfg() that checks setup() opts.wikis, then vim.g.nuwiki_wikis (for users who configure via VimL rather than setup()), then scalar opts / g: vars. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
ba5c0002ab |
fix(compat): add vimwiki#vars shim for vimwiki-sync and vim-zettel
Third-party plugins such as vimwiki-sync and vim-zettel call
vimwiki#vars#get_wikilocal() — a function only provided by the original
vimwiki plugin. Without it, the after/ftplugin loaded by vimwiki-sync
errors on every wiki buffer open:
E117: Unknown function: vimwiki#vars#get_wikilocal
E121: Undefined variable: g:zettel_dir
Add autoload/vimwiki/vars.vim with lightweight stubs for the two keys
vimwiki-sync uses ('path', 'is_temporary_wiki'), reading values from
nuwiki's own g:nuwiki_wiki_root / g:nuwiki_file_extension config so
users don't have to duplicate settings. get_global() is stubbed as a
no-op for completeness.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
9354e1c176 |
fix(mappings): add global entry-point keymaps and correct <Leader>ww/<Leader>wt targets
Two bugs prevented keymaps from working after a Dein install: 1. <Leader>ww and <Leader>wt both called diary_today() instead of wiki_index() / wiki_tab_index(). Fixed in keymaps.lua (Neovim) and ftplugin/vimwiki.vim (Vim). 2. All keymaps were buffer-local (<buffer> / buffer=bufnr), so they only activated inside an already-open .wiki file. Users had no way to reach the wiki from any other buffer, making the plugin appear broken on a fresh Vim start. Fix: register the eight <Leader>w* entry-point mappings globally — in setup() for Neovim (lua/nuwiki/init.lua) and in plugin/nuwiki.vim for plain Vim. To avoid a chicken-and-egg LSP dependency, the global mappings open files directly from config (wiki_root, diary_rel_path, file_extension); the LSP auto-starts via the FileType autocmd once the vimwiki buffer loads. Three new autoload helpers (open_wiki_path, open_diary_path, open_diary_index_path) provide the LSP-free path for the Vim side. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
7a0cec4920 |
fix(lists): skip own indent in smart_return when auto-indent is active
nvim defaults autoindent=on, so the indent inserted by Vim/Nvim after the <CR> we return was being doubled by our own indent prefix — pressing Enter on a sub-item produced a deeper-nested item instead of a same-level one. Detect any auto-indent mechanism (autoindent, smartindent, cindent, indentexpr) and let it own the indentation; otherwise add it ourselves so vim's noautoindent default still works. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
5b6f789c8d |
fix(tables): auto-realign on edit + stop dragging trailing | onto new row
Two bugs in the insert-mode table editing path: 1. <Tab> past the last cell (and <CR> on a table row) used <CR>+typed keystrokes to create a new row, which split the current line at the cursor — pulling the trailing | down onto the next line and mangling the formatting. Both paths now go through helpers that append() a fresh row beside the current one without touching it. 2. The table never realigned to new content. Ported the LSP-side render_aligned_table algorithm to Lua + VimL so smart_tab, smart_shift_tab, and smart_return tighten column widths locally on every navigation. No vim-lsp / nuwiki server roundtrip required. Neovim side schedules the work via vim.schedule (textlock-safe); plain Vim hands off via <Cmd>:call …<CR> to keep insert mode and avoid the cmdline-mode flash. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ae96562969 |
parity(vim): port text objects + folding, fix smart_return textlock
Close the remaining Vim-vs-Neovim functional gaps:
* Text objects — new `autoload/nuwiki/textobjects.vim` mirroring
`lua/nuwiki/textobjects.lua`. All five pairs (ah/ih, aH/iH,
al/il, a\/i\, ac/ic) wired in the Vim path of `ftplugin/vimwiki.vim`
via the classic `:<C-u>call` idiom that works cleanly in both
operator-pending and visual modes.
* Folding — new `autoload/nuwiki/folding.vim` providing a regex
`foldexpr` over headings, plus a tidy `foldtext`. Wired in the
Vim path; opts out via `let g:nuwiki_no_folding = 1`.
* `smart_return` was using `setline()` / `append()` inside an
`<expr>` callback — fine on Neovim but plain Vim's stricter
textlock raised E565. Rewrote as pure keystrokes (matches the
Lua version): table rows insert via `<CR>...<Esc>0li`, empty
list lines break via `<Esc>0DA<CR>`.
* Function-name parity: added
`nuwiki#commands#heading_add_level`,
`nuwiki#commands#heading_remove_level`,
`nuwiki#commands#table_move_column_{left,right}` as thin
aliases over the original short names so the public
`nuwiki#commands#*` surface matches `require('nuwiki.commands').*`.
Test harness:
* `scripts/test-keymaps-vim.vim` extended from 12 to 30 cases:
4 smart_return, 3 smart_tab/<S-Tab>, 3 named-command exists,
4 text-object helpers, 1 `dah` end-to-end, 2 folding, and the
original 12 pure-VimL cases. (Visual-mode mark inspection in
`vim -e -s` stays unreliable, so text objects are exercised
at the helper level plus one operator-pending end-to-end.)
Gates: 456 Rust / 39 Neovim / 30 Vim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
2562a046db |
parity(6): insert-mode <Tab>/<S-Tab> table cell nav
`<Tab>` / `<S-Tab>` in insert mode navigate between table cells when the cursor is on a `|…|` row, otherwise they pass through to their default insert-mode behaviour (literal tab / shift-tab). Same `<expr>`-mapping idiom as Cluster 5's smart_return. <Tab> next cell; creates a fresh row below if past the last cell <S-Tab> previous cell; no-op past the first Cursor lands immediately after the destination cell's leading `|`, matching upstream vimwiki's `vimwiki#tbl#go_*_cell` behaviour. Both Lua and VimL counterparts wired into ftplugin's existing table_editing block (gated alongside `gqq`/`<A-Left>`). Tests: 4 new in scripts/test-keymaps.lua — next cell, new-row overflow, previous cell, and pass-through outside a table. Gates: 421 Rust / 39 Neovim / 12 Vim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
e347f605ff |
parity(5): smart <CR> in insert mode (VimwikiReturn)
Bind `<CR>` in insert mode as an `<expr>` map to a `smart_return`
helper. Behaviour matches upstream vimwiki's `:VimwikiReturn`:
- On a list line with content → continue the list with the same
marker on a new line (preserving leading checkbox `[ ]` if any).
- On an empty list line (marker only) → clear the marker and break
out of the list with a plain newline.
- Inside a `|…|` table row → insert a fresh empty row below with
the same column count, cursor lands inside the first cell.
- Otherwise → plain `<CR>`.
Implementation note: the helper is `<expr>`-bound, which means
textlock is active and the buffer can't be mutated from inside the
callback. The function returns key sequences only — including
`<Esc>0DA<CR>` for the empty-list break and `<Esc>0li` for the
table-row cursor jump — so every effect flows through Vim's normal
keystroke pipeline and stays undo-coherent.
Both Lua and VimL counterparts shipped.
Tests: 4 new in scripts/test-keymaps.lua covering list continuation,
checkbox preservation, empty-marker break-out, and new table row.
Gates: 421 Rust / 35 Neovim / 12 Vim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
46ae618b5f |
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> |
||
|
|
ee0309b3c2 |
parity(1): vimwiki per-wiki config keys, table colspan/rowspan,
named link commands, mouse maps
Parity audit Cluster 1 — small wins.
WikiConfig (server) extended with 14 vimwiki globals:
- `index` (`g:vimwiki_index`), wired into `:VimwikiIndex` so users
with a custom index page stem (e.g. `home`) get the right file.
- `diary_frequency`, `diary_start_week_day`, `diary_caption_level`,
`diary_sort`, `diary_header` — diary keys (weekly/monthly/yearly
semantics land in Cluster 4; the keys parse now so config
migration doesn't need to wait).
- `maxhi`, `listsyms`, `listsyms_propagate`, `list_margin`,
`links_space_char`, `nested_syntaxes`, `auto_toc` — list +
highlight knobs the renderer/handlers can consult.
All keys threaded through `RawWiki` → `WikiConfig::from(RawWiki)`,
defaults centralised in `wiki_defaults()` so `empty()`, `from_root()`,
the legacy single-wiki path, and the `RawWiki` impl stay in sync.
Lua front-door (`lua/nuwiki/config.lua`) now documents the multi-wiki
`wikis = {…}` shape with every accepted per-wiki key — users who
prefer Lua tables no longer have to round-trip through
`init_options` raw JSON.
HTML renderer (`crates/nuwiki-core/src/render/html.rs`):
- New `table_spans()` pre-pass resolves vimwiki's `>` (col_span) and
`\\/` (row_span) continuation markers into proper HTML
`colspan="N"` / `rowspan="N"` attributes on the lead cell. Continuation
cells emit nothing, matching what browsers expect.
- The old behaviour (emitting `class="col-span"` / `class="row-span"`
as visual markers) is gone — replaced with real merging so the
rendered HTML matches the source semantics.
Named ex-commands:
- `:VimwikiNextLink` / `:VimwikiPrevLink` — were keymapped only
(`<Tab>`/`<S-Tab>`); now have explicit `:` commands in both editor
paths, dispatching to new `nuwiki.commands.link_next` / `link_prev`
pure-Vim/Lua helpers.
- `:VimwikiBaddLink` — adds the link target's file to the buffer
list without switching focus. Goes through
`textDocument/definition` and runs `:badd <fname>` on the resolved
URI.
Mouse maps (opt-in via `mappings.mouse = true` in Lua or
`g:nuwiki_mouse_mappings = 1` in Vim):
- `<2-LeftMouse>` follows, `<S-2-LeftMouse>` / `<C-2-LeftMouse>`
follow in split/vsplit, `<MiddleMouse>` adds to buflist,
`<RightMouse>` goes back. Mirrors upstream vimwiki's defaults.
Tests: 7 new in `parity_cluster_1.rs` covering the per-wiki config
defaults + raw JSON parse, the legacy-single-wiki path, colspan
folding into a lead cell with no leftover class markers, rowspan
across rows, no-attrs when the table has no spans, and a sanity
paragraph render. Total 421 Rust tests pass; clippy clean; both
keymap harnesses still green (20 nvim + 12 vim).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
de8b8fa30d |
feat(13.1): colorize + color_dic → ColorNode renderer
Closes the last pending §13.1 entries: - **`nuwiki.colorize`** (client-side, Lua + VimL) — wraps the word at cursor (or the visual selection on Neovim) in an inline `<span style="color:%c">…</span>` template. Matches vimwiki's default `color_tag_template`. Bound to `<Leader>wc` in both normal and visual mode on both editor paths; the previous "deferred" stub is gone. - **`color_dic` → renderer** — `HtmlConfig` gains a `color_dic: HashMap<String, String>` field reading the same key out of `initializationOptions` / `didChangeConfiguration`. The HTML export path threads it into `HtmlRenderer::with_colors`; `ColorNode` now picks `style="color:<value>"` when the colour name is in the dict, falling back to the existing `class="color-<name>"` when it isn't. SPEC §13.1 is fully checked off — the table moved from "deferred sketch" to a per-command status table marking all 11 commands done, plus a note on the `color_dic` follow-up landing alongside. README's "Phase 14 list & table edit commands" row now reads ✅ without the deferred-subset caveat, and the §13.1-blocked text-objects note in the keymaps section is rephrased as "planned follow-ups". Tests: 4 new in `phase17_colorize.rs` covering the renderer fallback when the dict is empty, the inline-style emission for a listed name, the fallback path for an unlisted name in a populated dict, and the `initializationOptions` JSON shape. Total 414 Rust tests pass; clippy clean; keymap harness still 20/20. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
4245424d2f |
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> |
||
|
|
9d34c8baa2 |
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> |
||
|
|
cebc806ce3 |
feat(13.1-C): link helpers — pasteWikilink, pasteUrl, normalize
Closing out §13.1's smallest cluster. Three commands move from "not yet implemented" stubs to real behaviour: - `nuwiki.link.pasteWikilink` (server, executeCommand) — derives the current page name from the source URI + wiki root, returns a `WorkspaceEdit` inserting `[[<page>]]` at the requested cursor position. - `nuwiki.link.pasteUrl` (server) — same lookup, but the inserted text is the page's relative HTML output URL (`<page>.html`, including subdir segments) so the snippet survives when the export root moves. - `nuwiki.link.normalize` (client) — wraps the word at cursor as `[[word]]` without following. Reuses the `wrap_cword_as_wikilink` helper that already powers the `<CR>` two-step. Pure-VimL on the Vim path; pure-Lua on the Neovim path. No LSP round-trip. Keymaps: - `+` (normal + visual) now actually calls `normalize_link` on both editor paths instead of stubbing with a "deferred" notification. Tests: - 5 new Rust unit tests in `cluster_c_link_helpers.rs` covering command-list presence + the page-name derivation for root and subdirectory pages + the URL / wikilink shape strings. - Neovim keymap harness gains a `links.normalize_via_+` case (20 passing now, up from 19). Vim harness inherits the same command-presence check via its existing smoke tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
5fdd7a842e |
test(keymaps): Vim path harness + fix 25 broken one-liner functions
User asked about the Vim path of the keymap suite. Building it
surfaced a real bug: 25 of our autoload functions were written as
`function! foo() abort | call bar() | endfunction` one-liners, which
isn't valid Vim syntax — `function!` requires a multi-line body, and
Vim parses the `|` after `abort` as an unexpected trailing character
(E488). Most invocations of the buggy autoload functions errored
out the moment Vim tried to parse them, which is why the user saw
broken keymaps and confusing diagnostics.
Rewrote all 25 one-liners (`autoload/nuwiki/commands.vim`) into the
standard three-line form. Affected groups: `diary_*`, `toggle_list_item`,
`cycle_list_item`, `reject_list_item`, `heading_add`, `heading_remove`,
`toc_generate`, `links_generate`, `export_current` / `_all` /
`_all_force` / `_rss`, and the §13.1 deferred stubs (`list_change_lvl`,
`list_remove_done`, `table_*`, `colorize`, `paste_link`, `paste_url`).
Added `scripts/test-keymaps-vim.{sh,vim}` — a Vim-side counterpart of
the Neovim harness covering the pure-VimL bindings (header nav,
link nav, `o`/`O` bullet continuation, `<CR>` wrap step). The
LSP-roundtrip bindings (`<C-Space>`, `=`, `-`, …) stay on the Neovim
side because vim-lsp's async layer uses timers that don't fire
inside `vim -e -s` headless mode — their server-side codepath is
already exercised by the Neovim harness and the cargo test suite.
Vim harness covers 12 cases: filetype + 2 command-presence smoke
tests, 4 header-nav (`]]`/`[[`/`]=`/`]u`), `<Tab>` link-nav, `<CR>`
wrap-on-first-press, and 3 bullet-continuation flows.
CI: extended the existing `keymaps` job to install both nvim + vim
and run both harnesses. Verified locally:
Neovim harness: 19 passed, 0 failed
Vim harness: 12 passed, 0 failed
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|