8000 fix(merge): clear opts keys set to vim.NIL by zuqini · Pull Request #47 · zuqini/zpack.nvim · GitHub
[go: up one dir, main page]

Skip to content

fix(merge): clear opts keys set to vim.NIL - #47

Merged
zuqini merged 1 commit into
mainfrom
opts-vim-nil
Oct 30, 2026
Merged

zuqini merged 1 commit into
mainfrom
opts-vim-nil

Conversation

@zuqini
@zuqini zuqini commented Oct 29, 2026 •
Copy link
Copy Markdown
Owner

lazy.nvim's opts merge treats vim.NIL as "remove this key", so a later spec can drop an option an earlier one set:

{ 'user/plugin', opts = { a = { x = 1 } } }
{ 'user/plugin', opts = { a = vim.NIL } }  -- lazy.nvim: `a` is removed

zpack passed the userdata through instead, so setup() received a = vim.NIL and code like opts.a.x threw. After vim.tbl_deep_extend, merge_opts now walks the incoming opts along the tables it merged and removes their vim.NIL keys. Only tables vim.tbl_deep_extend created are written to, so specs' own opts are never edited.

As in lazy.nvim, vim.NIL is removed only where specs merge: at the top level of opts (unless these or the earlier opts are a non-empty list) and in a table merged into the one an earlier spec set at the same place. A table that replaces the earlier value (nothing, a scalar or a list was there, or it is a list itself) keeps its vim.NIL, and so do opts a function returns or edits.

Behaviour change: a vim.NIL at a merged key (e.g. a JSON null in LSP settings) no longer reaches the plugin. lazy.nvim users already can't do that; the vimdoc and docs/tips.md say how to still pass a null.

  • vimdoc opts entry and docs/tips.md Gotchas document vim.NIL
  • tests cover the cleared keys, the places vim.NIL is kept, specs' opts staying untouched across resolves, and an FFI cdata's __eq never being called (rawequal)
  • checked against a port of lazy.nvim's Util.merge on ~20k one-, two- and three-spec chains of opts shapes: no chain diverges from lazy.nvim that didn't on main, and 8,123 that did now match. The rest are existing differences: vim.tbl_deep_extend merges top-level list opts by index and drops a merged object's metatable

Rebuilt on main after #46 merged with its reworked vim.tbl_deep_extend merge. The earlier lazy.nvim merge rewrite on this branch is dropped.

lazy.nvim's merge treats vim.NIL as "remove this key", so
{ opts = { a = { x = 1 } } } + { opts = { a = vim.NIL } } drops `a`.
resolve_opts copied vim.NIL into the result instead, and setup() got
a = vim.NIL. After vim.tbl_deep_extend, walk the incoming opts along
the tables it merged and remove their vim.NIL keys. Only the tables
vim.tbl_deep_extend made are written to, so specs' opts are untouched;
a table that replaced the earlier value, a list, and function-form
opts keep their vim.NIL, as in lazy.nvim.

Behaviour change: a vim.NIL at a merged key (e.g. a JSON null in LSP
settings) no longer reaches the plugin; the vimdoc and tips.md say how
to pass one.

Refs zpack_nvim-0eg
@zuqini
zuqini changed the base branch from opts-extend-45 to main October 30, 2026 04:01
@zuqini zuqini closed this Oct 30, 2026
@zuqini zuqini reopened this Oct 30, 2026
@zuqini
zuqini merged commit 3bd8cdf into main Oct 30, 2026
4 checks passed
@zuqini
zuqini deleted the opts-vim-nil branch November 6, 2026 08:07
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

0