Commit Graph

224 Commits

Author SHA1 Message Date
gffranco 3c1ed48a2f fix(install): resolve release asset via Gitea API (download was always 404)
CI / cargo fmt --check (push) Successful in 29s
CI / cargo clippy (push) Successful in 40s
CI / cargo test (push) Successful in 46s
CI / editor keymaps (push) Successful in 1m40s
:NuwikiInstall always fell back to building from source because the
download URL used the GitHub-only shape
`/releases/latest/download/<asset>`, which this Gitea instance serves as
404. The release assets exist and are correctly named; only the URL was
wrong.

Resolve the asset's real download URL through the Gitea API instead: GET
`/api/v1/repos/.../releases/latest`, find the asset matching
`nuwiki-ls-<target>.tar.gz`, and download its `browser_download_url`
(`/releases/download/<tag>/<asset>`, which returns 200). Fixed in both
install paths — lua/nuwiki/install.lua (vim.json.decode) and
scripts/download_bin.vim (json_decode). Verified end to end: resolve →
download → extract → executable binary.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 01:41:21 +00:00
gffranco 34a0607e7a chore(release): bump version to 0.2.0
CI / cargo fmt --check (push) Successful in 48s
CI / cargo clippy (push) Successful in 1m0s
CI / cargo test (push) Successful in 1m28s
Release / build aarch64-unknown-linux-musl (push) Successful in 1m33s
Release / build x86_64-unknown-linux-gnu (push) Successful in 1m0s
Release / build aarch64-unknown-linux-gnu (push) Successful in 1m2s
Release / build x86_64-unknown-linux-musl (push) Successful in 1m1s
Release / gitea release (push) Successful in 26s
CI / editor keymaps (push) Successful in 1m45s
Minor feature release over v0.1.0 (124 commits). Highlights:
- Drop-in upstream g:vimwiki_list / g:vimwiki_* config (Vim) + global
  per-wiki defaults shorthand (both clients)
- Programmatic coc.nvim registration (no hand-written coc-settings.json)
- :NuwikiTOC / GenerateLinks / GenerateTagLinks insert at the cursor line;
  scoped :NuwikiGenerateLinks <path> wired up
- HTML export: heading id anchors, div.toc wrapper, section numbering;
  toc_header/level honoured in single-wiki config
- The full P3 config/command/mapping parity batch + R1–R18 review fixes

Bumps the workspace version, the inter-crate path-dep requirements, and
g:nuwiki_version.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 01:29:29 +00:00
gffranco daee0f1902 feat(links): wire up nuwiki.links.generateForPath (scoped GenerateLinks)
CI / cargo fmt --check (push) Successful in 24s
CI / cargo clippy (push) Successful in 30s
CI / cargo test (push) Successful in 40s
CI / editor keymaps (push) Successful in 1m22s
`:VimwikiGenerateLinks <path>` sent nuwiki.links.generateForPath, but the
server had no handler and didn't advertise it — so the scoped form was
silently dropped (only the no-arg form worked). Register and implement it.

The page list is scoped via page_in_scope: a plain `path` is a directory
subtree (the page itself or anything under `<path>/`); a `path` with `*`/`?`
is a glob pattern (upstream's behaviour), matched with export::glob_match
(now pub(crate)). links_generate and the scoped form share
links_generate_scoped, so cursor-line insertion + captions + config all
apply uniformly.

Tests: page_in_scope unit tests (subtree, glob, prefix-sibling, trailing
slash) + COMMANDS advertises both generate forms. 580 passed, clippy
clean, harnesses green. Doc updated with the [path] argument.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 01:23:42 +00:00
gffranco f0c51fbfcc feat(generate): insert links/tags sections at the cursor line too
CI / cargo fmt --check (push) Successful in 28s
CI / cargo clippy (push) Successful in 36s
CI / cargo test (push) Successful in 40s
CI / editor keymaps (push) Successful in 1m26s
Extend the cursor-line insertion from :NuwikiTOC to the other buffer
list generators: :NuwikiGenerateLinks and :NuwikiGenerateTagLinks. They
appended at end-of-file; a fresh section now goes at the cursor line
(with a leading blank), matching :NuwikiTOC. An existing section is still
refreshed in place, and the auto_generate_*-on-save hooks are unaffected
(they only ever replace).

Shared section_insert() helper computes the insert position/block for all
three (cursor line clamped to the document, else the per-command fallback:
top of file for TOC, EOF for links/tags). Clients send the 0-based cursor
line; handlers parse it via parse_uri_line_arg and thread it through
links_edit / tag_links_edit. Rebuild variants pass None.

Tests: links_edit_inserts_at_cursor_line + tag_links_edit_inserts_at_cursor_line.
577 passed, clippy clean, keymap harnesses green. Docs updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 01:07:18 +00:00
gffranco 94cb58064d feat(toc): insert a fresh TOC at the cursor line
CI / cargo fmt --check (push) Successful in 35s
CI / cargo clippy (push) Successful in 39s
CI / cargo test (push) Successful in 50s
CI / editor keymaps (push) Successful in 1m25s
:NuwikiTOC inserted a new table of contents at the top of the file. It now
inserts at the cursor line instead, so you can place the TOC where you want
it (a blank line separates it from preceding text). An existing TOC is
still refreshed in place, and auto_toc-on-save is unaffected.

The Vim/Lua clients send the 0-based cursor line with nuwiki.toc.generate;
the server threads it into toc_edit (clamped to the document) and falls
back to the top of the file when absent. toc_rebuild_edit passes None.

Tests: toc_edit_inserts_at_cursor_line +
toc_edit_cursor_line_clamped_and_existing_replaced_in_place. 575 passed,
clippy clean, keymap harnesses green. Doc updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:51:40 +00:00
gffranco 9d6d28a1b6 fix(vim): buffer commands honour g:vimwiki_list (<Leader>ww opened ~/vimwiki)
CI / cargo fmt --check (push) Successful in 33s
CI / cargo clippy (push) Successful in 33s
CI / cargo test (push) Successful in 41s
CI / editor keymaps (push) Successful in 1m23s
The g:vimwiki_* drop-in only fed the LSP payload (lsp.vim s:settings).
The buffer-side commands — <Leader>ww (wiki_index), :VimwikiSearch,
auto_chdir, diary, completion — resolve the wiki list independently via
s:wiki_cfg / nuwiki#commands#wiki_list, which read only g:nuwiki_wikis /
g:nuwiki_wiki_root. So with a g:vimwiki_list config the server knew the
wikis but <Leader>ww fell back to the default ~/vimwiki and opened an
empty index.

Extract the resolution into a single source of truth,
autoload/nuwiki/config.vim (nuwiki#config#wikis / #scalar_globals), which
resolves g:nuwiki_wikis or an upstream g:vimwiki_list and folds the global
scalar defaults. lsp.vim (payload), commands.vim, and diary.vim all route
through it — also dedups the s:wiki_cfg copy that lived in both
commands.vim and diary.vim.

Regression guard in test-vimwiki-compat-vim: nuwiki#commands#wiki_list()
must resolve the g:vimwiki_list roots (21 checks). All Vim harnesses +
config-parity goldens green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:40:48 +00:00
gffranco 346e8b0de6 dev: NUWIKI_DEV_VIMWIKI mode to dogfood the g:vimwiki_* drop-in
CI / cargo fmt --check (push) Successful in 25s
CI / cargo clippy (push) Successful in 30s
CI / cargo test (push) Successful in 38s
CI / editor keymaps (push) Successful in 1m31s
The start-vim-coc.sh harness runs `vim --clean`, so it never sources a
user's real vimwiki.vim — meaning g:vimwiki_list is never set and the
g:vimwiki_* drop-in translation was impossible to exercise through the
harness (you'd only ever test the native g:nuwiki_* path).

Add NUWIKI_DEV_VIMWIKI=1: instead of g:nuwiki_*, the generated vimrc
configures an upstream g:vimwiki_list (+ g:vimwiki_toc_header_level etc.)
pointing at the scratch wiki, so nuwiki's client-side translation +
programmatic coc registration run on a real vimwiki-shaped config.

    NUWIKI_DEV_VIMWIKI=1 ./development/start-vim-coc.sh

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:26:11 +00:00
gffranco ac14cdd838 feat(coc): auto-register the language server with coc.nvim
CI / cargo fmt --check (push) Successful in 47s
CI / cargo clippy (push) Successful in 46s
CI / cargo test (push) Successful in 56s
CI / editor keymaps (push) Successful in 1m30s
coc users had to hand-maintain a coc-settings.json `languageserver.nuwiki`
entry, which didn't track g:nuwiki_wikis / g:vimwiki_list / the global
shorthand and meant editing JSON per wiki. nuwiki now registers itself
programmatically: on the first .wiki buffer it calls
coc#config('languageserver.nuwiki', {…}) with the s:settings() payload
(same config the vim-lsp path sends). coc reacts to the languageserver
config change (onDidChangeConfiguration → registerClientsByConfig) and
starts the server for the open buffer.

Details:
- Reliable coc detection via :CocConfig (exists('*coc#config') can't be
  trusted — it doesn't trigger autoload in Vim 9.2). The coc#config call
  is wrapped in try/catch and autoloads coc.vim itself; falls back to the
  printed snippet only if coc genuinely isn't there.
- Deferred to User CocNvimInit when coc's node service isn't up yet.
- Opt out with g:nuwiki_no_coc_register (then we just print the snippet).

Dogfooded in start-vim-coc.sh: dropped the manual coc-settings.json
languageserver block; the harness now relies on auto-registration from
g:nuwiki_* (real-user flow). New harness test-coc-register-vim (7 checks,
stubbed coc#config) asserts the injected payload incl. the folded global
shorthand; wired into CI. README coc section rewritten (zero-config).
Rust 573 passed, clippy clean, all harnesses green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 00:07:50 +00:00
gffranco a4643bdacb dev: exercise toc_header_level + html numbering in the dev launchers
CI / cargo fmt --check (push) Successful in 36s
CI / cargo clippy (push) Successful in 45s
CI / cargo test (push) Successful in 51s
CI / editor keymaps (push) Successful in 1m47s
The start-* dev harnesses generated a minimal server config (wiki_root,
file_extension, syntax, log_level, diagnostic) with no display settings,
so :NuwikiTOC always produced `= Contents =` (level 1) regardless of code
changes — there was no way to test toc_header_level/html numbering through
the harness. The coc launcher is worst: coc reads coc-settings.json
verbatim, bypassing the Vim client's config translation entirely.

Set toc_header_level=2, html_header_numbering=2, html_header_numbering_sym
in all three launchers:
- start-vim-coc.sh: into the generated coc-settings.json (init + settings).
- start-vim.sh: as g:nuwiki_* globals (folded into the wiki via the global
  shorthand).
- start-nvim.sh: in the setup() table.

Now the dev wiki demonstrates the settings: :NuwikiTOC writes
`== Contents ==` and HTML export numbers headings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 23:50:40 +00:00
gffranco 9d89e01ed8 feat(config): vimwiki drop-in config + global per-wiki defaults
CI / cargo fmt --check (push) Successful in 31s
CI / cargo clippy (push) Successful in 32s
CI / cargo test (push) Successful in 41s
CI / editor keymaps (push) Successful in 1m53s
Two related config-ergonomics features for vimwiki migrants, sharing the
same scalar-global machinery.

1. Upstream g:vimwiki_* drop-in (Vim client). When nuwiki isn't configured
   natively, the Vim client reads g:vimwiki_list + g:vimwiki_* globals and
   translates them into nuwiki's schema: per-wiki path->root,
   path_html->html_path, template_*, css_name, auto_export/auto_toc,
   syntax, ext->file_extension, index, diary_*, name. g:nuwiki_* always
   wins. Lets a vimwiki user drop in nuwiki without rewriting config.

2. Global per-wiki defaults (both clients). A display/generation setting
   given once at the top level — g:nuwiki_<key> / setup({<key>=…}) /
   g:vimwiki_<key> — is folded into every wiki as a default; a per-wiki
   value overrides it (vimwiki's model). Covers toc_header(_level),
   toc_link_format, links_header(_level), tags_header(_level),
   html_header_numbering(_sym), links_space_char, list_margin, listsyms,
   listsym_rejected, and the auto_* toggles. Only values the user
   explicitly set fold — built-in defaults don't (added config.user
   tracking on the Lua side so a default toc_header_level=1 isn't pushed
   onto every wiki). User config tables are never mutated.

Both clients kept in lock-step (config-parity golden enforces identical
payloads). New harnesses test-vimwiki-compat-vim (18) and
test-global-shorthand (8), wired into CI. Server test
vimwiki_compat_payload_sets_toc_level_per_wiki. Docs in README +
known-issues.md (drop-in is currently Vim-only). Rust 573 passed, clippy
clean, all harnesses green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 23:37:10 +00:00
gffranco fc0d74bfbe fix(toc): honour toc_header/level in single-wiki config + div.toc on export
CI / cargo fmt --check (push) Successful in 48s
CI / cargo clippy (push) Successful in 54s
CI / cargo test (push) Successful in 1m4s
CI / editor keymaps (push) Successful in 1m38s
Two TOC bugs:

1. :NuwikiTOC ignored toc_header / toc_header_level (always "= Contents ="
   at level 1). In the single-wiki shorthand the server only carried
   file_extension/syntax from the top-level options into the synthesized
   wiki; every other per-wiki key (toc_header, toc_header_level,
   links_header, html_path, auto_export, …) was dropped. Add
   single_wiki_from_value(), which re-parses the top-level object as a full
   RawWiki (injecting root from wiki_root), so all per-wiki keys set at the
   top level flow through. Wired into from_init_params + apply_change.

2. HTML export put class="toc" on the <hN> element, but upstream vimwiki
   (and its stylesheet) wraps the TOC heading in <div class="toc">…</div>.
   render_heading now emits the div wrapper, matching upstream so .toc CSS
   applies. With (1) fixed, detection also works for a custom toc_header.

Tests: single_wiki_shorthand_honours_top_level_per_wiki_keys (config),
toc_header_heading_wrapped_in_div_toc + non_toc_heading_not_wrapped
(renderer). Full suite 572 passed; clippy clean; config-parity goldens
match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 22:56:17 +00:00
gffranco f3d8af5f23 fix: TOC header class, numbering config, and Lua defaults
CI / cargo fmt --check (push) Successful in 31s
CI / cargo clippy (push) Successful in 31s
CI / cargo test (push) Successful in 36s
Release / build x86_64-unknown-linux-gnu (push) Successful in 53s
Release / build aarch64-unknown-linux-musl (push) Successful in 1m6s
Release / build x86_64-unknown-linux-musl (push) Successful in 1m8s
Release / build aarch64-unknown-linux-gnu (push) Successful in 1m47s
Release / gitea release (push) Successful in 28s
CI / editor keymaps (push) Successful in 1m39s
- Add class='toc' to TOC heading in HTML export by detecting the
  configured toc_header value in render_heading()
- Add toc_header field to HtmlRenderer and wire it through
  render_page_html()
- Add toc_header, toc_header_level, html_header_numbering, and
  html_header_numbering_sym to Lua config defaults so users can
  discover and set them
2026-06-04 00:39:20 -03:00
gffranco bd729d513d fix: include release notes in Gitea API payload
CI / cargo fmt --check (push) Successful in 29s
CI / cargo clippy (push) Successful in 35s
CI / cargo test (push) Successful in 52s
Release / build x86_64-unknown-linux-gnu (push) Successful in 50s
Release / build x86_64-unknown-linux-musl (push) Successful in 56s
CI / editor keymaps (push) Successful in 1m55s
Release / build aarch64-unknown-linux-gnu (push) Successful in 3m16s
Release / build aarch64-unknown-linux-musl (push) Successful in 4m23s
Release / gitea release (push) Successful in 1m40s
The release notes were generated but never passed to the Gitea API.
Also suppress the expected 404 from the idempotency check.
2026-06-03 22:43:53 -03:00
gffranco 5a936e4f96 fix: add checkout step to release job for git commands
CI / cargo fmt --check (push) Successful in 49s
CI / cargo clippy (push) Successful in 49s
CI / cargo test (push) Successful in 58s
Release / build aarch64-unknown-linux-musl (push) Successful in 1m2s
Release / build x86_64-unknown-linux-gnu (push) Successful in 1m36s
Release / build x86_64-unknown-linux-musl (push) Successful in 1m34s
CI / editor keymaps (push) Successful in 1m44s
Release / build aarch64-unknown-linux-gnu (push) Successful in 2m27s
Release / gitea release (push) Successful in 1m51s
download-artifact@v3 doesn't create a git repo, so git log/git tag
fail in the release notes generation step.
2026-06-03 22:33:08 -03:00
gffranco 32cf4508de fix: use artifact v3 for GHES compatibility
CI / cargo fmt --check (push) Successful in 38s
CI / cargo clippy (push) Successful in 34s
CI / cargo test (push) Successful in 32s
Release / build aarch64-unknown-linux-musl (push) Successful in 3m31s
Release / build x86_64-unknown-linux-gnu (push) Successful in 57s
Release / build aarch64-unknown-linux-gnu (push) Successful in 1m8s
Release / build x86_64-unknown-linux-musl (push) Successful in 1m3s
CI / editor keymaps (push) Successful in 1m22s
Release / gitea release (push) Failing after 14s
Gitea (GHES) does not support upload-artifact@v4+.
Revert to v3 which is supported on GHES.
2026-06-03 22:17:31 -03:00
gffranco 7e757c6a7f release: fix restore-keys pipe syntax for Gitea 2026-06-03 22:17:31 -03:00
gffranco a5a07768d6 ci: fix restore-keys to use pipe syntax (Gitea doesn't support YAML list) 2026-06-03 22:17:31 -03:00
gffranco 08ebdc6f9b ci: remove concurrency key (not supported by Gitea Actions) 2026-06-03 22:17:31 -03:00
gffranco b77f4b1ced ci: improve workflows with stricter checks, caching, and idempotency
CI improvements:
- Add concurrency group to cancel redundant runs on same branch
- Add cargo cache to fmt job (was missing entirely)
- Add timeout-minutes: 5 to fast jobs (fmt, clippy, test) for fail-fast
- Change RUST_BACKTRACE from 'short' to '1' for better CI debuggability
- Pin push trigger to branches: [main] to avoid double-firing on PR merges
- Test minimum supported Neovim (0.11.0) instead of latest patch (0.11.3)

Release improvements:
- Enforce RUSTFLAGS: -D warnings at env level and in matrix rustflags
- Remove redundant checkout in release job (only needs env vars)
- Add release notes generation from git log since previous tag
- Make release creation idempotent (check if release exists before creating)
- Fix release_id not being set when release already exists
2026-06-03 22:17:31 -03:00
gffranco c9d75aeb1f Ci improvements (#5)
CI / cargo fmt --check (push) Successful in 42s
CI / cargo clippy (push) Successful in 34s
CI / cargo test (push) Successful in 38s
CI / editor keymaps (push) Successful in 1m32s
Reviewed-on: #5
Co-authored-by: Gabriel Fróes Franco <gffranco@gmail.com>
Co-committed-by: Gabriel Fróes Franco <gffranco@gmail.com>
2026-06-04 01:06:53 +00:00
gffranco cd4bfffef9 Ci improvements (#4)
CI / cargo fmt --check (push) Successful in 31s
CI / cargo clippy (push) Successful in 49s
CI / cargo test (push) Successful in 32s
CI / editor keymaps (push) Successful in 1m34s
Reviewed-on: #4
2026-06-03 23:52:46 +00:00
gffranco 0de2bd9d68 revert e530b3d623
CI / cargo fmt --check (push) Successful in 18s
CI / cargo clippy (push) Successful in 26s
CI / cargo test (push) Successful in 35s
CI / editor keymaps (push) Successful in 1m24s
revert Ci improvements (#3)

Reviewed-on: #3
2026-06-03 23:36:11 +00:00
gffranco e530b3d623 Ci improvements (#3)
Reviewed-on: #3
2026-06-03 23:35:10 +00:00
gffranco a2ca49a64c docs: fix README.md stale documentation and incorrect mappings
CI / cargo fmt --check (push) Successful in 51s
CI / cargo clippy (push) Successful in 27s
CI / cargo test (push) Successful in 33s
CI / editor keymaps (push) Successful in 1m35s
- Add NuwikiSearch to commands table (was incorrectly marked as Vimwiki-only)
- Add missing Vim globals: g:nuwiki_no_calendar, g:nuwiki_auto_chdir, g:nuwiki_auto_header
- Fix Plain Vim manual install to use cp instead of symlink (aligns with install() helper)
- Add missing <S-CR> insert-mode keymap to Lists keymaps table
- Clean up diary frequency section line wrapping
2026-06-03 19:51:27 -03:00
gffranco 5090ab1be0 docs: retire development/vimwiki-gap.md
CI / editor keymaps (push) Successful in 1m27s
CI / cargo fmt --check (push) Successful in 27s
CI / cargo clippy (push) Successful in 54s
CI / cargo test (push) Successful in 46s
The parity work stream is complete. Forward-looking content (vimwiki
divergences, deferred features, internal deferrals) now lives in the
single source of truth, known-issues.md; the historical per-item
tracking log is preserved in git history. No code or docs reference the
file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 15:31:29 +00:00
gffranco 68f10971f7 fix(html): emit heading id anchors so exported #links resolve
CI / cargo fmt --check (push) Successful in 26s
CI / cargo clippy (push) Successful in 27s
CI / cargo test (push) Successful in 31s
CI / editor keymaps (push) Successful in 1m22s
Exported HTML anchor links (TOC entries, [[Page#Heading]], [[#Heading]])
went nowhere because heading elements carried no `id`. Worse, the two TOC
builders slugified anchors (`#my-heading`) while the link resolver emits
the raw heading text (`#My Heading`, matching upstream vimwiki), so even
once ids existed the two halves wouldn't have agreed.

Fix — adopt vimwiki's scheme (raw heading text as the anchor) everywhere:
- render_heading emits `<hN id="<plain heading text>">`.
- build_toc_html (HTML export TOC) uses the raw, HTML-escaped title for
  both the href and the link text (was slugify).
- collect_toc_items (:VimwikiTOC buffer output) uses the raw title for the
  generated `[[#anchor]]` (was slugify). In-editor navigation slugifies
  both sides, so it still resolves.

Consistency: add canonical `nuwiki_core::ast::inline_text()` and route the
heading id, the HTML-TOC title, the buffer-TOC title, and
`diagnostics::heading_text` through it — three duplicated extractors
collapsed into one, so the anchor and its validation can't drift.

Regression test: heading_id_matches_anchor_link_href (core) asserts the
heading id and a `#anchor` link's href are identical. Updated the heading
assertions in the renderer/export tests for the new `id=` attribute.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 15:09:33 +00:00
gffranco ddb9d0b916 fix(vars): E121 in get_wikilocal no-index path; add regression test
CI / cargo fmt --check (push) Successful in 39s
CI / cargo clippy (push) Successful in 28s
CI / cargo test (push) Successful in 29s
CI / editor keymaps (push) Successful in 1m45s
s:resolve_index referenced an undefined `a:file` (a copy-paste leftover
from wiki_root_for, whose parameter is named a:file) inside the
buffer-owning-wiki loop. Any get_wikilocal() call with no explicit index
while a wiki buffer was current — i.e. the ftplugin BufRead path — hit
`E121: undefined variable a:file`. The local is `l:file`, and the
surrounding `!empty(l:file)` guard already covers emptiness, so the
clause was both wrong and redundant; removed it.

Add development/tests/test-vars-vim.{sh,vim} covering the shim:
per-wiki-index resolution, global-default fallback, out-of-range clamp,
the no-index owning-wiki path (direct guard for this E121), and the
single-wiki shorthand. Wired into CI. 14/14 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:57:14 +00:00
gffranco 255e24d1e0 docs(known-issues): make it the single source of truth
CI / cargo fmt --check (push) Successful in 17s
CI / cargo clippy (push) Successful in 30s
CI / cargo test (push) Successful in 40s
CI / editor keymaps (push) Successful in 1m25s
Promote known-issues.md to the authoritative divergence reference ahead
of retiring development/vimwiki-gap.md:
- drop the pointer into vimwiki-gap.md so the file stands alone
- reframe the intro as the single source of truth
- add an "Internal deferrals (non-parity)" section capturing the
  cold-path optimizations (RSS render_entry_body disk read,
  push_level_edit_for_line offset scan, diary neighbor scan) that
  otherwise only lived in the gap doc, so nothing is lost on deletion

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:27:00 +00:00
gffranco 38fed6dd9e docs: add known-issues.md gathering vimwiki divergences
CI / cargo fmt --check (push) Successful in 29s
CI / cargo clippy (push) Successful in 23s
CI / cargo test (push) Successful in 45s
CI / editor keymaps (push) Successful in 1m44s
Consolidate the deferred features and intentional divergences from the
parity log (development/vimwiki-gap.md) into a user-facing reference:
- Deferred: the markdown generated-content cluster
  (markdown heading generation, markdown_header_style, markdown_link_ext)
- By-design divergences grouped by area (highlighting/conceal -> LSP,
  syntax detection, config mechanism, auto_tags, mouse maps, list_margin
  negative + diary_caption_level -1 value semantics, Vim/Win shims)
- Default-location differences (html_path/template_path/diary_rel_path)
- Notes on the vars.vim compat shim and additive commands

Link it from the README "Migrating from vimwiki" section so it's
discoverable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:23:51 +00:00
gffranco 30cccd88bd fix(vars): resolve wiki by index in the vimwiki compat shim (R15)
CI / cargo fmt --check (push) Successful in 26s
CI / cargo clippy (push) Successful in 32s
CI / cargo test (push) Successful in 29s
CI / editor keymaps (push) Successful in 1m23s
`vimwiki#vars#get_wikilocal(key, N)` previously ignored the wiki-index
argument and always read the scalar `g:nuwiki_*` globals (the first
wiki), so third-party plugins (vimwiki-sync, vim-zettel) got the wrong
wiki's path/ext/syntax in a multi-wiki setup.

Now:
- an explicit numeric index selects that wiki from `g:nuwiki_wikis[N]`,
  falling back per-key to the scalar globals;
- with no index, the wiki owning the current buffer is resolved (matching
  upstream's `g:vimwiki_current_idx` behaviour);
- an out-of-range index clamps to the first wiki.

The single-wiki shorthand path is unchanged. Verified with a headless
Vim test (by-index, global fallback, clamp, no-arg, shorthand) and the
Vim keymap harness (301/18/21, 0 failed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:20:14 +00:00
gffranco 3b92b11948 fix(review): close all 2026-06-03 codebase-review findings (R1-R18)
CI / cargo fmt --check (push) Successful in 20s
CI / cargo clippy (push) Successful in 32s
CI / cargo test (push) Successful in 38s
CI / editor keymaps (push) Successful in 1m33s
Resolves the 18 findings from the parallel codebase review, tracked in
development/vimwiki-gap.md.

Correctness / perf:
- Wiki.config -> Arc<WikiConfig> so cloning a Wiki is a refcount bump (R5)
- WorkspaceIndex::remove is no longer O(n^2): a per-source contributions
  map limits the scan to buckets the source actually wrote into (R6)
- render_color now expands color_tag_template (__STYLE__/__CONTENT__),
  consuming the previously-dead field; ColorNode documented as an
  extension point; 3 renderer tests added (R3/R4)
- wiki_root_for returns empty/nil on no-match instead of falling back to
  the first wiki (R2); auto_header honours links_space_char (R7)

Cleanup / dedup:
- Remove dead #[allow(dead_code)] stubs + uncalled pub helpers, narrow
  imports (R10/R11)
- Dedup span_of_inline x3 -> InlineNode::span() (R12)
- diary_step single read lock; page_captions single pass (R13)
- Lua auto_header loop -> wiki_list(); detect_current_symbol cleanup
  (R14/R18)

Client / docs:
- :VimwikiNormalizeLink Vim cmds -> <q-args> (R17); ftplugin header fix
  (R16); vars.vim multi-wiki limitation documented (R15)
- Document 19 config options in README.md + doc/nuwiki.txt; fix
  list_margin/shiftwidth doc and stale comments (R1/R9)
- R8 investigated, confirmed not a real bug (documented)

Verified: Neovim harness 307, Vim harness 301/18/21, Rust suite 568, all
0 failed; clippy clean; fresh parallel-agent audit found no regressions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:13:55 +00:00
gffranco e319b4a935 docs(gap): record 2026-06-03 codebase-review findings (R1-R18)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 13:40:31 +00:00
gffranco e6e3f70dd2 feat(render): list_ignore_newline / text_ignore_newline = false → <br>
CI / cargo fmt --check (push) Failing after 22s
CI / cargo clippy (push) Successful in 22s
CI / cargo test (push) Successful in 36s
CI / editor keymaps (push) Successful in 1m26s
Implements the deferred half of these options: a soft line break inside a
paragraph / list item can render as <br /> instead of a space.

- Parser: soft breaks now emit a dedicated InlineNode::SoftBreak node
  (parse_inline_seq K::Newline + the list-continuation synthetic join) instead
  of collapsing to Text(" "). Added SoftBreakNode + the variant.
- All inline consumers treat SoftBreak as whitespace: AST visitor (no-op),
  text extraction (index.rs + lib.rs → space), nav/semantic_tokens span_of_inline,
  semantic emit (skip like Text), parser span_of_inline.
- Renderer: render_inlines_break renders top-level SoftBreaks as the
  context-specific string; render_paragraph uses text_ignore_newline,
  render_list_item uses list_ignore_newline; default render_inline → space.
  with_newline_handling builder; export.rs wires both from HtmlConfig.

Default (true/true = upstream default) behaviour is unchanged (space). Updated
3 core tests + 1 parser test that asserted the old Text(" ") shape to treat
SoftBreak as whitespace. New test render_page_html_ignore_newline_controls_soft_breaks.

Gap doc: P3 Config item closed — only the deferred markdown cluster remains.
Full rust suite + clippy clean; Neovim 307, Vim 301/18/21.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 13:06:38 +00:00
gffranco 1246c99c3c fix(config): address P3 config-batch audit findings
CI / cargo fmt --check (push) Failing after 19s
CI / cargo clippy (push) Successful in 21s
CI / cargo test (push) Successful in 34s
CI / editor keymaps (push) Successful in 1m41s
Parallel-agent audit of the config batch found:

- cycle_bullets used find_marker_span's third element as an indent column, but
  it's the ABSOLUTE byte offset after the marker — so depth (and the rotated
  glyph) was wrong for any item not near offset 0 (tests passed by coincidence).
  Fixed to use the marker span's column (the indentation). Regression test now
  places the list deep in the document.

- :VimwikiColorize interpolated the colour into the template via an unescaped
  replacement: Lua gsub treats `%` specially, Vim substitute() treats `&`/`\`.
  Lua now uses a function replacement (verbatim); Vim escapes `\&~`.

- render_swapped_table applied table_reduce_last_col before the column swap, so
  a swap involving the last column moved the narrow slot — now clamped after.

- Fixed a stale toc_link_format doc comment (format 1 = [[#anchor]], not a
  full parent path).

Verified-correct by the audit (no change needed): RSS rfc822/cdata/fidelity,
prune_orphan_html reverse-mapping + guards, write_escaped_allowing/match_allowed_tag
(multibyte-safe), substitute_emoji (byte-boundary-safe), resolve_target_uri
create_link/dir_link ordering, all config defaults + From/constructors.

Full rust suite + clippy clean; Neovim 307, Vim 301/18/21.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 12:48:25 +00:00
gffranco f5420bd1da docs(gap): close the P3 Config section + record divergences/deferrals
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 12:41:03 +00:00
gffranco a63d3dd7cf feat(config): P3 config batch — group 7 (user_htmls pruning)
allToHtml now prunes orphan HTML files (no corresponding wiki source) under
html_path — export_ops::prune_orphan_html walks the output tree, maps each
<rel>.html back to <root>/<rel>.<ext>, and deletes those with no source,
skipping the CSS file and any basename in user_htmls. Gated on
!html_filename_parameterization (slugified names can't be reverse-mapped),
mirroring upstream; the pruned paths are reported in the command result.

hl_headers / hl_cb_checked are NOT implemented as toggles: nuwiki already
highlights headers per-level (@vimwikiHeading.level1..6) and checkboxes
always-on via LSP semantic tokens, which supersedes the upstream opt-in
toggles (default off) — same class as the maxhi divergence. Documented in the
gap doc rather than degrading the existing highlighting.

Test: prune_orphan_html_deletes_sourceless_keeps_protected. Full rust suite +
clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 12:37:38 +00:00
gffranco 5cc47b0a42 test(rss): fix commands_coverage assertion for the new <rss xmlns:atom> tag
Follow-up to the RSS-fidelity change: the `<rss version="2.0">` substring now
carries the xmlns:atom attribute, so match the open-tag prefix instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 12:34:58 +00:00
gffranco 4a19f180f2 feat(config): P3 config batch — group 6 (RSS fidelity + rss_name/rss_max_items)
write_rss now emits upstream's full RSS 2.0 structure:
- xmlns:atom on <rss>; channel <link> points at the diary index page
  (base_url + diary_rel + diary_index + .html), not bare base_url.
- <atom:link rel="self"> to base_url + rss_name.
- channel + per-item <pubDate> (RFC-822, derived from the diary date;
  1970-01-01=Thu weekday math via to_days_epoch).
- per-item <guid isPermaLink="false"> holding the bare date.
- per-item <![CDATA[ rendered page body ]]> (render_entry_body reads+parses
  the entry and renders body-only with the wiki's colour/valid-tag/emoji opts;
  cdata_safe splits any literal ]]>).
- rss_name drives the output filename; rss_max_items caps the feed (0 =
  unlimited).

Tests: updated write_rss_uses_base_url_for_public_links for the new channel
link/guid/atom/pubDate; new write_rss_honours_rss_name_and_max_items. Full
rust suite + clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 12:34:32 +00:00
gffranco 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>
2026-06-03 12:30:38 +00:00
gffranco dcb5d89c0c feat(config): P3 config batch — group 3 (cycle_bullets)
cycle_bullets (default off): when an unordered list item changes indent level
(gll/glh), rotate its glyph through the configured bullet_types as a depth-keyed
ring buffer — change_level_edit gains cycle_bullets + bullet_types params,
locates the marker via find_marker_span, and rewrites the glyph to
bullet_types[new_depth % len] for single-char unordered markers. Ordered
markers are untouched. list_change_level reads both from the wiki config.

Tests: cycle_bullets_rotates_glyph_on_indent + cycle_bullets_off_leaves_glyph.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 12:22:42 +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 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>
2026-06-03 12:04:36 +00:00
gffranco 03005d0931 fix(insert): pumvisible() guard on smart_return/smart_shift_return (audit follow-up)
CI / cargo fmt --check (push) Successful in 23s
CI / cargo clippy (push) Successful in 22s
CI / cargo test (push) Successful in 28s
CI / editor keymaps (push) Successful in 1m27s
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>
2026-06-03 11:10:07 +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 305324c6e9 Merge remote-tracking branch 'origin/calendar-support' into feature-gap
CI / cargo fmt --check (push) Successful in 35s
CI / cargo clippy (push) Successful in 32s
CI / cargo test (push) Successful in 39s
CI / editor keymaps (push) Successful in 1m32s
# Conflicts:
#	development/vimwiki-gap.md
2026-06-03 01:46:07 +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