commit 5d8e870c1178e8e8b6bb9bd5cd17682eb1edd825
parent df9ff9cfa8a4f120cb075d765aa68556394390ec
Author: Justin M. Keyes <justinkz@gmail.com>
Date: Fri, 22 Aug 2025 14:35:41 -0400
Merge #35429 vim.pack adjustments
Diffstat:
3 files changed, 41 insertions(+), 48 deletions(-)
diff --git a/runtime/doc/pack.txt b/runtime/doc/pack.txt
@@ -211,7 +211,9 @@ WORK IN PROGRESS built-in plugin manager! Early testing of existing features
is appreciated, but expect breaking changes without notice.
Manages plugins only in a dedicated *vim.pack-directory* (see |packages|):
-`$XDG_DATA_HOME/nvim/site/pack/core/opt`. Plugin's subdirectory name matches
+`$XDG_DATA_HOME/nvim/site/pack/core/opt`. `$XDG_DATA_HOME/nvim/site` needs to
+be part of 'packpath'. It usually is, but might not be in cases like |--clean|
+or setting |$XDG_DATA_HOME| during startup. Plugin's subdirectory name matches
plugin's name in specification. It is assumed that all plugins in the
directory are managed exclusively by `vim.pack`.
diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua
@@ -4,7 +4,9 @@
---is appreciated, but expect breaking changes without notice.
---
---Manages plugins only in a dedicated [vim.pack-directory]() (see |packages|):
----`$XDG_DATA_HOME/nvim/site/pack/core/opt`.
+---`$XDG_DATA_HOME/nvim/site/pack/core/opt`. `$XDG_DATA_HOME/nvim/site` needs to
+---be part of 'packpath'. It usually is, but might not be in cases like |--clean| or
+---setting |$XDG_DATA_HOME| during startup.
---Plugin's subdirectory name matches plugin's name in specification.
---It is assumed that all plugins in the directory are managed exclusively by `vim.pack`.
---
@@ -270,10 +272,11 @@ end
--- @field info vim.pack.PlugInfo Gathered information about plugin.
--- @param spec string|vim.pack.Spec
+--- @param plug_dir string?
--- @return vim.pack.Plug
-local function new_plug(spec)
+local function new_plug(spec, plug_dir)
local spec_resolved = normalize_spec(spec)
- local path = vim.fs.joinpath(get_plug_dir(), spec_resolved.name)
+ local path = vim.fs.joinpath(plug_dir or get_plug_dir(), spec_resolved.name)
local info = { err = '', installed = uv.fs_stat(path) ~= nil }
return { spec = spec_resolved, path = path, info = info }
end
@@ -324,6 +327,7 @@ end
--- @return vim.pack.Plug[]
local function plug_list_from_names(names)
local all_plugins = M.get()
+ local plug_dir = get_plug_dir()
local plugs = {} --- @type vim.pack.Plug[]
local used_names = {} --- @type table<string,boolean>
-- Preserve plugin order; might be important during checkout or event trigger
@@ -334,7 +338,7 @@ local function plug_list_from_names(names)
-- TODO(echasnovski): Consider changing this if/when there is lockfile.
--- @cast names string[]
if (not names and p_data.active) or vim.tbl_contains(names or {}, p_data.spec.name) then
- plugs[#plugs + 1] = new_plug(p_data.spec)
+ plugs[#plugs + 1] = new_plug(p_data.spec, plug_dir)
used_names[p_data.spec.name] = true
end
end
@@ -712,8 +716,11 @@ function M.add(specs, opts)
opts = vim.tbl_extend('force', { load = vim.v.vim_did_enter == 1, confirm = true }, opts or {})
vim.validate('opts', opts, 'table')
- --- @type vim.pack.Plug[]
- local plugs = vim.tbl_map(new_plug, specs)
+ local plug_dir = get_plug_dir()
+ local plugs = {} --- @type vim.pack.Plug[]
+ for i = 1, #specs do
+ plugs[i] = new_plug(specs[i], plug_dir)
+ end
plugs = normalize_plugs(plugs)
-- Install
diff --git a/test/functional/plugin/pack_spec.lua b/test/functional/plugin/pack_spec.lua
@@ -311,32 +311,20 @@ describe('vim.pack', function()
eq(exec_lua('return #_G.event_log'), 0)
end)
- it('passes data field through to opts.load', function()
- eq(
- 2,
- exec_lua(function()
- local successes = 0
- vim.pack.add({
- { name = 'tabletest', src = repos_src.basic, data = { test = 'value' } },
- { name = 'stringtest', src = repos_src.basic, data = 'value' },
- }, {
- confirm = false,
- load = function(p)
- if p.spec.name == 'tabletest' then
- if p.spec.data.test == 'value' then
- successes = successes + 1
- end
- end
- if p.spec.name == 'stringtest' then
- if p.spec.data == 'value' then
- successes = successes + 1
- end
- end
- end,
- })
- return successes
- end)
- )
+ it('passes `data` field through to `opts.load`', function()
+ local out = exec_lua(function()
+ local map = {} ---@type table<string,boolean>
+ local load = function(p)
+ local name = p.spec.name ---@type string
+ map[name] = name == 'basic' and (p.spec.data.test == 'value') or (p.spec.data == 'value')
+ end
+ vim.pack.add({
+ { src = repos_src.basic, data = { test = 'value' } },
+ { src = repos_src.defbranch, data = 'value' },
+ }, { load = load })
+ return map
+ end)
+ eq({ basic = true, defbranch = true }, out)
end)
it('asks for installation confirmation', function()
@@ -1207,21 +1195,17 @@ describe('vim.pack', function()
}, exec_lua('return vim.pack.get()'))
end)
- it('respects data field', function()
- eq(
- true,
- exec_lua(function()
- vim.pack.add {
- { src = repos_src.basic, data = { test = 'value' } },
- }
- for _, p in ipairs(vim.pack.get()) do
- if p.spec.name == 'basic' and p.spec.data.test == 'value' then
- return true
- end
- end
- return false
- end)
- )
+ it('respects `data` field', function()
+ local out = exec_lua(function()
+ vim.pack.add({
+ { src = repos_src.basic, data = { test = 'value' } },
+ { src = repos_src.defbranch, data = 'value' },
+ })
+ local plugs = vim.pack.get()
+ ---@type table<string,string>
+ return { basic = plugs[1].spec.data.test, defbranch = plugs[2].spec.data }
+ end)
+ eq({ basic = 'value', defbranch = 'value' }, out)
end)
it('works with `del()`', function()