CI improvements:
- Add concurrency group to cancel redundant runs on same branch
- Add cargo cache to fmt job (was missing entirely)
- Add timeout-minutes: 5 to fast jobs (fmt, clippy, test) for fail-fast
- Change RUST_BACKTRACE from 'short' to '1' for better CI debuggability
- Pin push trigger to branches: [main] to avoid double-firing on PR merges
- Test minimum supported Neovim (0.11.0) instead of latest patch (0.11.3)
Release improvements:
- Enforce RUSTFLAGS: -D warnings at env level and in matrix rustflags
- Remove redundant checkout in release job (only needs env vars)
- Add release notes generation from git log since previous tag
- Make release creation idempotent (check if release exists before creating)
- Fix release_id not being set when release already exists
s:resolve_index referenced an undefined `a:file` (a copy-paste leftover
from wiki_root_for, whose parameter is named a:file) inside the
buffer-owning-wiki loop. Any get_wikilocal() call with no explicit index
while a wiki buffer was current — i.e. the ftplugin BufRead path — hit
`E121: undefined variable a:file`. The local is `l:file`, and the
surrounding `!empty(l:file)` guard already covers emptiness, so the
clause was both wrong and redundant; removed it.
Add development/tests/test-vars-vim.{sh,vim} covering the shim:
per-wiki-index resolution, global-default fallback, out-of-range clamp,
the no-index owning-wiki path (direct guard for this E121), and the
single-wiki shorthand. Wired into CI. 14/14 pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add headless harnesses covering the calendar-vim integration, wired into
CI alongside the existing keymap/config suites:
- test-calendar-vim.sh/.vim (+ -optout.vim): pure-VimL diary hooks
(calendar_sign markers, calendar_action path resolution from wiki root,
calendar window close), plugin/nuwiki.vim hook auto-wiring that
overrides calendar-vim's defaults, and opt-out via g:nuwiki_use_calendar
and g:nuwiki_no_calendar. Uses a stub calendar-vim on the runtimepath.
- test-calendar.sh/.lua: Neovim setup() wiring + window-close under the
real window API, and opt-out via use_calendar = false.
Fixes surfaced by the suite:
- diary.vim: new diary entries set filetype 'vimwiki' (was the raw
extension, e.g. 'wiki'); the stray FileType autocmd also blocked the
calendar window from closing.
- init.lua: drop the redundant Neovim FileType autocmd (plugin/nuwiki.vim
already wires both editors) and translate use_calendar=false into
g:nuwiki_no_calendar so the opt-out actually disables wiring.
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>
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>
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>
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>
`scripts/test-keymaps.sh` boots `nvim --headless` against a scratch
wiki, sources `scripts/test-keymaps.lua`, and asserts the post-state
of each buffer-local mapping registered by `ftplugin/vimwiki.vim` +
`lua/nuwiki/keymaps.lua`.
The harness covers the bindings that actually have observable effects
on the buffer or cursor:
- **Lists** (LSP round-trip): `<C-Space>` / `<C-@>` / `<Nul>` toggle,
`gln` cycle, `glx` reject, plus a `[X]→[ ]` round-trip.
- **Tasks**: `gnt` jumps to the next unfinished `[ ]`.
- **Headings** (LSP round-trip): `=` adds a level, `-` removes one,
`=` on h6 clamps without growing.
- **Header nav** (pure Lua): `]]` next, `[[` prev, `]u` parent.
- **Link nav** (pure Lua): `<Tab>` to the next `[[…]]`.
- **`<CR>` two-step**: first press wraps a bare word as `[[word]]`
and stops (matches vimwiki's review-then-follow).
- **Bullet continuation**: `o` / `O` keep the marker, and `o` on a
`[ ]` line carries the checkbox forward.
Each case sets buffer lines, places the cursor (1-based), fires
`nvim_feedkeys` with `replace_termcodes`, waits long enough for the
LSP `executeCommand` round-trip (800 ms by default; 100 ms for the
pure-client maps), and asserts either the resulting lines, a specific
line, the cursor's new line, or the buffer's new name.
Output goes via `$NUWIKI_KEYMAP_RESULTS` (env-var IPC keeps it
robust to `--clean -u` argument parsing). Exit code mirrors the
harness: 0 on green, 1 on any FAIL. Local run yields:
SUMMARY: 19 passed, 0 failed
CI: new `keymaps` job in `.gitea/workflows/ci.yaml` installs Neovim
and runs the script, so a regression in `lua/nuwiki/keymaps.lua`,
`autoload/nuwiki/commands.vim`, or the LSP command surface is caught
on every push.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>