9de8543385a4062a10d787a2ef193c3e790ad451
137 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
769580af75 |
chore(scripts): add test-personal-wiki.sh + NUWIKI_DEV_NO_SEED
test-personal-wiki.sh wraps start-vim.sh to open the user's real wiki at ~/.vimwiki/personal_wiki (override with NUWIKI_PERSONAL_WIKI) — used when reproducing user-reported bugs against actual content instead of the seeded smoke-test wiki. Also adds a NUWIKI_DEV_NO_SEED env var to start-vim.sh so seed_wiki doesn't drop a scratch Notes.wiki into the user's real notes when we point WIKI_DIR at an already-populated wiki. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
c66431cde3 |
chore(scripts): add syntax-diag helper for debugging highlight issues
Drop-in script that dumps the syntax/highlight state of the current buffer to /tmp/nuwiki-syndiag.log: filetype, b:current_syntax, every syntax/vimwiki.vim found in &runtimepath (to spot duplicates from other plugins), the resolved attributes of our highlight groups + the colorscheme groups they link to, a per-segment synID walk over the buffer, and the filtered scriptnames list. Useful when a user reports broken highlighting and we need to know whether the patterns aren't matching, the colorscheme is the culprit, or another plugin's syntax/vimwiki.vim is winning the runtimepath race. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
04cbe67882 |
fix(syntax): per-level heading groups so colorschemes differentiate H1-H6
The single `nuwikiHeading` group linked all six levels to `Title`. Many popular colorschemes (codedark, gruvbox-light, etc.) define `Title` as bold-only with no foreground colour, so every heading rendered as bold text in the Normal colour — H1 and H3 were visually identical. Split into nuwikiHeading1..6 and link each to a different accent (Title / Function / Identifier / Type / Constant / PreProc), matching the per-level Tree-sitter mapping the Neovim semantic-token side already uses. The patterns are mutually exclusive: each requires whitespace immediately after the equals run, so `=` won't match `==`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
cf48242542 |
fix(syntax): target colorscheme-stable groups for inline markup
Two undefined targets meant bold/italic rendered as plain text:
- Neovim semantic-token defaults linked @vimwikiBold/Italic to
markdownBold/Italic, which only exist when the markdown treesitter
parser is loaded — never in a .wiki buffer. Use @markup.strong /
@markup.italic / @markup.raw.inline / @markup.link instead; those
are defined by every nvim 0.9+ colorscheme.
- The static fallback linked nuwikiBold/Italic to Bold/Italic groups
that exist in Neovim but not plain Vim, so on Vim the links
resolved to nothing. Define them with explicit gui=bold/italic
attributes so they render correctly everywhere.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
8f8c2884a9 |
feat(vim): conceal markup delimiters when conceallevel=2
Set conceallevel=2 and concealcursor=nc on .wiki buffers and add contained `conceal` matches for the bold/italic/code delimiters and wikilink brackets/targets. The static-fallback rendering now mirrors what the Neovim semantic-token path produced: *bold* shows as bold without the asterisks, [[target|desc]] shows just "desc", etc. The wikilink region uses an inline `contains=` (no line continuation) because some Vim builds (notably Homebrew Vim 9.2) raise E10 on the leading `\\ contains=...` form even though the surrounding region parses fine. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
6ae642dbee |
fix(config): unwrap {nuwiki:{...}} wrapper in apply_change
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>
|
||
|
|
02172d9e25 |
fix(config): accept integer 0/1 for bool fields in RawWiki deserialization
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> |
||
|
|
8d11f7daef |
fix(lsp): send g:nuwiki_wikis to the server so per-wiki roots are known
The server received only wiki_root (the parent directory) and had no
knowledge of the per-wiki sub-roots configured in g:nuwiki_wikis / the
setup() wikis list. It therefore resolved all links relative to the
parent root, causing every link in a sub-wiki to appear broken.
Vim path (autoload/nuwiki/lsp.vim):
s:settings() now includes a 'wikis' key when g:nuwiki_wikis is set,
so the initialization_options and settings payloads carry the full
per-wiki config (root, diary_rel_path, file_extension, …).
Lua path (lua/nuwiki/lsp.lua):
Add resolved_opts() which merges vim.g.nuwiki_wikis into
config.options.wikis when the user configures via VimL rather than
setup({wikis=…}). init_options(), server_settings(), and the
pre-0.11 root_dir_for() fallback all use resolved_opts() so the
server receives the correct per-wiki roots in every code path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
b3e2a72023 |
fix(lsp): add coc.nvim dispatch path to all Vim-side LSP calls
Commands were hardwired to vim-lsp (lsp#send_request, :LspDefinition,
:LspReferences, :LspRename). Users running coc.nvim got "vim-lsp not
loaded" on every command despite the plugin correctly detecting coc.
Changes:
autoload/nuwiki/commands.vim
- Add s:has_coc() (checks CocActionAsync exists)
- Add s:coc_wrap() adapter — converts coc's (err, result) callback into
the vim-lsp notification shape {response:{result:…}} so all existing
on_notification handlers work unchanged
- s:exec(): try vim-lsp first, fall back to CocActionAsync('runCommand',
…) with arguments spread as positional params, then error if neither
- Add s:jump_definition() helper — :LspDefinition vs CocActionAsync
- Add nuwiki#commands#backlinks() — :LspReferences vs CocActionAsync
- badd_link(): coc path uses CocAction('getDefinition') to resolve the
target URI without navigating
- follow_link_or_create(): replace inline :LspDefinition checks with
s:jump_definition()
- rename_file(): :LspRename vs CocActionAsync('rename')
ftplugin/vimwiki.vim
- VimwikiFollowLink / NuwikiFollowLink: dispatch through
nuwiki#commands#follow_link_or_create() instead of :LspDefinition
- VimwikiBacklinks / NuwikiBacklinks / VWB: dispatch through
nuwiki#commands#backlinks() instead of :LspReferences
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
b7d2a6c61a |
fix(install): resolve plugin root at source time to fix NuwikiInstall E484
<sfile> inside a command! body is evaluated at execution time, not at
definition time. When :NuwikiInstall is run interactively there is no
sourcing context, so <sfile> expands to nothing and the path collapses
to ./scripts/download_bin.vim — producing E484.
Fix: capture the path in s:plugin_root immediately while the script is
being sourced, then reference that variable from the command body.
Also hoist :NuwikiInstall above the early `finish` for Neovim so the
command is available in both editors (Neovim routes to
require('nuwiki.install').install(), Vim sources the download script).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
2c0cefb5c5 |
fix(mappings): respect g:nuwiki_wikis in global entry-point helpers
The global <Leader>ww / diary helpers read g:nuwiki_wiki_root directly, so they always opened the root-level index.wiki even when the user had configured per-wiki roots via g:nuwiki_wikis (e.g. personal_wiki.root = '~/.vimwiki/personal_wiki'). Vim path (autoload): replace the three open_*_path functions with a shared s:wiki_cfg(n) helper that checks g:nuwiki_wikis[n] first, then falls back to the scalar g:nuwiki_* vars and built-in defaults. Lua path (init.lua): replace the separate _wiki_index_path /_diary_path locals with a unified _wiki_cfg() that checks setup() opts.wikis, then vim.g.nuwiki_wikis (for users who configure via VimL rather than setup()), then scalar opts / g: vars. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
ba5c0002ab |
fix(compat): add vimwiki#vars shim for vimwiki-sync and vim-zettel
Third-party plugins such as vimwiki-sync and vim-zettel call
vimwiki#vars#get_wikilocal() — a function only provided by the original
vimwiki plugin. Without it, the after/ftplugin loaded by vimwiki-sync
errors on every wiki buffer open:
E117: Unknown function: vimwiki#vars#get_wikilocal
E121: Undefined variable: g:zettel_dir
Add autoload/vimwiki/vars.vim with lightweight stubs for the two keys
vimwiki-sync uses ('path', 'is_temporary_wiki'), reading values from
nuwiki's own g:nuwiki_wiki_root / g:nuwiki_file_extension config so
users don't have to duplicate settings. get_global() is stubbed as a
no-op for completeness.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
9354e1c176 |
fix(mappings): add global entry-point keymaps and correct <Leader>ww/<Leader>wt targets
Two bugs prevented keymaps from working after a Dein install: 1. <Leader>ww and <Leader>wt both called diary_today() instead of wiki_index() / wiki_tab_index(). Fixed in keymaps.lua (Neovim) and ftplugin/vimwiki.vim (Vim). 2. All keymaps were buffer-local (<buffer> / buffer=bufnr), so they only activated inside an already-open .wiki file. Users had no way to reach the wiki from any other buffer, making the plugin appear broken on a fresh Vim start. Fix: register the eight <Leader>w* entry-point mappings globally — in setup() for Neovim (lua/nuwiki/init.lua) and in plugin/nuwiki.vim for plain Vim. To avoid a chicken-and-egg LSP dependency, the global mappings open files directly from config (wiki_root, diary_rel_path, file_extension); the LSP auto-starts via the FileType autocmd once the vimwiki buffer loads. Three new autoload helpers (open_wiki_path, open_diary_path, open_diary_index_path) provide the LSP-free path for the Vim side. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
a8b89a5303 |
fix(vim): correct broken symlink, missing commands, and bad VimwikiGoBackLink
- README: fix plain-Vim install symlink (ln -s target/… → ln -s ../target/… so the relative path resolves correctly from inside bin/) - ftplugin: add missing VimwikiUISelect command on the Vim path - ftplugin: add missing -count attribute on NuwikiTabIndex (Vim path) - ftplugin: fix VimwikiGoBackLink (Neovim path) — `normal!` with no argument causes E471; use `execute "normal! \<C-o>"` instead Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
8cff0c2d68 |
ci(release): add libc6-dev-arm64-cross for aarch64-gnu builds
CI / cargo fmt --check (push) Successful in 29s
CI / cargo clippy (push) Successful in 22s
CI / cargo test (push) Successful in 35s
CI / editor keymaps (push) Successful in 2m4s
Release / build x86_64-unknown-linux-gnu (push) Successful in 34s
Release / build aarch64-unknown-linux-musl (push) Successful in 55s
Release / build aarch64-unknown-linux-gnu (push) Successful in 1m50s
Release / build x86_64-unknown-linux-musl (push) Successful in 47s
Release / gitea release (push) Successful in 37s
gcc-aarch64-linux-gnu ships the cross compiler and binutils only; linking glibc binaries also requires the target libc crt/dev files (Scrt1.o, crti.o), which live in libc6-dev-arm64-cross. Without it, the aarch64-unknown-linux-gnu build failed with: ld: cannot find Scrt1.o: No such file or directory ld: cannot find crti.o: No such file or directory Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
f2fd7d6376 |
ci(release): pin upload/download-artifact to v3 for Gitea Actions
CI / cargo fmt --check (push) Successful in 22s
CI / cargo clippy (push) Successful in 19s
CI / cargo test (push) Successful in 31s
Release / build x86_64-unknown-linux-gnu (push) Successful in 1m34s
Release / build aarch64-unknown-linux-musl (push) Successful in 55s
Release / build aarch64-unknown-linux-gnu (push) Failing after 57s
Release / build x86_64-unknown-linux-musl (push) Successful in 1m16s
Release / gitea release (push) Has been skipped
CI / editor keymaps (push) Successful in 1m24s
actions/upload-artifact@v4 and download-artifact@v4 require the GitHub-hosted artifact backend, which Gitea Actions does not implement (GHESNotSupportedError on v2.0.0+). Downgrade to v3. v3's download-artifact has no merge-multiple flag and nests each artifact under artifacts/<artifact-name>/, so the upload loop now recurses to find the archives. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
82ff454e0f |
ci(release): drop cross, use rustup targets + native linkers
CI / cargo fmt --check (push) Successful in 22s
CI / cargo clippy (push) Successful in 23s
CI / cargo test (push) Failing after 16m25s
Release / build x86_64-unknown-linux-gnu (push) Failing after 56s
Release / build aarch64-unknown-linux-musl (push) Failing after 56s
Release / build aarch64-unknown-linux-gnu (push) Failing after 1m43s
Release / build x86_64-unknown-linux-musl (push) Failing after 1m31s
Release / gitea release (push) Has been skipped
CI / editor keymaps (push) Has been cancelled
cross spawns Docker containers per target, but the Gitea Actions
runner doesn't expose /var/run/docker.sock, so every cross-compile
step died with "Cannot connect to the Docker daemon".
Replace with rustup-installed targets plus per-target linker setup:
- x86_64-gnu: native (no extra deps)
- aarch64-gnu: gcc-aarch64-linux-gnu from apt
- x86_64-musl: musl-tools from apt
- aarch64-musl: rust-lld + link-self-contained (rust-std bundles
musl libc.a + crt, no apt deps needed)
Verified aarch64-musl path locally: produces a statically linked
ARM aarch64 ELF.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
3ef70e4b7c |
test(lsp): update find_section_range test for any-level heading match
The prior commit (
|
||
|
|
ab6b5f6d73 |
style(lsp): apply rustfmt to commands.rs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
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
|
||
|
|
8fa85988d8 |
style(lists): apply rustfmt to checkbox propagation
CI's cargo fmt --check flagged a few lines from the propagation patch that exceeded the wrapping threshold. No behavioural change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
7a0cec4920 |
fix(lists): skip own indent in smart_return when auto-indent is active
nvim defaults autoindent=on, so the indent inserted by Vim/Nvim after the <CR> we return was being doubled by our own indent prefix — pressing Enter on a sub-item produced a deeper-nested item instead of a same-level one. Detect any auto-indent mechanism (autoindent, smartindent, cindent, indentexpr) and let it own the indentation; otherwise add it ourselves so vim's noautoindent default still works. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
bcb32777fb |
chore(dev): always rebuild release binary in start scripts
ensure_binary used to short-circuit whenever bin/nuwiki-ls existed, which left vim/nvim running an outdated LSP after every source change. Now always invoke cargo build (incremental, so a no-op when nothing changed) and refresh the symlink + log the build timestamp. Add NUWIKI_DEV_SKIP_BUILD=1 for the rare opt-out. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
801896926d |
fix(lists): propagate checkbox state to ancestor list items on toggle
Toggling/cycling/rejecting a nested checkbox now recomputes each ancestor's progress marker (vimwiki's listsyms_propagate). Mirrors vimwiki's averaging — rejected items count as 100% unless every child is rejected, in which case the parent itself becomes rejected. Walks up while each ancestor has its own checkbox. Also tightens find_checkbox_span to scan only the marker line, since a parent item's span covers its nested sublist and was matching child markers as if they belonged to the parent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
695702555f |
fix(tables/lua): switch smart_tab/return to <Cmd>, drop vim.schedule
The keymap harness caught a regression in
|
||
|
|
f4e086f981 |
refactor(tests): group test files by feature, drop phase/cluster naming
Restructures the integration test layout so each file is named after
what it covers, not the implementation phase it landed in.
nuwiki-core (renames only):
vimwiki_lexer → lexer
vimwiki_parser → parser
vimwiki_tags → tags
vimwiki_table_alignment → table_alignment
diary_period → diary
list_continuation → lists
transclusion_attrs → transclusion
+ table colspan/rowspan tests moved here from parity_cluster_1
nuwiki-lsp (renames + merges + one split):
cluster_a_list_rewriters → commands_lists
cluster_b_table_rewriters → commands_tables
cluster_c_link_helpers +
phase19_followlink_creates → commands_links
phase13_rename_commands → commands_files
phase17_colorize → commands_colorize
phase17_html_export → html_export
phase15_link_health → link_health
phase18_multi_wiki → multi_wiki
phase19_folding → folding
nav → navigation
lsp_helpers → helpers
phase16_diary +
diary_frequency → diary
phase11_plumbing +
parity_cluster_1 (config) → index_and_config
tags_index_and_lsp +
phase17_backfill → commands_tags
phase14_edit_commands → split into
commands_checkboxes,
commands_headings,
commands_tasks
Net: 30 → 28 integration-test files. 456 → 455 tests (the one
removed test was a dummy `paragraph_render_is_unchanged` whose only
purpose was to keep a `ParagraphNode` import alive in
parity_cluster_1; the import is exercised elsewhere now).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
5b6f789c8d |
fix(tables): auto-realign on edit + stop dragging trailing | onto new row
Two bugs in the insert-mode table editing path: 1. <Tab> past the last cell (and <CR> on a table row) used <CR>+typed keystrokes to create a new row, which split the current line at the cursor — pulling the trailing | down onto the next line and mangling the formatting. Both paths now go through helpers that append() a fresh row beside the current one without touching it. 2. The table never realigned to new content. Ported the LSP-side render_aligned_table algorithm to Lua + VimL so smart_tab, smart_shift_tab, and smart_return tighten column widths locally on every navigation. No vim-lsp / nuwiki server roundtrip required. Neovim side schedules the work via vim.schedule (textlock-safe); plain Vim hands off via <Cmd>:call …<CR> to keep insert mode and avoid the cmdline-mode flash. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
37af0803d8 |
docs: rewrite README + :help nuwiki for users
Both files now describe what the plugin DOES, with no references to
internal phase work or SPEC.md (which is dev-only).
README.md
* Reorganised the feature list by area (syntax, editor intelligence,
editing, diary, other) and surfaced everything actually shipped:
text objects, smart `<CR>` / `<Tab>` in insert, table alignment
markers, colspan/rowspan, transclusion attributes, diary
frequencies, list continuation, etc.
* Updated the keymaps table to include the full insert-mode bindings,
list-rewriter shortcuts (`gLh`/`gLl`, `glr`/`gLr`, `gl<Space>`),
and all five text-object pairs (was "ah/ih + planned follow-ups").
* Expanded the configuration example with the per-wiki keys (diary,
HTML export, listsyms, nested_syntaxes) and the new Vim globals
(`g:nuwiki_no_folding`, `g:nuwiki_mouse_mappings`).
* Dropped the architecture / repository-layout / phase-log sections.
Contributors who care about those still find them in the codebase.
* Removed the "two known behavior deltas" note — the gln/glp claim
is no longer accurate (both bindings ship as separate keymaps),
and the lazy-index caveat moved into the Migrating section.
doc/nuwiki.txt
* Grew from 7 sections to 14 covering installation, configuration
(top-level + per-wiki + Vim globals), commands, keymaps (by area),
text objects, insert-mode bindings, diary (with frequency formats),
tables (with alignment / span syntax), HTML export, folding, health
checks, and migrating from vimwiki.
* Every public command has a help anchor.
* Removed the §6.9 spec reference and the phase 9 caveat.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
ae96562969 |
parity(vim): port text objects + folding, fix smart_return textlock
Close the remaining Vim-vs-Neovim functional gaps:
* Text objects — new `autoload/nuwiki/textobjects.vim` mirroring
`lua/nuwiki/textobjects.lua`. All five pairs (ah/ih, aH/iH,
al/il, a\/i\, ac/ic) wired in the Vim path of `ftplugin/vimwiki.vim`
via the classic `:<C-u>call` idiom that works cleanly in both
operator-pending and visual modes.
* Folding — new `autoload/nuwiki/folding.vim` providing a regex
`foldexpr` over headings, plus a tidy `foldtext`. Wired in the
Vim path; opts out via `let g:nuwiki_no_folding = 1`.
* `smart_return` was using `setline()` / `append()` inside an
`<expr>` callback — fine on Neovim but plain Vim's stricter
textlock raised E565. Rewrote as pure keystrokes (matches the
Lua version): table rows insert via `<CR>...<Esc>0li`, empty
list lines break via `<Esc>0DA<CR>`.
* Function-name parity: added
`nuwiki#commands#heading_add_level`,
`nuwiki#commands#heading_remove_level`,
`nuwiki#commands#table_move_column_{left,right}` as thin
aliases over the original short names so the public
`nuwiki#commands#*` surface matches `require('nuwiki.commands').*`.
Test harness:
* `scripts/test-keymaps-vim.vim` extended from 12 to 30 cases:
4 smart_return, 3 smart_tab/<S-Tab>, 3 named-command exists,
4 text-object helpers, 1 `dah` end-to-end, 2 folding, and the
original 12 pure-VimL cases. (Visual-mode mark inspection in
`vim -e -s` stays unreliable, so text objects are exercised
at the helper level plus one operator-pending end-to-end.)
Gates: 456 Rust / 39 Neovim / 30 Vim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
c8a6fc1172 |
parity(8b): multi-line list item continuation
Lines indented strictly past a list item's marker now attach to that
item rather than becoming a sibling paragraph. Matches upstream
vimwiki + Markdown convention.
Before:
- first item
continuing here ← rendered as a separate <p>
- second
Now:
- first item continuing here ← one <li>, joined with a space
- second
The detection lives in `parse_list_item`: after the item's first
line, we loop over subsequent lines and treat each as continuation
when its leading whitespace exceeds the marker's column. Two
flavours need handling because the lexer emits different tokens
based on indent width:
* 1..3 leading spaces → `Text(s)` with the whitespace embedded;
we trim it off the first text token before re-running
`parse_inline_seq`.
* 4+ leading spaces → `BlockquoteIndent` + bare `Text`; we
advance past the indent token and use the text as-is.
Continuation also works inside nested lists (`level + 1` threshold
adapts to the marker's own indent) and is bounded by blank lines /
unindented content / sibling-or-shallower list markers.
Tests: 6 new in `crates/nuwiki-core/tests/list_continuation.rs`
covering single-line continuation, multi-line continuation, blank-
line termination, unindented termination, nested-list continuation,
and the HTML-renderer regression (single `<ul>` with two `<li>`s,
no orphan `<p>`).
Gates: 456 Rust / 39 Neovim / 12 Vim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
d8fa59a63a |
parity(4): diary weekly / monthly / yearly frequency support
vimwiki's `diary_frequency` config has been honoured by the existing
`nuwiki.diary.openToday` / `openYesterday` / `openTomorrow` commands
end-to-end. Setting `diary_frequency = 'weekly'` (or `monthly` /
`yearly`) now creates and addresses entries at that cadence — file
stems follow the canonical formats:
daily YYYY-MM-DD 2026-05-12.wiki
weekly YYYY-Www 2026-W19.wiki (ISO 8601 week)
monthly YYYY-MM 2026-05.wiki
yearly YYYY 2026.wiki
Core additions (nuwiki_core::date):
- DiaryFrequency enum + permissive `parse` (unknown → Daily)
- DiaryPeriod enum unifying Day / Week / Month / Year
- format / parse / next / prev / today_utc + first_day, with
proper ISO-week math (Thursday rule, year-boundary handling)
LSP wiring:
- WikiConfig::frequency() and diary_path_for_period()
- crate::diary::uri_for_period
- Index now records `diary_period` for any of the four flavours;
`diary_date` is preserved (filtered to Day-only) for back-compat
with existing daily-only callers
- `nuwiki.diary.next` / `nuwiki.diary.prev` now navigate at the
*same flavour* as the current entry (or at the wiki's configured
frequency when off a diary page), via new
`crate::diary::next_period` / `prev_period` helpers
- `nuwiki.diary.openToday` returns the period stem + frequency in
its response payload alongside the URI
Tests:
- 12 in crates/nuwiki-core/tests/diary_period.rs covering the date
math (ISO week boundaries, format round-trips, next/prev across
year edges, etc.)
- 9 in crates/nuwiki-lsp/tests/diary_frequency.rs covering
WikiConfig path computation, index recognition for all four
stems, period navigation, and diary-dir filtering
Gates: 450 Rust / 39 Neovim / 12 Vim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
bcef714805 |
parity(8a): transclusion attr quote-stripping
`{{url|alt|key="quoted value"}}` syntax was already parsed end-to-end
through to `TransclusionNode::attrs`, but the value retained the
surrounding `"…"` (or `'…'`) characters verbatim. The HTML renderer
then escaped them into `"`, producing `style=""border: 1px""`
instead of clean `style="border: 1px"`.
Extracted a small `insert_attr` helper that splits on `=`, trims, and
strips matching single- or double-quote pairs from the value before
inserting. Unquoted values pass through unchanged.
Tests: 4 new in crates/nuwiki-core/tests/transclusion_attrs.rs
covering double-quote stripping, single-quote stripping, unquoted
pass-through, and the clean-HTML rendering shape (no `"`).
Note: this commit covers the "transclusion attrs" half of the
original Cluster 8 audit. The "multi-line list-item continuation
paragraphs" half requires lexer + parser changes (continuation lines
indented past the marker should attach to the prior list item
instead of becoming a sibling paragraph) and is deferred.
Gates: 429 Rust / 39 Neovim / 12 Vim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
214d54e3b9 |
parity(7): table cell alignment markers (|:--|--:|:--:|)
The Markdown-style alignment anchors on a table's header-separator row now propagate from the lexer through the parser into the AST, and the HTML renderer emits a `style="text-align: …;"` attribute on each affected `<th>` / `<td>`. |:--| → left |--:| → right |:--:| → center |---| → default (no style attr) Encoding choice: rather than threading the source string into the parser, the lexer now extracts per-cell alignment when it recognises the separator row and carries the `Vec<TableAlign>` inline on the `TableHeaderRow` token. The parser unpacks it into `TableNode`'s new `alignments: Vec<TableAlign>` field. Cells past the end of the vector render with the default alignment. `TableAlign` lives in `nuwiki_core::ast::block` alongside the table nodes and is re-exported via `nuwiki_core::ast`. Tests: 4 new in crates/nuwiki-core/tests/vimwiki_table_alignment.rs covering plain dashes, all three anchor flavours, the HTML output shape, and the no-style-attr case. The existing `vimwiki_lexer::table_header_separator_row` was updated to assert the new payload shape. Gates: 425 Rust / 39 Neovim / 12 Vim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
2562a046db |
parity(6): insert-mode <Tab>/<S-Tab> table cell nav
`<Tab>` / `<S-Tab>` in insert mode navigate between table cells when the cursor is on a `|…|` row, otherwise they pass through to their default insert-mode behaviour (literal tab / shift-tab). Same `<expr>`-mapping idiom as Cluster 5's smart_return. <Tab> next cell; creates a fresh row below if past the last cell <S-Tab> previous cell; no-op past the first Cursor lands immediately after the destination cell's leading `|`, matching upstream vimwiki's `vimwiki#tbl#go_*_cell` behaviour. Both Lua and VimL counterparts wired into ftplugin's existing table_editing block (gated alongside `gqq`/`<A-Left>`). Tests: 4 new in scripts/test-keymaps.lua — next cell, new-row overflow, previous cell, and pass-through outside a table. Gates: 421 Rust / 39 Neovim / 12 Vim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
e347f605ff |
parity(5): smart <CR> in insert mode (VimwikiReturn)
Bind `<CR>` in insert mode as an `<expr>` map to a `smart_return`
helper. Behaviour matches upstream vimwiki's `:VimwikiReturn`:
- On a list line with content → continue the list with the same
marker on a new line (preserving leading checkbox `[ ]` if any).
- On an empty list line (marker only) → clear the marker and break
out of the list with a plain newline.
- Inside a `|…|` table row → insert a fresh empty row below with
the same column count, cursor lands inside the first cell.
- Otherwise → plain `<CR>`.
Implementation note: the helper is `<expr>`-bound, which means
textlock is active and the buffer can't be mutated from inside the
callback. The function returns key sequences only — including
`<Esc>0DA<CR>` for the empty-list break and `<Esc>0li` for the
table-row cursor jump — so every effect flows through Vim's normal
keystroke pipeline and stays undo-coherent.
Both Lua and VimL counterparts shipped.
Tests: 4 new in scripts/test-keymaps.lua covering list continuation,
checkbox preservation, empty-marker break-out, and new table row.
Gates: 421 Rust / 35 Neovim / 12 Vim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
fd4d902fde |
parity(3): text objects — aH/iH, al/il, a\/i\, ac/ic
Five operator-pending + visual text-object pairs, matching upstream vimwiki: ah / ih heading section only (stops at any next heading) aH / iH heading section + sub-tree (stops at same-or-shallower) al / il list item (line, with / without marker prefix + checkbox) a\ / i\ table cell (with / without surrounding `|` separators) ac / ic table column (with / without the header separator row) Pre-existing `ah` used aH semantics — fixed to match vimwiki: `ah` now stops at the next heading regardless of level. `aH` is the new descendants-inclusive variant. Implementation notes: - Pure regex; no LSP round-trip. Each helper computes a `(line, col)` rectangle and drives the selection with feedkeys. - Operator-pending and visual need different feed sequences. In visual the previous anchor is sticky, so bounce through `<Esc>` first. In operator-pending an `<Esc>` would CANCEL the pending operator — feed the visual keys directly so Vim treats them as the motion. - Re-exported helpers (`_heading_block`, `_cell_ranges`, `_current_cell_for_line`, `_table_bounds`) keep the integration surface testable without going through Vim's visual-mode pipeline, whose `'<`/`'>` mark semantics fight headless test harnesses. Tests: 6 new in scripts/test-keymaps.lua — five pure-helper cases plus one end-to-end `dah` deletion to verify the operator-pending wiring. Gates: 421 Rust / 31 Neovim / 12 Vim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
46ae618b5f |
parity(2): insert-mode list bindings (<C-D>/<C-T>/<C-L><C-?>)
Match upstream vimwiki's insert-mode list editing: <C-D> list_change_level(-1) dedent current item <C-T> list_change_level(+1) indent current item <C-L><C-J> list_cycle_symbol(+1) cycle marker forward <C-L><C-K> list_cycle_symbol(-1) cycle marker backward <C-L><C-M> list_toggle_or_add_chk toggle if has checkbox, else add `[ ]` Cycle order matches vimwiki's canonical run: - → * → # → 1. → 1) → a) → A) → i) → I) → (wrap) Both Lua and VimL paths wired. Lua callbacks fire directly (no `<C-o>` dance) since list_change_level / changeSymbol mutate the buffer via the LSP applyEdit pipeline, which works cleanly in insert mode. VimL keeps the `<C-o>:call …<CR>` idiom since that's the standard there. Harness adds 5 cases covering the new insert-mode bindings plus one direct LSP roundtrip for changeSymbol — surfaced a long-standing stale-binary footgun in test-keymaps.sh (rebuilt only when bin was missing; now rebuilds every run since incremental cargo is fast). Harness also captures server log_messages and dumps them on failure so future swallowed-error bugs (Err → log + Ok(None)) are visible. Gates: 421 Rust / 25 Neovim / 12 Vim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ee0309b3c2 |
parity(1): vimwiki per-wiki config keys, table colspan/rowspan,
named link commands, mouse maps
Parity audit Cluster 1 — small wins.
WikiConfig (server) extended with 14 vimwiki globals:
- `index` (`g:vimwiki_index`), wired into `:VimwikiIndex` so users
with a custom index page stem (e.g. `home`) get the right file.
- `diary_frequency`, `diary_start_week_day`, `diary_caption_level`,
`diary_sort`, `diary_header` — diary keys (weekly/monthly/yearly
semantics land in Cluster 4; the keys parse now so config
migration doesn't need to wait).
- `maxhi`, `listsyms`, `listsyms_propagate`, `list_margin`,
`links_space_char`, `nested_syntaxes`, `auto_toc` — list +
highlight knobs the renderer/handlers can consult.
All keys threaded through `RawWiki` → `WikiConfig::from(RawWiki)`,
defaults centralised in `wiki_defaults()` so `empty()`, `from_root()`,
the legacy single-wiki path, and the `RawWiki` impl stay in sync.
Lua front-door (`lua/nuwiki/config.lua`) now documents the multi-wiki
`wikis = {…}` shape with every accepted per-wiki key — users who
prefer Lua tables no longer have to round-trip through
`init_options` raw JSON.
HTML renderer (`crates/nuwiki-core/src/render/html.rs`):
- New `table_spans()` pre-pass resolves vimwiki's `>` (col_span) and
`\\/` (row_span) continuation markers into proper HTML
`colspan="N"` / `rowspan="N"` attributes on the lead cell. Continuation
cells emit nothing, matching what browsers expect.
- The old behaviour (emitting `class="col-span"` / `class="row-span"`
as visual markers) is gone — replaced with real merging so the
rendered HTML matches the source semantics.
Named ex-commands:
- `:VimwikiNextLink` / `:VimwikiPrevLink` — were keymapped only
(`<Tab>`/`<S-Tab>`); now have explicit `:` commands in both editor
paths, dispatching to new `nuwiki.commands.link_next` / `link_prev`
pure-Vim/Lua helpers.
- `:VimwikiBaddLink` — adds the link target's file to the buffer
list without switching focus. Goes through
`textDocument/definition` and runs `:badd <fname>` on the resolved
URI.
Mouse maps (opt-in via `mappings.mouse = true` in Lua or
`g:nuwiki_mouse_mappings = 1` in Vim):
- `<2-LeftMouse>` follows, `<S-2-LeftMouse>` / `<C-2-LeftMouse>`
follow in split/vsplit, `<MiddleMouse>` adds to buflist,
`<RightMouse>` goes back. Mirrors upstream vimwiki's defaults.
Tests: 7 new in `parity_cluster_1.rs` covering the per-wiki config
defaults + raw JSON parse, the legacy-single-wiki path, colspan
folding into a lead cell with no leftover class markers, rowspan
across rows, no-attrs when the table has no spans, and a sanity
paragraph render. Total 421 Rust tests pass; clippy clean; both
keymap harnesses still green (20 nvim + 12 vim).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
de8b8fa30d |
feat(13.1): colorize + color_dic → ColorNode renderer
Closes the last pending §13.1 entries: - **`nuwiki.colorize`** (client-side, Lua + VimL) — wraps the word at cursor (or the visual selection on Neovim) in an inline `<span style="color:%c">…</span>` template. Matches vimwiki's default `color_tag_template`. Bound to `<Leader>wc` in both normal and visual mode on both editor paths; the previous "deferred" stub is gone. - **`color_dic` → renderer** — `HtmlConfig` gains a `color_dic: HashMap<String, String>` field reading the same key out of `initializationOptions` / `didChangeConfiguration`. The HTML export path threads it into `HtmlRenderer::with_colors`; `ColorNode` now picks `style="color:<value>"` when the colour name is in the dict, falling back to the existing `class="color-<name>"` when it isn't. SPEC §13.1 is fully checked off — the table moved from "deferred sketch" to a per-command status table marking all 11 commands done, plus a note on the `color_dic` follow-up landing alongside. README's "Phase 14 list & table edit commands" row now reads ✅ without the deferred-subset caveat, and the §13.1-blocked text-objects note in the keymaps section is rephrased as "planned follow-ups". Tests: 4 new in `phase17_colorize.rs` covering the renderer fallback when the dict is empty, the inline-style emission for a listed name, the fallback path for an unlisted name in a populated dict, and the `initializationOptions` JSON shape. Total 414 Rust tests pass; clippy clean; keymap harness still 20/20. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
4245424d2f |
feat(13.1-B): table rewriters — insert, align, moveColumn
Closes the table-rewriter cluster from SPEC §13.1. Server-side (ops module): - `render_blank_table(cols, rows)` — pure templating: header row, separator `|--|--|--|`, then `rows` empty data rows. Wired through `table_insert` which dispatches a `TextEdit` at the cursor. - `table_align_edit` — locates the `TableNode` containing the cursor line, computes max width per column across every row, re-emits the table with each cell space-padded to its column's width. The parser drops `|---|---|` separator rows but sets `TableNode.has_header`; the renderer re-inserts a padded separator after the header so the result still parses. - `table_move_column_edit` — column-under-cursor swap with the left or right neighbour (`dir = "left" | "right"`). Cursor column is computed by counting pipe separators before the cursor's byte offset on the row's line. Column widths swap alongside the data so the post-swap table stays aligned. No-ops cleanly when the swap would fall off either edge. Editor glue: - `lua/nuwiki/commands.lua` / `autoload/nuwiki/commands.vim` — the three "not yet implemented" stubs are replaced with real LSP dispatchers. `table_insert` accepts optional `cols`/`rows` arguments (defaults: 3×2). - Default keymaps `gqq` / `gq1` / `gww` / `gw1` now call `table_align`; `<A-Left>` / `<A-Right>` call `table_move_column_left` / `_right`. No more "deferred" notifications on the table keys. Tests: 8 new in `cluster_b_table_rewriters.rs` — blank-table shape (3×2 + 1×1), column-width alignment with separator-row repad, swap- right shape, swap-left clamp at column 0, no-table-found fallbacks, COMMANDS list completeness. Total 410 Rust tests pass; clippy clean; Neovim keymap harness still 20/20. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
9d34c8baa2 |
feat(13.1-A): list rewriters — removeDone, renumber, changeSymbol/Level
Closes the four-command list-rewriter cluster from SPEC §13.1. Server-side (commands.rs ops module): - `parse_symbol` / `render_marker` — round-trip between `:VimwikiListChangeSymbol` arg shapes (`-`, `1.`, `a)`, `i)`, `Dash`, `Numeric`, …) and the rendered marker text. `render_marker` knows how to spell `a/b/…/z/aa` and `i/ii/iv/v/…/MMM` for the alphabetic + roman variants. - `remove_done_edit` — walks every list (recursively through blockquotes and sublists), emits delete TextEdits for items whose checkbox is `Done` or `Rejected`. Item span gets extended through the trailing newline so we don't leave behind empty lines. Accepts an optional `position` to scope the operation to the item under cursor + its descendants. - `renumber_edit` — finds the list containing the cursor line (or every list when `whole_file: true`), re-sequences numeric markers in-place. Unordered lists are left alone. - `change_symbol_edit` — rewrites the leading marker on a single item, or every item in a list when `whole_list: true`. Uses `render_marker` so ordered variants get the right index. - `change_level_edit` — re-indents the marker line (or every line of the item subtree when `whole_subtree: true`) by ±2 spaces per level. Dedent clamps at column 0. - `find_list_at_line` + `find_marker_span` — pure helpers reused by the three above. Editor glue: - `lua/nuwiki/commands.lua` / `autoload/nuwiki/commands.vim` — removed all four "not yet implemented" stubs and wired them to the real LSP commands. Lua also exposes `list_change_lvl(direction)` for the `:VimwikiListChangeLvl decrease|increase` compat entry. - Keymaps for `glh` / `gll` / `gLh` / `gLl` (list level single + subtree), `glr` / `gLr` (renumber list + whole-file), `gl<Space>` / `gL<Space>` (remove done items) now hit the real commands instead of printing a "deferred" notification. Tests: 16 new in `cluster_a_list_rewriters.rs` covering symbol parsing, marker rendering (alpha + roman + numeric), removeDone shape, scoped removeDone, no-match cases, renumber sequencing, whole-file walk, changeSymbol single + whole-list, changeLevel single + subtree + clamp, and COMMANDS list completeness. Total 402 Rust tests pass; clippy clean; keymap harness still at 20/20. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
cebc806ce3 |
feat(13.1-C): link helpers — pasteWikilink, pasteUrl, normalize
Closing out §13.1's smallest cluster. Three commands move from "not yet implemented" stubs to real behaviour: - `nuwiki.link.pasteWikilink` (server, executeCommand) — derives the current page name from the source URI + wiki root, returns a `WorkspaceEdit` inserting `[[<page>]]` at the requested cursor position. - `nuwiki.link.pasteUrl` (server) — same lookup, but the inserted text is the page's relative HTML output URL (`<page>.html`, including subdir segments) so the snippet survives when the export root moves. - `nuwiki.link.normalize` (client) — wraps the word at cursor as `[[word]]` without following. Reuses the `wrap_cword_as_wikilink` helper that already powers the `<CR>` two-step. Pure-VimL on the Vim path; pure-Lua on the Neovim path. No LSP round-trip. Keymaps: - `+` (normal + visual) now actually calls `normalize_link` on both editor paths instead of stubbing with a "deferred" notification. Tests: - 5 new Rust unit tests in `cluster_c_link_helpers.rs` covering command-list presence + the page-name derivation for root and subdirectory pages + the URL / wikilink shape strings. - Neovim keymap harness gains a `links.normalize_via_+` case (20 passing now, up from 19). Vim harness inherits the same command-presence check via its existing smoke tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
7c9e679169 |
docs: rewrite README into a proper user-facing intro
The old README was mostly a phase-status table — useful for tracking
progress but unhelpful for a first-time reader landing on the repo.
Restructured around the three things a new user actually needs:
1. **What it is.** One-paragraph pitch + a feature checklist that
mirrors the SPEC §13.3 status without burying the reader in phase
numbers. Architecture details + the deferred §13.1 work stay in
`SPEC.md`, linked from the intro.
2. **How to install.** Plugin-manager snippets for lazy.nvim,
vim-plug, dein, and a plain-Vim packpath path. Plus a
"try it without touching your config" pointer to
`./start-nvim.sh` / `./start-vim.sh` so curious users can kick the
tyres in 5 seconds.
3. **How to use.** A compact `setup({})` example covering wiki_root,
multi-wiki, mappings groups, folding strategy, and diagnostic
severity. Then command and keymap cheatsheets that distinguish
"vimwiki-compat surface" from "things the LSP server returns",
plus the migrating-from-vimwiki notes (two behaviour deltas the
user might trip on).
Kept:
- The repository layout diagram (updated to reflect the renamed
ftplugin/syntax files and the new `scripts/` test harness).
- The implementation-status tables, now under `Development` so
contributors find them but new users aren't drowned in them.
- The dual MIT/Apache license footer.
No behaviour changes; documentation-only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
a229977b77 |
ci(keymaps): pin Neovim 0.11 from upstream release tarball
CI log for the keymaps job showed Lua crashing with `attempt to call field 'get_clients' (a nil value)` plus a flood of `W18: Invalid character in group name` on the `@vimwiki*` highlight links. Both signal that apt's `neovim` package is too old (Ubuntu LTS ships 0.6/0.7) — `vim.lsp.get_clients` only landed in 0.10, and Tree-sitter-style `@group.modifier` highlight names only became valid sometime in the 0.8-ish era. Switched the installer to pull the official static tarball (`neovim/neovim/releases/v0.11.3/nvim-linux-x86_64.tar.gz`) and symlink it into `/usr/local/bin/nvim`. Vim from apt is kept — it only runs the pure-VimL harness so its age doesn't matter. Also added a defensive fallback in the harness: `get_lsp_clients = vim.lsp.get_clients or vim.lsp.get_active_clients`, plus a `server_capabilities` nil guard. Won't matter on the pinned 0.11 runner, but means a future regression that drops the deps will fail with a clear `lsp.attached` FAIL message instead of a Lua stack trace. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
a489bea480 |
test(keymaps): hard timeouts + serialise the CI job behind test
User reported the editor-keymaps CI job hung for 30 minutes before "Has been cancelled" — twice in a row. Two changes to keep that from happening again: 1. Wrap both harness invocations with `timeout` (60s Neovim, 30s Vim). A misbehaving LSP attach, a stuck `vim.defer_fn`, or ex-mode hung on stdin can no longer hold the runner indefinitely; `timeout` kills the process and the wrapper exits non-zero so CI shows the real failure shape. 2. `</dev/null` on `vim -e -s` so ex-mode doesn't sit waiting for input on CI's non-TTY stdin (the local zsh run inherits the user's tty, masking this). 3. CI: the keymaps job now has `needs: test` and `timeout-minutes: 10`. `needs: test` serialises behind the cargo jobs so we don't fight for the single Gitea runner, and the workflow-level timeout is a belt to the script-level `timeout`'s braces — if for some reason both fail the same way, the runner reclaims itself in 10 minutes instead of 30. Local timing: `test-keymaps.sh` 10.4s, `test-keymaps-vim.sh` 0.1s. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
5fdd7a842e |
test(keymaps): Vim path harness + fix 25 broken one-liner functions
User asked about the Vim path of the keymap suite. Building it
surfaced a real bug: 25 of our autoload functions were written as
`function! foo() abort | call bar() | endfunction` one-liners, which
isn't valid Vim syntax — `function!` requires a multi-line body, and
Vim parses the `|` after `abort` as an unexpected trailing character
(E488). Most invocations of the buggy autoload functions errored
out the moment Vim tried to parse them, which is why the user saw
broken keymaps and confusing diagnostics.
Rewrote all 25 one-liners (`autoload/nuwiki/commands.vim`) into the
standard three-line form. Affected groups: `diary_*`, `toggle_list_item`,
`cycle_list_item`, `reject_list_item`, `heading_add`, `heading_remove`,
`toc_generate`, `links_generate`, `export_current` / `_all` /
`_all_force` / `_rss`, and the §13.1 deferred stubs (`list_change_lvl`,
`list_remove_done`, `table_*`, `colorize`, `paste_link`, `paste_url`).
Added `scripts/test-keymaps-vim.{sh,vim}` — a Vim-side counterpart of
the Neovim harness covering the pure-VimL bindings (header nav,
link nav, `o`/`O` bullet continuation, `<CR>` wrap step). The
LSP-roundtrip bindings (`<C-Space>`, `=`, `-`, …) stay on the Neovim
side because vim-lsp's async layer uses timers that don't fire
inside `vim -e -s` headless mode — their server-side codepath is
already exercised by the Neovim harness and the cargo test suite.
Vim harness covers 12 cases: filetype + 2 command-presence smoke
tests, 4 header-nav (`]]`/`[[`/`]=`/`]u`), `<Tab>` link-nav, `<CR>`
wrap-on-first-press, and 3 bullet-continuation flows.
CI: extended the existing `keymaps` job to install both nvim + vim
and run both harnesses. Verified locally:
Neovim harness: 19 passed, 0 failed
Vim harness: 12 passed, 0 failed
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|