545367c3f6
TOC / links / tags section headings (and their levels) were hardcoded. Added per-wiki toc_header/toc_header_level, links_header/links_header_level, tags_header/tags_header_level — defaults Contents / Generated Links / Generated Tags at level 1, matching upstream (also fixes the tags index heading: Tags -> Generated Tags). A caption_line(name, level) helper emits the `=`-markers; the configured text + level thread through toc_edit / links_edit / tag_links_edit and the auto_toc save hook. find_section_range matches the configured text, so regeneration stays idempotent at any level. Tests: captions_honour_custom_header_and_level (link_health) + config round-trip + default assertions (index_and_config); existing tag/toc/links tests updated for the new arity and the Generated Tags default. fmt/clippy clean (8-arg ops get allow(too_many_arguments), matching the codebase precedent); 0 Rust test failures; config-parity green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
20 KiB
20 KiB
vimwiki → nuwiki Parity Gaps
Tracking document for closing the gap between nuwiki and the original vimwiki plugin across configuration, commands, and key mappings.
Source of truth for upstream: vimwiki master —
autoload/vimwiki/vars.vim (option defaults), plugin/vimwiki.vim +
ftplugin/vimwiki.vim (commands/mappings), doc/vimwiki.txt (prose).
Audited 2026-05-31. Check items off as they land. Each row cites the nuwiki fix site.
P1 — Core workflow gaps (fix first)
- Vim client split/tab link-follow commands —
VimwikiSplitLink,VimwikiVSplitLink,VimwikiGoBackLink,VimwikiTabnewLink,VimwikiTabDropLinkexist only in the Neovim branch. Vim users lose split-window link following and back-navigation. Fix:ftplugin/vimwiki.vim(Vim branch) — commands added +:Nuwiki*aliases;follow_link_drop()helper inautoload/nuwiki/commands.vim; true:tab droptab-reuse wired in both clients (lua/nuwiki/commands.luaopen_uri'tabdrop'case);<C-S-CR>repointed to tab-drop. gl<symbol>change-symbol mappings — upstream's one-key bullet/number symbol change (gl*gl#gl-gl1glagli… plusgL…) has no nuwiki keymap; only:…ChangeSymbol*commands exist. Fix: added normal-modegl{-,*,#,1,i,I,a,A}(item) +gL…(whole list) inlua/nuwiki/keymaps.lualists group andftplugin/vimwiki.vimVim-branch lists block, wired to the existinglist_change_symbol.1)stays command-only (upstream shadows it with1.); normal-mode only (server acts on cursor item / whole list, not a visual range).gl<Space>/gL<Space>semantics diverge — upstream = remove checkbox from item / list siblings; nuwiki rebound to remove done items. Same keys, different effect (parity trap). Fix: bound baregl/gLto remove-checkbox-item / -in-list for exact upstream parity (lua/nuwiki/keymaps.lualists block,ftplugin/vimwiki.vimVim-branch lists block); they share thegl…prefix so they fire aftertimeoutlen, just like upstream. Remove-done is now command-only::NuwikiRemoveDone(current list) gained a-bangso:NuwikiRemoveDone!reaches the whole-buffer sweep thatgL<Space>previously held (the only prior entry point). Normal-mode only.
Regressions (reported by users — verify, then fix)
<CR>link-follow: wrong window placement + no create-on-follow on the Vim clients — two related Vim-branch bugs (Neovim path was already correct): (a) on coc.nvim,<CR>opened the target in a new tab instead of the current window; (b) on both vim-lsp and coc,<CR>on a link to a not-yet-created page failed to open/create it. Root cause: the Vim follow path delegated to the LSP client's jump UI (:LspDefinition/CocActionAsync('jumpDefinition')). Those fetch the target's text before jumping — vim-lspreadfile()s it for the quickfix entry (autoload/lsp/utils/location.vim), which throwsE484for a missing file and aborts the jump (→ no create-on-follow); coc, lacking an explicit open command, fell back to the user'scoc.preferences.jumpCommand(→ new tab). The server itself was correct throughout — verified over JSON-RPC thattextDocument/definitionreturns a synthesised location for missing pages and resolves existing links. Fix: stop delegating.nuwiki#commands#follow_link_or_create()/follow_link_drop()now resolvetextDocument/definitiondirectly and open the URI ourselves via a shareds:open_definition(open_cmd)helper (autoload/nuwiki/commands.vim) —:editfor<CR>,tab dropfor<C-S-CR>.:editopens a buffer for a missing path (save creates it, matching vimwiki) and gives exact current-window placement regardless of the user's coc jumpCommand. Covered bycr.follow_opens_missing_page_in_current_windowindevelopment/tests/test-keymaps-vim.vim; manually reproducible viadevelopment/start-vim.sh(vim-lsp) anddevelopment/start-vim-coc.sh(coc).- coc.nvim reported valid links as broken / couldn't resolve — only via
the new
development/start-vim-coc.shlauncher: its generatedcoc-settings.jsonregistered the server withcommand/filetypesbut noinitializationOptions, sowiki_rootnever reached the server and it resolved links against its default (~/vimwiki). Fix: the launcher now emitsinitializationOptionsandsettings.nuwikimirroring the vim-lsp client (autoload/nuwiki/lsp.vims:settings()). Verified with a headless coc.nvim run:[[Notes]]resolves, only genuinely-missing links warn. (Shipped plugin only — no production code change; coc users configure their owncoc-settings.jsonper the README snippet.)
P2 — Moderate (real users hit these)
<Leader>w<Leader>tcollision — upstream = today-in-new-tab; nuwiki bound both<Leader>w<Leader>tand<Leader>w<Leader>mto tomorrow's diary. Fix:<Leader>w<Leader>tnow callsdiary_today_tab(today in a new tab),<Leader>w<Leader>mstays tomorrow — exact upstream parity (lua/nuwiki/keymaps.lua,ftplugin/vimwiki.vim; docs + README updated). Covered bydiary.leader_t_opens_today_in_tab/diary.leader_m_opens_tomorrow.- Generated-section captions hardcoded — TOC/links/tags headings and
their levels were hardcoded (
= Contents =,= Generated Links =,= Tags =, all level 1). Fix: added per-wikitoc_header/toc_header_level,links_header/links_header_level,tags_header/tags_header_level(defaultsContents/Generated Links/Generated Tags, level 1 — matching upstream; this also corrects the tags index heading fromTags→Generated Tags). Acaption_line(name, level)helper emits the markers; the text + level thread throughtoc_edit/links_edit/tag_links_edit(+ the auto_toc save hook) andfind_section_rangematches the configured text so regen stays idempotent. Tests:captions_honour_custom_header_and_level(link_health.rs) + config round-trip inindex_and_config.rs. - On-save autoregen family —
auto_diary_index,auto_generate_links,auto_generate_tags,auto_tags(onlyauto_toc/auto_exportexist). Fix:config.rsRawWiki/WikiConfig+ thedidSavepath. listsym_rejected— the rejected glyph was a hardcodedconst '-'. Fix:ListSymsgained arejectedfield +new_with_rejected()(crates/nuwiki-core/src/listsyms.rs); per-wikilistsym_rejectedkey (default-) added toWikiConfig;WikiConfig::list_syms()builds the palette with it, used by the parse path (lib.rs) and the toggle/cycle commands — so a custom rejected glyph both lexes and round-trips. Tests:listsyms::custom_rejected_glyph_is_honoured+ config round-trip inindex_and_config.rs.custom_wiki2html(+_args) andbase_url— external HTML converter hook + export URL prefix. Fix:config.rsHtmlConfig.map_prefix—<Leader>whardcoded across the map layer. Fix:plugin/nuwiki.vim,lua/nuwiki/keymaps.lua,ftplugin/vimwiki.vim.<M-CR>badd-link — was mouse-only (<MiddleMouse>) / command-only (:VimwikiBaddLink); upstream binds<M-CR>→VimwikiBaddLink(confirmed against upstreamftplugin/vimwiki.vim). Fix: added normal-mode<M-CR>→badd_linkin the links group of both clients (lua/nuwiki/keymaps.lua,ftplugin/vimwiki.vim; docs + README updated). Covered bymap[n].<M-CR>in both keymap harnesses.diary_caption_leveldefault divergence — nuwiki defaulted to1, upstream0. Fix:wiki_defaults()incrates/nuwiki-lsp/src/config.rsnow defaultsdiary_caption_level: 0(year captions top-level, months one below), still per-wiki overridable. Testdefaults_carry_vimwiki_per_wiki_keysupdated.diary_start_week_day— removed inc63ec67(weekly diary hardwired to ISO-Monday). Restored as a configurable choice so migrators keep upstream behaviour while new wikis can use ISO weeks. New per-wiki keydiary_weekly_style:iso(default —YYYY-Www, Monday-based, nuwiki's original) ordate/vimwiki(YYYY-MM-DDof the week-start day, upstream parity, honouring the restoreddiary_start_week_day=monday..sunday). Impl:nuwiki_core::date::{WeeklyStyle, WeekStart, DiaryCalendar}own the today/next/prev logic;WikiConfig::diary_calendar()builds it from config; the diary commands (commands.rsdiary_open_relative+ next/prev pivot) use it. Defaults keep existing nuwiki weekly files working (no breaking change). Covered by calendar tests incrates/nuwiki-core/tests/diary.rsand the config round-trip incrates/nuwiki-lsp/tests/index_and_config.rs.
P3 — Niche / low impact
Commands
VimwikiVar— config-var get/set introspection. Fix:plugin/nuwiki.vim.VimwikiShowVersion— print version (trivial). Fix:plugin/nuwiki.vim.VimwikiReturn— no Ex-command (mapping-driven only). Fix:ftplugin/vimwiki.vim.VimwikiTableAlignQvsAlignWcollapsed to onetable_align—gqq(align) vsgww(align w/o resize) distinction lost.VimwikiTableis-nargs=1vs upstream-nargs=*(can't pass cols+rows).VimwikiListChangeLvlis-nargs=?vs upstream-range -nargs=+.VimwikiRebuildTags-bang("rebuild all") —:…RebuildTags!now passes{ all: true }; the server (tags_rebuild) re-indexes every configured wiki (viawikis_snapshot()) instead of just the current one.-bangadded to all four command defs.:VimwikiSearch/VWSuseslvimgrep, not vimwiki's search engine.VimwikiIndexfamily is buffer-local in nuwiki (upstream defines globally inplugin/); only:…UISelectis a global entry point.VimwikiColorize/NuwikiColorizedrop their argument in the Neovim branch — both are-nargs=1, but the Neovim defs calledcolorize()with no<q-args>(ftplugin/vimwiki.vim:445,517) while the Vim branch passes it. The color name was silently ignored under Neovim (real bug, not just parity). Fix: Neovim command defs now pass<q-args>. While verifying, found a second bug:colorize()inferred visual-vs-normal fromvim.fn.visualmode(), which returns the last session visual mode with stale'</'>marks — so the normal-mode command wrapped a leftover selection instead of the cword.colorize(color, visual)now takes an explicitvisualflag; the command and normal mapping always wrap the cword. Third bug: the commands were not-range, so selecting text and running:VimwikiColorize(which Vim turns into:'<,'>VimwikiColorize) raisedE481: No range allowed. All four command defs are now-rangeand pass the range to the handler — a ranged (visual) invocation wraps the'</'>selection on both clients; thex-mode<Leader>wcmapping passes the visual flag directly. Covered bycmd.VimwikiColorize_uses_arg,cmd.Colorize_ignores_stale_visual_selection,colorize.visual_wraps_selection,cmd.Colorize_range_wraps_selectionintest-keymaps.luaandcolorize.{command_wraps_cword,visual_wraps_selection, ranged_command_no_error}intest-keymaps-vim.vim.- Colour spans aren't concealed — a colorized word shows the literal
<span style="color:…">…</span>markup instead of just the coloured text. Fix:autoload/nuwiki/colors.vimnuwiki#colors#refresh()scans the buffer and defines, per colour, a syntax region that conceals the<span …>/</span>tags (concealends) and paints the wrapped text in the span's actual colour (guifg/ctermfg). Wired from the syntax file (initial + on:colorschemereload), anftpluginTextChangedautocmd, and directly fromcolorize()for immediate effect. The LSP@vimwikiColortoken no longer links toConstantso it doesn't override the real colour on the concealed text in Neovim. Works in Vim, coc, and Neovim (pure syntax +:highlight, no LSP needed). Covered bycolorize.conceal_hides_tags_shows_text(both harnesses) andcolorize.command_conceals_immediately(test-keymaps-vim.vim). VimwikiTableMoveColumn{Left,Right}dispatch to different backing names per client — converged: the Vim-branch commands now callnuwiki#commands#table_move_column_left/right(existing aliases over thetable_move_left/rightimpls), matching the Neovim branch.NuwikiTabIndexlacks-countin the Neovim branch — added-count; also switched the NeovimIndex/TabIndexfamily (Vimwiki/NuwikiTabIndexandVimwiki/NuwikiIndex) fromvim.v.count(always 0 in command context) to<count>, so a:2NuwikiIndex/:3NuwikiTabIndexcount is now honored. (TheIndexhalf was caught by the 2026-05-31 second re-audit and fixed then.)VimwikiToggleListItem/Increment/DecrementListItem-range— all three (both branches) are now-range; the client loops the per-line op over[<line1>, <line2>](toggle_list_item_range/list_cycle_symbol_range). The server edits are version-less single-line, so each line's edit applies independently — no server protocol change needed. Covered bycmd.toggle_list_item_rangeintest-keymaps.lua.- Diary-note family lacks
-count(new, 2026-05-31 re-audit) — upstream's:Vimwiki{Make,TabMake,MakeYesterday,MakeTomorrow}DiaryNotecarry-count=0(the count selects the wiki number); nuwiki's diary-note commands declare no count in either branch, andIndex/TabIndexuse bare-countvs upstream-count=0. Fix:ftplugin/vimwiki.vimdiary block (both branches) + thread the count intodiary_today/yesterday/tomorrow. - No
-complete=specs (new) — upstream attaches command-line completion toVimwikiGoto(links),VimwikiRenameFile(files),VimwikiColorize(colours), and the tag commands. nuwiki defines none, so<Tab>completion of page / tag / colour names at the:line is unavailable. Fix:ftplugin/vimwiki.vim(both branches) — VimL completers or LSP-backed. - Minor command-attribute gaps (new) — all now real, not cosmetic:
VimwikiNormalizeLinkis-nargs=?and with1wraps the'</'>selection (wrap_visual_as_wikilink, both clients; thex-mode+passes it too);VimwikiCheckLinksis-rangeand a ranged invocation filters the report to the current buffer's selected lines;VimwikiColorize-nargs=1→-nargs=*(bare:VimwikiColorizeprompts). Covered bynormalize.visual_wraps_selection(vim) /cmd.normalize_link_visual_wraps_selection(nvim). VimwikiSplitLink/VimwikiVSplitLinklack-nargs=*(new, 2026-05-31 third re-audit) — upstream both take an optional target link to follow in the split; nuwiki's defs (both branches) take no args, so you can't pass a link to the split-follow. Low impact (the arg path is rarely used). Fix:ftplugin/vimwiki.vimboth branches + thread a target throughfollow_link_or_create.
Config
auto_header— auto H1-from-filename on new page (server-side).create_link— toggle to suppress link-target creation.dir_link— index file to open when following a directory link.auto_chdir—:cdinto wiki root on open (client-side).bullet_types/cycle_bullets— custom bullet glyphs + wrap-around.commentstring('%%%s') — comment toggling/text-objects.color_tag_template—color_dicpresent; template regex missing.rss_max_items/rss_name—:Rssoutput hardcoded. Fix:HtmlConfig.emoji_enable— emoji substitution.html_header_numbering(+_sym) — numbered HTML headers.valid_html_tags— allowed inline HTML tags in export.generated_links_caption,toc_link_format,markdown_link_ext.list_ignore_newline/text_ignore_newline— export newline handling.
Mappings
- Visual
<CR>normalize-link (visual+covers the same intent). - Insert
<S-CR>multiline list item. gLH/gLL/gLR— upstream binds these as case-variant aliases ofgLh/gLl/gLr(same actions: dedent / indent whole item, renumber all lists; upstreamftplugin/vimwiki.vim:553,555,561). nuwiki has the lowercase forms but not the uppercase-suffix aliases. Cosmetic — same effect, redundant keys.<D-CR>(Cmd+Return) tab-drop alias (new, 2026-05-31 re-audit) — added<D-CR>→follow_link_dropalongside<C-S-CR>in both clients (lua/nuwiki/keymaps.lua,ftplugin/vimwiki.vim); docs updated. Covered bymap[n].<D-CR>in both harnesses.<Leader>w<Leader>mmissing from the Vim global map block (new) —plugin/nuwiki.vim's global family now binds<Leader>w<Leader>m(tomorrow) and<Leader>w<Leader>topens today in a new tab (was the same collision the buffer-local maps had). Covered bymap[n].<Leader>w<Leader>min both harnesses.
Intentional divergences (no action — architectural)
These upstream options have no nuwiki equivalent by design, because nuwiki is an LSP-backed reimplementation rather than a pure-VimL plugin. Listed so future audits don't re-flag them.
nested_syntaxes/automatic_nested_syntaxes— code-fence languages are auto-detected from the fence tag (syntax/vimwiki.vim); always on, no toggle.maxhi— existence-based link highlighting; superseded by LSP diagnostics.conceal*(conceallevel,conceal_onechar_markers, …) — semantic tokens replace conceal.ext2syntax— syntax chosen by extension /syntaxkey automatically.folding(upstream string) — nuwiki usesfolding = 'lsp' | 'expr' | 'off'backed by LSP foldingRange.key_mappings(dict) — replaced by Luamappings.<group>+ theg:nuwiki_no_<group>_mappingsglobals.use_calendar— no calendar.vim integration.- Mouse maps (
<2-LeftMouse>,<MiddleMouse>, …) — upstream binds them unconditionally; nuwiki ships them opt-in (mappings.mouse/g:nuwiki_mouse_mappings). Deliberate, so they're not always-on. global_ext(upstream1) — nuwiki's ftdetect always maps the configured wiki extension(s) to thevimwikifiletype regardless of location; there's no per-wiki "only inside the root" toggle. Effectively always-on, likenested_syntaxes.syntaxdefault name — nuwiki defaults the per-wikisyntaxtovimwiki(its primary syntax) where upstream defaults todefault; a naming difference, not a behavioural one.CJK_length,listing_hl*,schemes_*,w32_dir_enc,menu,rx_todo/tag_format— syntax internals, menu, or Vim/Win shims.
Notes
- Audit confidence: upstream defaults pulled from vimwiki
master; a couple of values (CJK_length,links_space_char) were summarized loosely but don't affect the gap list. - nuwiki adds some commands with no upstream equivalent (e.g.
:NuwikiFindOrphans) — additive, not divergences. - Re-audited 2026-05-31 (config / mappings / commands, three parallel agents
against vimwiki
master). All recent P1/P2/P3 fixes — split/tab link-follow,gl/gLchange-symbol + bare-gl/gLremove-checkbox,<CR>-family create-on-follow,<M-CR>badd,<Leader>w<Leader>t/m,VimwikiColorizearg+range, colour-span conceal — confirmed present and correct in both clients. New gaps from that pass (diary-note-count,-completespecs,<D-CR>, global<Leader>w<Leader>m, plusglobal_ext/syntax-name notes) were added above; no previously-closed item regressed. - Re-audited again 2026-05-31 (third pass) after the range/bang/visual and
diary-week work. All those fixes confirmed in both clients; no regressions.
Confirmed Neovim does bind the text objects (
nuwiki.textobjects.attach). Found + fixed an oversight (NeovimVimwiki/NuwikiIndexstill readvim.v.count; now<count>, completing theTabIndexfix). New gaps logged:VimwikiSplitLink/VSplitLinkmissing-nargs=*; mouse-maps-opt-in noted as an intentional divergence. Config pass found no new gaps; all shipped defaults match upstream except the documentedsyntax-name divergence.