Commit Graph

83 Commits

Author SHA1 Message Date
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 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 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 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 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 9441fe918c fix(parity): close the 2026-06-02 re-audit config/command findings
CI / cargo fmt --check (push) Successful in 19s
CI / cargo clippy (push) Successful in 37s
CI / cargo test (push) Successful in 29s
CI / editor keymaps (push) Successful in 1m36s
Implements the remaining fourth-pass findings (gap doc updated):

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

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

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

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

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

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

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 10:50:38 +00:00
gffranco 79b502fa5c feat(html): html_header_numbering section numbering for HTML export
CI / cargo fmt --check (push) Successful in 51s
CI / cargo clippy (push) Successful in 27s
CI / cargo test (push) Successful in 49s
CI / editor keymaps (push) Successful in 2m52s
Mirror vimwiki's html_header_numbering / html_header_numbering_sym:
top-level headings at or below the start level get a dotted section
number (1, 1.1, 1.2, ...) with a configurable trailing symbol. Off by
default (level 0). Nested headings in lists/quotes stay unnumbered,
matching upstream's document-level-only scan.

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

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

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

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

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

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

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

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:16:03 +00:00
gffranco 724c12ac16 style: rustfmt the custom_wiki2html test assert (fixes red CI)
CI / cargo fmt --check (push) Successful in 42s
CI / cargo clippy (push) Successful in 38s
CI / cargo test (push) Successful in 36s
CI / editor keymaps (push) Successful in 1m26s
The custom_wiki2html test added in 23aec3e had an over-width `assert!`
that `cargo fmt` wants wrapped; CI's `cargo fmt --all -- --check` job has
been failing on it since. No behavior change — `cargo fmt --all` only.

Verified locally against the exact CI matrix: fmt --check clean, clippy
--workspace --all-targets -D warnings clean, test --workspace --all-targets
all pass, keymap + config harnesses pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 19:45:35 +00:00
gffranco 23aec3e6c7 feat(config): custom_wiki2html external converter + base_url for RSS (P2)
CI / cargo fmt --check (push) Failing after 16s
CI / cargo clippy (push) Successful in 32s
CI / cargo test (push) Successful in 48s
CI / editor keymaps (push) Successful in 1m39s
Add three per-wiki HtmlConfig keys mirroring vimwiki globals:

- custom_wiki2html / custom_wiki2html_args: when set, export shells out
  to the external converter via `sh -c` with vimwiki's exact arg order
  (<cmd> <force> <syntax> <ext> <out_dir> <in_file> <css> <tpl_path>
  <tpl_default> <tpl_ext> <root_path> <args>, `-` for empty optionals)
  instead of the built-in renderer.
- base_url: when set, diary RSS item + channel links become
  <base_url><diary_rel_path>/<date>.html instead of file:// URIs.

write_page() gains a `force` flag threaded through export_current (false),
export_all (its own flag) and the did_save auto-export path (false).

Tests: write_page_invokes_custom_wiki2html_converter,
write_rss_uses_base_url_for_public_links (html_export.rs), config
round-trip + defaults (index_and_config.rs). Docs: README, doc/nuwiki.txt,
lua config comment, vimwiki-gap.md item ticked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 19:06:42 +00:00
gffranco 09b5a2bd46 feat(config): on-save autoregen family — links/tags/diary-index (P2)
CI / cargo fmt --check (push) Successful in 17s
CI / cargo clippy (push) Successful in 38s
CI / cargo test (push) Successful in 41s
CI / editor keymaps (push) Successful in 1m25s
Added per-wiki auto_generate_links, auto_generate_tags, auto_diary_index
(default false, like upstream), wired into the did_save hook mirroring
auto_toc:

- auto_generate_links / auto_generate_tags rebuild the Generated Links /
  Generated Tags section ONLY when it already exists (new
  links_rebuild_edit / tag_links_rebuild_edit, like toc_rebuild_edit) — never
  inserts one into a page that lacks it.
- auto_diary_index regenerates the diary index page when a dated diary entry
  (not the index itself) is saved, via diary_generate_index_edit (handles the
  index file open / on-disk / absent).

auto_tags is recorded as an intentional divergence: nuwiki re-indexes tags on
every change, so the tag metadata is always fresh (no on-disk file to update).

Tests: links_rebuild_edit_only_acts_when_section_present,
tag_links_rebuild_edit_only_acts_when_index_present, config round-trip +
defaults. README/doc/lua comment updated. fmt/clippy clean; 0 Rust failures.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 18:55:51 +00:00
gffranco 3fd04b0efa fix(lsp): section-range termination is level-aware (caption audit follow-up)
CI / cargo fmt --check (push) Successful in 20s
CI / cargo clippy (push) Successful in 37s
CI / cargo test (push) Successful in 27s
CI / editor keymaps (push) Successful in 1m38s
The post-captions audit found find_section_range terminated a generated
section only at the next *level-1* heading. With a custom non-1
*_header_level (e.g. a level-2 Generated Tags index) a following same-level
section could be absorbed into the replaced span. Terminate at the next
heading of level <= the matched section's level instead, which keeps the
deeper `level+1` sub-groups inside while stopping at a sibling/parent.

Test: find_section_range_stops_at_same_level_sibling. 0 failures, clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 18:49:00 +00:00
gffranco 545367c3f6 feat(config): configurable generated-section captions (P2)
CI / cargo fmt --check (push) Successful in 32s
CI / cargo clippy (push) Successful in 24s
CI / cargo test (push) Successful in 31s
CI / editor keymaps (push) Successful in 1m40s
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>
2026-05-31 18:44:35 +00:00
gffranco 2d3db458fb feat(config): make listsym_rejected configurable (P2)
The rejected/cancelled checkbox glyph was a hardcoded `const REJECTED = '-'`.
ListSyms now carries a `rejected` field (new_with_rejected); a per-wiki
`listsym_rejected` key (default `-`) is added to WikiConfig, and
WikiConfig::list_syms() builds the palette with it. Routed the three
config-driven ListSyms construction sites (parse path in lib.rs + the
toggle/cycle commands) through list_syms(), so a custom rejected glyph both
lexes and round-trips.

Tests: listsyms::custom_rejected_glyph_is_honoured + config round-trip.
README/doc/lua config comment updated. fmt clean; 0 Rust test failures.

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

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

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

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:57:03 +00:00
gffranco b8586537f8 feat(diary): restore diary_start_week_day via configurable weekly naming
CI / cargo fmt --check (push) Successful in 29s
CI / cargo clippy (push) Successful in 34s
CI / cargo test (push) Successful in 31s
CI / editor keymaps (push) Successful in 1m34s
c63ec67 dropped diary_start_week_day, hardwiring the weekly diary to ISO
(Monday) weeks. Upstream vimwiki instead names a weekly note by the
week-start day's date (YYYY-MM-DD) and honours diary_start_week_day. Rather
than force one scheme, make it a per-wiki choice so migrators keep upstream
behaviour while existing nuwiki weekly files keep working:

- New per-wiki key `diary_weekly_style`: `iso` (default — `YYYY-Www`,
  Monday-based, nuwiki's original) or `date`/`vimwiki` (`YYYY-MM-DD` of the
  week-start day, upstream parity).
- Restored per-wiki key `diary_start_week_day` (`monday`..`sunday`, default
  monday); applies only in `date` mode.

Implementation:
- nuwiki-core::date gains WeeklyStyle, WeekStart, and DiaryCalendar (owns
  today/next/prev — date-mode snaps to the week-start and steps ±7 days;
  iso/daily/monthly/yearly defer to the existing DiaryPeriod logic).
- WikiConfig gains the two fields (+ defaults, RawWiki, From) and a
  diary_calendar() builder; commands.rs diary_open_relative and the
  next/prev pivot use it.

Defaults preserve current behaviour (iso/monday), so no breaking change.
Tests: DiaryCalendar cases in nuwiki-core/tests/diary.rs (snap, ±7, sunday
start, iso delegation, daily) + config round-trip in
nuwiki-lsp/tests/index_and_config.rs. README + doc/nuwiki.txt + lua config
comment updated. fmt + clippy clean; all crate tests + config-parity green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:06:09 +00:00
gffranco 28d5caf581 fix(diary): default diary_caption_level to 0 (upstream parity)
nuwiki defaulted the per-wiki diary_caption_level to 1; upstream vimwiki's
default is 0 (year captions at the top level, months one below, rather than
nested one deeper). Default it to 0 in wiki_defaults(); still per-wiki
overridable. Render tests pass an explicit level so are unaffected; the
default-value assertion in defaults_carry_vimwiki_per_wiki_keys updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 16:50:59 +00:00
gffranco a53ba167d6 fix(lsp): silence clippy too_many_arguments on render_page_html
CI / cargo fmt --check (push) Successful in 17s
CI / cargo clippy (push) Successful in 33s
CI / cargo test (push) Successful in 33s
CI / editor keymaps (push) Successful in 1m34s
Adding list_margin pushed render_page_html to 8 params, tripping
clippy::too_many_arguments under -D warnings in CI. Every parameter is a
distinct render input and the function has a single production caller, so
scope an #[allow] rather than introduce an options-struct abstraction.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 08:13:30 -03:00
gffranco 3a33d53c22 feat(lsp): drive checkbox commands from the wiki listsyms palette
Parse editor and export documents with each wiki's configured listsyms,
and make toggle/cycle/reject plus parent-propagation walk the real
palette glyphs instead of the hardcoded ' .oOX'. Falls back to the
default palette when no wiki matches the URI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 23:32:15 -03:00
gffranco 85094d6e3b feat(core): make checkbox lexing honor a configurable listsyms palette
Add a ListSyms type (vimwiki's g:vimwiki_listsyms) and thread it through
the lexer so checkbox glyphs are recognized from the configured palette
rather than the hardcoded ' .oOX'. Glyphs map to the existing five-bucket
CheckboxState, so the HTML renderer and AST consumers are unchanged.
VimwikiSyntax::parse_with_listsyms opts into a custom palette; the trait
parse() keeps the default.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 23:32:07 -03:00
gffranco c63ec679ae feat(lsp): wire diary/auto_toc/links_space_char/list_margin; drop client-side keys
Consume several per-wiki config keys that the server deserialized but
ignored, and remove keys whose effect is purely client-side:

- diagnostics: re-publish open-doc diagnostics on
  didChangeConfiguration so a link_severity change takes effect
  immediately; fix the single-key unwrap in apply_change so a minimal
  `{ diagnostic: {...} }` payload isn't mistaken for a namespace wrapper.
- auto_toc: rebuild an existing TOC section on save (new
  ops::toc_rebuild_edit, no-op when the page has no TOC).
- diary index: honour diary_header, diary_sort and diary_caption_level
  when rendering the diary index body.
- links_space_char: apply on rename so spaces in the link target and
  the on-disk path become the configured glyph (default " " = verbatim).
- list_margin: thread the per-wiki value into render_page_html.
- remove nested_syntaxes, maxhi and diary_start_week_day from the server
  config: nested-syntax and heading highlighting are client-side, and
  the weekly diary is ISO-week based so a custom week start has no clean
  server-side meaning.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 23:12:08 -03:00
gffranco 0741c349db feat(core): support configurable list_margin in HTML list rendering
Add `HtmlRenderer::with_list_margin`. When the margin is >= 0 the
outermost list gets an inline `margin-left:<n>em`; nested lists and the
default of -1 stay unstyled (deferring to the stylesheet). Wires the
per-wiki vimwiki `list_margin` key into the export pipeline.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 23:11:56 -03:00
gffranco 9b6413c3de feat(lsp): wire diagnostic.link_severity through from client config
The broken-link diagnostic severity was already consulted by
collect_diagnostics, but Config.diagnostic was hardcoded to the default and
never populated from initializationOptions/didChangeConfiguration. Parse a
client-supplied `diagnostic.link_severity` ('off'|'hint'|'warn'|'error',
case-insensitive) into LinkSeverity and apply it in both from_init_params and
apply_change. Partial config updates that omit `diagnostic` preserve the
existing severity rather than resetting it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 21:53:46 -03:00
gffranco b922f0d612 test(config): verify Vim/Neovim config payload parity
CI / cargo fmt --check (push) Successful in 15s
CI / cargo clippy (push) Successful in 27s
CI / cargo test (push) Successful in 30s
CI / editor keymaps (push) Successful in 1m24s
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>
2026-05-30 19:24:20 -03:00
gffranco 47af0d6c1e docs(config): add configuration reference tables and fix links_space_char default
Document every config key (top-level, mappings, per-wiki, HTML export, and
g:nuwiki_* globals) with types, defaults, and accepted values in the README
Configuration section. Correct the links_space_char doc comment: the default
is a literal space (spaces kept verbatim), not "_". Note that
diagnostic.link_severity is accepted but not yet wired through to the server.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 19:24:08 -03:00
gffranco 8d8d85daf9 feat(lsp): add list.removeCheckbox and link.catUrl commands
removeCheckbox strips the `[ ]` marker (plus its trailing space) from
the current item or every item in the list. catUrl returns the
`file://` URL of the current page's HTML export, mirroring vimwiki's
:VimwikiCatUrl.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 17:32:41 -03:00
gffranco 8ab6015405 Major clean up and improvements to vimwiki compatibility and documentation.
CI / cargo fmt --check (push) Successful in 33s
CI / cargo clippy (push) Successful in 23s
CI / cargo test (push) Successful in 33s
CI / editor keymaps (push) Successful in 1m25s
Reviewed-on: #1
2026-05-30 18:35:40 +00:00
gffranco fa2d1b8b42 feat(keywords): add STOPPED keyword
CI / cargo fmt --check (push) Successful in 26s
CI / cargo clippy (push) Successful in 19s
CI / cargo test (push) Successful in 31s
CI / editor keymaps (push) Successful in 1m18s
Adds STOPPED alongside TODO/DONE/STARTED/FIXME/FIXED/XXX across the stack:
lexer, AST Keyword enum, HTML renderer (class="stopped"), LSP keyword_str,
and the Vim syntax red group (nuwikiKeywordAttn). Grouped with the
attention/pending keywords (red) for both export and in-editor highlighting.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 22:05:23 -03:00
gffranco e0f97a5caf fix(export): emit one CSS class per keyword for independent colouring
CI / cargo fmt --check (push) Successful in 22s
CI / cargo clippy (push) Successful in 39s
CI / cargo test (push) Successful in 30s
CI / editor keymaps (push) Successful in 1m17s
All keywords previously shared `class="todo"`, so a stylesheet couldn't
distinguish e.g. red TODO from green DONE. Emit a distinct class per keyword
(todo/done/started/fixme/fixed/xxx); TODO keeps the vimwiki `todo` class so
stock vimwiki CSS still styles it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 21:43:11 -03:00
gffranco e90bbab39e fix(export): render vimwiki-compatible HTML for templates, links, and tasks
Stock vimwiki templates and stylesheets rendered broken pages because the
HTML output diverged from vimwiki conventions on three fronts:

- Templates: the renderer only substituted nuwiki's `{{key}}` placeholders,
  so vimwiki's `%title%`/`%content%`/`%root_path%`/`%date%`/`%wiki_css%`
  passed through literally — dropping the body and breaking asset links.
  Both delimiter styles are now recognised; `%wiki_css%` aliases the css var.
- Links: `[[todo.wiki]]` exported to `todo.wiki.html`. render_page_html now
  takes the wiki file extension and strips it from wiki/interwiki targets
  (via index::strip_wiki_extension) before the `.html` URL is built, matching
  in-editor navigation. file:/local: links keep their literal extension.
- Tasks: checkbox items used bespoke `task-*` classes plus an `<input>`,
  which double-rendered against vimwiki stylesheets. Emit `done0..done4`
  (`[ ] [.] [o] [O] [X]`) and `rejected` (`[-]`) classes with no input — the
  stylesheet draws the box.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 21:19:55 -03:00
gffranco 66964be393 chore(fmt): apply cargo fmt to recent LSP changes
CI / cargo fmt --check (push) Successful in 11s
CI / cargo clippy (push) Successful in 14s
CI / cargo test (push) Successful in 21s
CI / editor keymaps (push) Successful in 1m10s
Pure rustfmt churn — the anchor-match, source-relative resolution,
and config-unwrap commits introduced lines that needed rustfmt
reformatting. CI's `cargo fmt --check` job was blocking on this.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 23:34:31 -03:00
gffranco e5b0042a90 fix(lsp): refresh diagnostics after initial workspace scan completes
`didOpen` for the wiki's index page fires almost immediately after
`initialized`, but the background `index_workspace` task hasn't yet
parsed the other pages. Link-health diagnostics computed at that
point look up every cross-page link target in a near-empty index and
flag them all as missing-page — and the diagnostics are never
recomputed once the scan catches up, so the editor shows stale red
squiggles on every link until the buffer is edited.

After each wiki's initial scan finishes, walk every open document
that lives in that wiki, recompute its diagnostics against the now-
populated index, and re-publish. Snapshots both the URI list and
each doc's `(ast, text, version)` so we don't hold DashMap iterators
across awaits.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 22:47:46 -03:00
gffranco f477f6e6a7 fix(lsp): resolve wikilinks source-relative first, with .. collapsing
`[[llm-wiki-pattern]]` in `tips/index.wiki` should resolve to
`tips/llm-wiki-pattern.wiki` — vimwiki's default is source-relative
for non-absolute targets. The index keyed every page by its
workspace-relative path, so the link looked up `llm-wiki-pattern`
(root-relative) and missed the sibling. Goto-definition then
synthesised a non-existent root URL, and `nuwiki.link` diagnostics
flagged every such link as missing-page.

  - `WorkspaceIndex::resolve_wiki_path` and `page_for_wiki_target`
    centralise the lookup: try `{source_dir}/{path}` first, fall back
    to root-relative. Used by goto-definition, diagnostics, and the
    workspace `checkLinks` walker.
  - `collapse_dots` resolves `.` / `..` segments before lookup so
    `[[../Other]]` from `posts/foo` correctly hits `Other` at the
    wiki root (and is reported broken if no such page exists, rather
    than silently going to nowhere).
  - `canonical_link_name` applies the same rule when keying the
    backlinks index, so backlinks queried by the resolved page name
    pick up references that were written source-relative.
  - `OutgoingLink` carries `is_absolute` now so `classify_outgoing`
    (driven from cached index data, not the live AST) gets the same
    treatment without re-parsing the source.
  - `classify_outgoing`'s File/Local branch now reuses
    `resolve_file_path` instead of duplicating the `//absolute` /
    relative-to-source logic inline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 22:30:32 -03:00
gffranco 859d69e4fe fix(lsp): match wikilink anchors against raw heading text
`[[Page#Heading text]]` parsed the anchor as the literal string after
`#`, but the index stored each heading's anchor as `slugify(title)`.
The two never compared equal, so every TOC-style anchor link
(`[[#1. Topologia atual]]`, etc.) was reported as a broken anchor and
goto-definition couldn't jump to the right heading either.

Slugify the request before comparing — `slugify` is idempotent on
valid-slug input, so the same code path now accepts both
`[[Page#some-heading]]` (slug form) and `[[Page#Some Heading]]`
(raw text). Applied to diagnostics, navigation, and hover preview so
all three agree on what "an anchor matches a heading" means.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 22:29:30 -03:00
gffranco 2aec51274e fix(lsp): resolve wikilinks that include the .wiki file extension
`[[page.wiki]]` should resolve identically to `[[page]]`. The index
keyed by stem, so links with the explicit extension fell through to
the broken-link diagnostic and to-page navigation failed. Strip the
configured extension before every page lookup (resolve, definition,
backlinks, classify_link, classify_outgoing) and stop appending the
extension in synthesise_page_uri when it's already present.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 22:00:03 -03:00
gffranco 6ae642dbee fix(config): unwrap {nuwiki:{...}} wrapper in apply_change
CI / cargo fmt --check (push) Failing after 22s
CI / cargo clippy (push) Successful in 21s
CI / cargo test (push) Successful in 29s
CI / editor keymaps (push) Successful in 1m19s
workspace/didChangeConfiguration settings from Neovim arrive as
{ "nuwiki": { "wiki_root": ..., "wikis": [...] } } because
server_settings() in lua/nuwiki/lsp.lua wraps the payload in a
"nuwiki" namespace key.  apply_change() was trying to deserialise that
outer object directly as InitOptions, which always succeeded but produced
all-None fields (unknown keys are ignored by serde), so every settings
refresh was silently dropped.

Unwrap single-key objects whose value is also an object before
deserialising — this handles the Neovim wrapper while keeping the flat
VimL shape working unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 23:24:51 -03:00
gffranco 02172d9e25 fix(config): accept integer 0/1 for bool fields in RawWiki deserialization
CI / cargo fmt --check (push) Successful in 31s
CI / cargo clippy (push) Successful in 39s
CI / cargo test (push) Successful in 36s
CI / editor keymaps (push) Successful in 1m25s
VimL dicts serialise boolean-like settings such as `auto_export = 1`
as the JSON number `1`, not `true`.  serde's default `Option<bool>`
deserializer rejects that, causing `serde_json::from_value::<InitOptions>`
to return `Err` and `.ok()` to silently discard the entire wikis list.
The server then fell back to `wiki_root` and could not resolve per-wiki
links, marking every cross-wiki link as broken.

Add an `opt_bool_or_int` serde helper that accepts JSON bool, `null`,
or integers (0 = false, non-zero = true), and apply it to `auto_export`,
`html_filename_parameterization`, `listsyms_propagate`, and `auto_toc`
in `RawWiki`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 23:03:36 -03:00
gffranco 3ef70e4b7c test(lsp): update find_section_range test for any-level heading match
CI / cargo fmt --check (push) Successful in 56s
CI / cargo clippy (push) Successful in 1m5s
CI / cargo test (push) Successful in 1m2s
CI / editor keymaps (push) Successful in 2m4s
The prior commit (e849ac9) intentionally removed the h1-only
restriction from find_section_range so VimwikiGenerateTagLinks stays
idempotent under non-h1 tag headings. The accompanying test still
asserted the old h1-only behavior and now fails.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 19:34:01 +00:00
gffranco ab6b5f6d73 style(lsp): apply rustfmt to commands.rs
CI / cargo fmt --check (push) Successful in 22s
CI / cargo clippy (push) Successful in 24s
CI / cargo test (push) Failing after 31s
CI / editor keymaps (push) Has been skipped
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 19:27:22 +00:00
gffranco e849ac9d1f Fix duplicate tag links for VimwikiGenerateTagLinks by extending section range detection and allowing any heading level
Release / build aarch64-unknown-linux-gnu (push) Failing after 32s
Release / build aarch64-unknown-linux-musl (push) Failing after 16m23s
Release / build x86_64-unknown-linux-gnu (push) Failing after 55s
Release / build x86_64-unknown-linux-musl (push) Failing after 55s
Release / gitea release (push) Has been skipped
CI / cargo fmt --check (push) Failing after 37s
CI / cargo clippy (push) Successful in 26s
CI / cargo test (push) Failing after 33s
CI / editor keymaps (push) Has been skipped
2026-05-14 16:11:29 -03:00