Skip to content

nvim: update flake to Neovim 0.12.4 and add a test suite - #21

Merged
junhyeokahn merged 11 commits into
mainfrom
chore/nvim-flake-update-2026-07
Aug 1, 2026
Merged

nvim: update flake to Neovim 0.12.4 and add a test suite#21
junhyeokahn merged 11 commits into
mainfrom
chore/nvim-flake-update-2026-07

Conversation

@junhyeokahn

Copy link
Copy Markdown
Owner

Why

install/nvim/flake.lock was pinned to nixpkgs from 2025-05-10 — 15 months stale. This updates it to 2026-07-30 and adds a test suite so the next update is safe to perform.

What changed

Neovim 0.11.1 → 0.12.4, plus every bundled plugin and tool: clang-tools 19 → 21, basedpyright 1.29 → 1.39, lua-language-server 3.14 → 3.18, ripgrep 14 → 15, fzf 0.62 → 0.74, mini.nvim → 0.18.0, fzf-lua ~800 commits.

A 22-case mini.test suite at install/nvim/tests/, run via nix run ./install/nvim#test (~16s):

  • test_startup.lua — the config loads with zero errors, every module present, options applied
  • test_contract.lua — ~60 assertions that every plugin API the config calls still exists
  • test_behavior.lua — 6 end-to-end outcomes: stylua/yapf formatting, harpoon round-trip, treesitter highlighting, oil listing, lua_ls attach + completion

CI's two nvim steps collapse to one nix run ./install/nvim#test. .github/scripts/verify-nvim.lua is deleted — every check it made is covered, and covered more strictly.

Two pre-existing bugs found

Neither was caused by the upgrade.

  • nodePackages.bash-language-server no longer evaluates; nixpkgs removed nodePackages.
  • lua_ls had no knowledge of the vim global. lsp.lua builds server configs from scratch via vim.lsp.config() and so never picked up the runtime/workspace.library snippet nvim-lspconfig documents as opt-in. Every config file reported "Undefined global `vim`" with no vim.* completion. Split out as 145bf89 since it changes editor behavior rather than test infrastructure.

Why the old check wasn't enough

config/init.lua uses bare require with no pcall. When a plugin's setup{} throws, Neovim prints the error and startup continues — and verify-nvim.lua only checked that modules were require-able, which they are whether or not setup{} succeeded. CI could pass green with half the config silently unapplied.

Suite trustworthiness

Four false-greens were found in the suite itself during review and closed, each with an injection proof:

Gap Now
Runner hung forever on an all-passing run explicit qall!, exit 0
Zero collected tests exited 0 refuses to report success
zk breakage entirely invisible (pcall-guarded module) caught via <leader>z* keymaps
LSP test passed with the lua_ls fix reverted asserts no "Undefined global `vim`" diagnostic

A known limitation is documented in test_startup.lua: every config module loaded can false-pass if the terminal module throws, because LuaJIT leaves a non-nil sentinel in package.loaded. It's kept because it catches an omitted require — which raises no error at all — and startup produces no errors is the reliable guard for throws.

Not verified yet

This suite has never run on CI. Green on macos-latest/ubuntu-latest, cold-runner timing for yapf and lua_ls, and paths-filter behavior on a real diff all ride on this PR's first Actions run. The yapf case already carries a raised timeout for cold spawns; the LSP case has a deliberate NVIM_TEST_SKIP_LSP escape hatch left unused pending real CI numbers.

Out of scope

Deliberately not included, each worth its own change: migrating nvim-cmp → 0.12 native completion, copilot-vim → native textDocument/inlineCompletion, and deleting the hand-rolled LspStart/LspRestart commands now superseded by :lsp.

🤖 Generated with Claude Code

junhyeokahn and others added 11 commits July 31, 2026 20:01
Neovim 0.11.1 -> 0.12.4, plus 15 months of plugin and tool updates
(clang-tools 19 -> 21, basedpyright 1.29 -> 1.39, lua-language-server
3.14 -> 3.18, ripgrep 14 -> 15, fzf 0.62 -> 0.74, mini.nvim -> 0.18.0).

nodePackages was removed from nixpkgs, so bash-language-server moves to
the top level.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ness

Three failure-path bugs in the mini.test harness defeated its purpose of
catching nix flake update breakage:

- flake.nix: nvimTest used `exec nvim`, which replaces the shell process
  and permanently defeats the `trap ... EXIT` cleanup, leaking a tmp dir
  (with populated data/state/cache) on every run. Now nvim runs normally,
  its exit status is captured, the tmp dir is removed explicitly, and the
  script exits with nvim's original status.

- run.lua: MiniTest.run() does not guard MiniTest.collect(), so a broken
  test file (e.g. a failed assert in helpers.lua) re-raises an error that
  nvim prints and then hangs on forever in headless mode instead of
  exiting nonzero. MiniTest.run() is now pcall-guarded; any bootstrap
  error prints and forces `cquit 1`.

- run.lua: mini.test's pass/fail check is vacuously false when zero cases
  are collected, so a bad glob/tests-dir silently exits 0 having tested
  nothing. Now asserts MiniTest.current.all_cases is non-empty after the
  run and exits nonzero with a clear message otherwise.

Verified all four paths manually via `nix run ./install/nvim#test`: all
green (0), an ordinary expectation failure (1), a bootstrap assert failure
(1, no hang), and zero collected tests (1, clear message). No leftover
temp dir after a run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
cmp.setup is a callable table (setmetatable + __call) in nvim-cmp's own
source, not a plain function, so it is checked with vim.is_callable
instead of the generic type()=="function" helper used for every other
API path.
lsp.lua builds server configs from scratch via vim.lsp.config(), so it
never picked up the runtime/workspace.library snippet that nvim-lspconfig
documents as opt-in. Without it lua_ls has no idea `vim` exists: every
config file reports "Undefined global `vim`" and offers no completion on
any vim.* path.

Found while writing the behavioral test for LSP completion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replace the old headless smoke-test steps with `nix run ./install/nvim#test`,
which now covers everything verify-nvim.lua checked plus more. Also widen the
yapf-format test's conform timeout so a cold first process spawn (the norm on
every CI runner, not an edge case) can't be mistaken for a broken formatter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- test_contract.lua: cover the zk.lua pcall-swallowed-require failure mode
  by asserting its <leader>z* keymaps register (proof the file ran past the
  pcall), plus the same class of gap for lsp.lua's cmp_nvim_lsp pcall.
- test_behavior.lua: the LSP completion test only asserted item count, which
  stayed green even with commit 145bf89's vim-global fix reverted. Replaced
  with an assertion on diagnostic content ("Undefined global `vim`") after
  empirically verifying (against the real pinned lua-language-server) that
  the originally suggested completion-label assertion never fires even when
  correctly fixed, which would have made the suite permanently red.

Verified by injection: breaking zk.lua's require and reverting 145bf89 both
turn the suite red; restored, it's 22/22 green.
The commit that added these settings (145bf89) already records why, and
the rest of this file carries no commentary.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@junhyeokahn
junhyeokahn merged commit 777bd6a into main Aug 1, 2026
11 checks passed
@junhyeokahn
junhyeokahn deleted the chore/nvim-flake-update-2026-07 branch August 1, 2026 06:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant