commit 52cd9dcff260decda860cf154873b298d10c1208
parent 1a3d3b77bb8d4a4c7b52cbd0b23f6b56772bae0b
Author: Justin M. Keyes <justinkz@gmail.com>
Date: Thu, 29 Jan 2026 16:55:20 -0500
Merge #37617 from echasnovski/pack-clearer-lockfile-sync
Diffstat:
3 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/runtime/doc/pack.txt b/runtime/doc/pack.txt
@@ -226,9 +226,11 @@ located at `$XDG_CONFIG_HOME/nvim/nvim-pack-lock.json`. It is a JSON file that
is used to persistently track data about plugins. For a more robust config
treat lockfile like its part: put under version control, etc. In this case all
plugins from the lockfile will be installed at once and at lockfile's revision
-(instead of inferring from `version`). Should not be edited by hand. Corrupted
-data for installed plugins is repaired (including after deleting whole file),
-but `version` fields will be missing for not yet added plugins.
+(instead of inferring from `version`). This is done on the very first
+`vim.pack` function call to ensure that lockfile is aligned with what is
+actually on the disk. Lockfile should not be edited by hand. Corrupted data
+for installed plugins is repaired (including after deleting whole file), but
+`version` fields will be missing for not yet added plugins.
*vim.pack-examples*
@@ -351,6 +353,8 @@ Remove plugins from disk ~
<
*vim.pack-events*
+
+Performing actions via `vim.pack` functions can trigger these events:
• *PackChangedPre* - before trying to change plugin's state.
• *PackChanged* - after plugin's state has changed.
@@ -385,6 +389,7 @@ These events can be used to execute plugin hooks. For example: >lua
end
-- If hooks need to run on install, run this before `vim.pack.add()`
+ -- To act on install from lockfile, run before very first `vim.pack.add()`
vim.api.nvim_create_autocmd('PackChanged', { callback = hooks })
<
diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua
@@ -18,9 +18,10 @@
---located at `$XDG_CONFIG_HOME/nvim/nvim-pack-lock.json`. It is a JSON file that
---is used to persistently track data about plugins.
---For a more robust config treat lockfile like its part: put under version control, etc.
----In this case all plugins from the lockfile will be installed at once and
----at lockfile's revision (instead of inferring from `version`).
----Should not be edited by hand. Corrupted data for installed plugins is repaired
+---In this case all plugins from the lockfile will be installed at once and at lockfile's revision
+---(instead of inferring from `version`). This is done on the very first `vim.pack` function call
+---to ensure that lockfile is aligned with what is actually on the disk.
+---Lockfile should not be edited by hand. Corrupted data for installed plugins is repaired
---(including after deleting whole file), but `version` fields will be missing
---for not yet added plugins.
---
@@ -160,6 +161,7 @@
---
---[vim.pack-events]()
---
+---Performing actions via `vim.pack` functions can trigger these events:
---- [PackChangedPre]() - before trying to change plugin's state.
---- [PackChanged]() - after plugin's state has changed.
---
@@ -195,6 +197,7 @@
---end
---
----- If hooks need to run on install, run this before `vim.pack.add()`
+----- To act on install from lockfile, run before very first `vim.pack.add()`
---vim.api.nvim_create_autocmd('PackChanged', { callback = hooks })
---```
diff --git a/test/functional/plugin/pack_spec.lua b/test/functional/plugin/pack_spec.lua
@@ -612,6 +612,7 @@ describe('vim.pack', function()
-- Mock clean initial install, but with lockfile present
vim.fs.rm(pack_get_dir(), { force = true, recursive = true })
n.clear()
+ watch_events({ 'PackChangedPre', 'PackChanged' })
local basic_rev = git_get_hash('feat-branch', 'basic')
local defbranch_rev = git_get_hash('HEAD', 'defbranch')
@@ -637,6 +638,17 @@ describe('vim.pack', function()
eq(true, pack_exists('defbranch'))
eq(false, exec_lua('return pcall(require, "defbranch")'))
+ -- Should trigger `kind=install` events
+ local log = exec_lua('return _G.event_log')
+ local find_event = make_find_packchanged(log)
+ local installpre_basic = find_event('Pre', 'install', 'basic', 'feat-branch', false)
+ local installpre_defbranch = find_event('Pre', 'install', 'defbranch', nil, false)
+ local install_basic = find_event('', 'install', 'basic', 'feat-branch', false)
+ local install_defbranch = find_event('', 'install', 'defbranch', nil, false)
+ eq(4, #log)
+ eq(true, installpre_basic < install_basic)
+ eq(true, installpre_defbranch < install_defbranch)
+
-- Running `update()` should still update to use `main`
exec_lua(function()
vim.pack.update({ 'basic' }, { force = true })