7a0cec4920fa6f330ca62a9991fc6e8a304cb8e4
12 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
3b6693129c |
test(keymaps): headless Neovim harness for buffer-local bindings + CI
`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> |
||
|
|
ee61d40872 |
phase 9: editor glue — plugin, LSP wiring, install, health, docs
P5 + P6 resolved (SPEC §11): Neovim 0.11+ and Vim 9.1+.
Universal Vim entry:
- plugin/nuwiki.vim dispatches Vim vs Neovim. Neovim path waits for
the user's `require('nuwiki').setup()` call; Vim path starts the
LSP client on `FileType vimwiki` and exposes `:NuwikiInstall`.
- ftdetect/nuwiki.vim associates `*.wiki` with the `vimwiki` filetype.
- ftplugin/nuwiki.vim sets commentstring + comments + formatoptions +
suffixesadd + iskeyword, with a clean `b:undo_ftplugin`.
- syntax/nuwiki.vim ships default `@vimwiki*` highlight links for the
semantic-token legend (with `level1..6` + `centered` modifiers),
plus a minimal regex fallback so static highlighting works before
the LSP attaches.
Lua glue (Neovim 0.11+):
- init.lua exposes setup() / install() / health() — wiring only per
SPEC §6.2.
- config.lua holds the §7.5 schema (wiki_root / file_extension /
syntax / log_level) and a tbl_deep_extend apply().
- lsp.lua registers via `vim.lsp.config{} + vim.lsp.enable` on 0.11+;
falls back to a FileType autocmd calling `vim.lsp.start` on older
builds. Root dir walks up for `.git` / `.nuwiki`, then uses
wiki_root.
- install.lua does target-triple detection (Linux gnu/musl x x86_64/
aarch64, macOS arm/x86, Windows), curl+tar download from the
release URL, cp/chmod into bin/, with a cargo fallback. Honours
`g:nuwiki_build_from_source`.
- health.lua implements `:checkhealth nuwiki` per §7.6.
VimL glue (Vim 9.1+):
- autoload/nuwiki/lsp.vim follows §7.4 preference order:
vim-lsp (calls `lsp#register_server`) → coc.nvim (prints the
coc-settings.json snippet) → error.
- scripts/download_bin.vim mirrors the Lua installer for Dein /
vim-plug build hooks — same target triples, same download →
fallback → cargo build chain.
Help: doc/nuwiki.txt with tags for install (lazy.nvim / vim-plug /
Dein), config options, health, LSP feature list, `:NuwikiInstall`.
Rust workspace unchanged this phase; 172 tests still green locally.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
cf336ee839 |
phase 0: scaffold workspace, plugin layout, and CI
Lay down the empty repo skeleton defined in SPEC.md §5 so subsequent phases have somewhere to land: - Cargo workspace (resolver v2, edition 2021, MSRV 1.83) with nuwiki-core, nuwiki-lsp, nuwiki-ls — dep direction matches §6.2. - Vim/Neovim plugin directory layout (plugin, lua, autoload, ftdetect, ftplugin, syntax, doc, scripts) with header-only stubs. - .gitea/workflows/ci.yaml running fmt, clippy -D warnings, and tests pinned to Rust 1.83. - README, dual MIT/Apache-2.0 license texts, .gitignore. Verified: cargo check / fmt --check / clippy / test all clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |