feat(pack): vim.pack.get() gets VCS info #35631

Problem:
Force resolve `spec.version` overrides the information about whether
a user supplied `version` or not. Knowing it might be useful in some use
cases (like comparing to previously set `spec` to detect if it has
changed).

Solution:
Do not resolve `spec.version`. This also improves speed when triggering
events and calling `get()`.
- Place default branch first when listing all branches.
- Use correct terminology in `get_hash` helper.
- Do not return `{ '' }` if there are no tags.

Problem:
There is no way to get more information about installed plugins, like
current revision or default branch (necessary if resolving default
`spec.version` manually). As computing Git data migth take some time,
also allow `get()` to limit output to only necessary set of plugins.

Solution:
- introduce arguments to `get(names, opts)`, which follows other
  `vim.pack` functions. Plugin extra info is returned by default and
  should be opt-out via `opts.info = false`.
  - Examples:
    - Get current revision: `get({ 'plug-name' })[1].rev`
    - Get default branch: `get({ 'plug_name' })[1].branches[1]`
- `update()` and `del()` act on plugins in the same order their names
  are supplied. This is less surprising.
- default `opts.info` to `true` since this simplifies logic for the
  common user, while still leaving the door open for a faster `get()` if
  needed.
This commit is contained in:
Evgeni Chasnovski
2025-09-07 19:59:31 +03:00
committed by GitHub
parent fd59e72b47
commit 7853cde29a
3 changed files with 170 additions and 104 deletions

View File

@@ -271,9 +271,8 @@ Switch plugin's version:
run |vim.pack.update()|. run |vim.pack.update()|.
Freeze plugin from being updated: Freeze plugin from being updated:
• Update 'init.lua' for plugin to have `version` set to current commit hash. • Update 'init.lua' for plugin to have `version` set to current revision. Get
You can get it by running `vim.pack.update({ 'plugin-name' })` and yanking it with `:=vim.pack.get({ 'plug-name' })[1].rev` (looks like `abc12345`).
the word describing current state (looks like `abc12345`).
• |:restart|. • |:restart|.
Unfreeze plugin to start receiving updates: Unfreeze plugin to start receiving updates:
@@ -355,16 +354,27 @@ del({names}) *vim.pack.del()*
be managed by |vim.pack|, not necessarily already added to be managed by |vim.pack|, not necessarily already added to
current session. current session.
get() *vim.pack.get()* get({names}, {opts}) *vim.pack.get()*
Get data about all plugins managed by |vim.pack| Gets |vim.pack| plugin info, optionally filtered by `names`.
Parameters: ~
• {names} (`string[]?`) List of plugin names. Default: all plugins
managed by |vim.pack|.
• {opts} (`table?`) A table with the following fields:
• {info} (`boolean`) Whether to include extra plugin info.
Default `true`.
Return: ~ Return: ~
(`table[]`) A list of objects with the following fields: (`table[]`) A list of objects with the following fields:
• {spec} (`vim.pack.SpecResolved`) A |vim.pack.Spec| with defaults
made explicit.
• {path} (`string`) Plugin's path on disk.
• {active} (`boolean`) Whether plugin was added via |vim.pack.add()| • {active} (`boolean`) Whether plugin was added via |vim.pack.add()|
to current session. to current session.
• {branches}? (`string[]`) Available Git branches (first is default).
Missing if `info=false`.
• {path} (`string`) Plugin's path on disk.
• {rev}? (`string`) Current Git revision. Missing if `info=false`.
• {spec} (`vim.pack.SpecResolved`) A |vim.pack.Spec| with resolved
`name`.
• {tags}? (`string[]`) Available Git tags. Missing if `info=false`.
update({names}, {opts}) *vim.pack.update()* update({names}, {opts}) *vim.pack.update()*
Update plugins Update plugins

View File

@@ -68,9 +68,8 @@
---you run |vim.pack.update()|. ---you run |vim.pack.update()|.
--- ---
---Freeze plugin from being updated: ---Freeze plugin from being updated:
---- Update 'init.lua' for plugin to have `version` set to current commit hash. ---- Update 'init.lua' for plugin to have `version` set to current revision.
---You can get it by running `vim.pack.update({ 'plugin-name' })` and yanking ---Get it with `:=vim.pack.get({ 'plug-name' })[1].rev` (looks like `abc12345`).
---the word describing current state (looks like `abc12345`).
---- |:restart|. ---- |:restart|.
--- ---
---Unfreeze plugin to start receiving updates: ---Unfreeze plugin to start receiving updates:
@@ -148,13 +147,13 @@ local function git_clone(url, path)
end end
--- @async --- @async
--- @param rev string --- @param ref string
--- @param cwd string --- @param cwd string
--- @return string --- @return string
local function git_get_hash(rev, cwd) local function git_get_hash(ref, cwd)
-- Using `rev-list -1` shows a commit of revision, while `rev-parse` shows -- Using `rev-list -1` shows a commit of reference, while `rev-parse` shows
-- hash of revision. Those are different for annotated tags. -- hash of reference. Those are different for annotated tags.
return git_cmd({ 'rev-list', '-1', '--abbrev-commit', rev }, cwd) return git_cmd({ 'rev-list', '-1', '--abbrev-commit', ref }, cwd)
end end
--- @async --- @async
@@ -169,11 +168,14 @@ end
--- @param cwd string --- @param cwd string
--- @return string[] --- @return string[]
local function git_get_branches(cwd) local function git_get_branches(cwd)
local def_branch = git_get_default_branch(cwd)
local cmd = { 'branch', '--remote', '--list', '--format=%(refname:short)', '--', 'origin/**' } local cmd = { 'branch', '--remote', '--list', '--format=%(refname:short)', '--', 'origin/**' }
local stdout = git_cmd(cmd, cwd) local stdout = git_cmd(cmd, cwd)
local res = {} --- @type string[] local res = {} --- @type string[]
for l in vim.gsplit(stdout, '\n') do for l in vim.gsplit(stdout, '\n') do
res[#res + 1] = l:match('^origin/(.+)$') local branch = l:match('^origin/(.+)$')
local pos = branch == def_branch and 1 or (#res + 1)
table.insert(res, pos, branch)
end end
return res return res
end end
@@ -182,8 +184,8 @@ end
--- @param cwd string --- @param cwd string
--- @return string[] --- @return string[]
local function git_get_tags(cwd) local function git_get_tags(cwd)
local cmd = { 'tag', '--list', '--sort=-v:refname' } local tags = git_cmd({ 'tag', '--list', '--sort=-v:refname' }, cwd)
return vim.split(git_cmd(cmd, cwd), '\n') return tags == '' and {} or vim.split(tags, '\n')
end end
-- Plugin operations ---------------------------------------------------------- -- Plugin operations ----------------------------------------------------------
@@ -323,34 +325,22 @@ local function normalize_plugs(plugs)
return res return res
end end
--- @param names string[]? --- @param names? string[]
--- @return vim.pack.Plug[] --- @return vim.pack.Plug[]
local function plug_list_from_names(names) local function plug_list_from_names(names)
local all_plugins = M.get() local p_data_list = M.get(names, { info = false })
local plug_dir = get_plug_dir() local plug_dir = get_plug_dir()
local plugs = {} --- @type vim.pack.Plug[] local plugs = {} --- @type vim.pack.Plug[]
local used_names = {} --- @type table<string,boolean> for _, p_data in ipairs(p_data_list) do
-- Preserve plugin order; might be important during checkout or event trigger
for _, p_data in ipairs(all_plugins) do
-- NOTE: By default include only active plugins (and not all on disk). Using -- NOTE: By default include only active plugins (and not all on disk). Using
-- not active plugins might lead to a confusion as default `version` and -- not active plugins might lead to a confusion as default `version` and
-- user's desired one might mismatch. -- user's desired one might mismatch.
-- TODO(echasnovski): Consider changing this if/when there is lockfile. -- TODO(echasnovski): Change this when there is lockfile.
--- @cast names string[] if names ~= nil or p_data.active then
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, plug_dir) plugs[#plugs + 1] = new_plug(p_data.spec, plug_dir)
used_names[p_data.spec.name] = true
end end
end end
if vim.islist(names) and #plugs ~= #names then
--- @param n string
local unused = vim.tbl_filter(function(n)
return not used_names[n]
end, names)
error('The following plugins are not installed: ' .. table.concat(unused, ', '))
end
return plugs return plugs
end end
@@ -358,13 +348,7 @@ end
--- @param event_name 'PackChangedPre'|'PackChanged' --- @param event_name 'PackChangedPre'|'PackChanged'
--- @param kind 'install'|'update'|'delete' --- @param kind 'install'|'update'|'delete'
local function trigger_event(p, event_name, kind) local function trigger_event(p, event_name, kind)
local spec = vim.deepcopy(p.spec) local data = { kind = kind, spec = vim.deepcopy(p.spec), path = p.path }
-- Infer default branch for fuller `event-data` (if possible)
-- Doing it only on event trigger level allows keeping `spec` close to what
-- user supplied without performance issues during startup.
spec.version = spec.version or (uv.fs_stat(p.path) and git_get_default_branch(p.path))
local data = { kind = kind, spec = spec, path = p.path }
api.nvim_exec_autocmds(event_name, { pattern = p.path, data = data }) api.nvim_exec_autocmds(event_name, { pattern = p.path, data = data })
end end
@@ -463,7 +447,7 @@ end
--- @param p vim.pack.Plug --- @param p vim.pack.Plug
local function resolve_version(p) local function resolve_version(p)
local function list_in_line(name, list) local function list_in_line(name, list)
return #list == 0 and '' or ('\n' .. name .. ': ' .. table.concat(list, ', ')) return ('\n%s: %s'):format(name, table.concat(list, ', '))
end end
-- Resolve only once -- Resolve only once
@@ -987,13 +971,44 @@ end
--- @inlinedoc --- @inlinedoc
--- @class vim.pack.PlugData --- @class vim.pack.PlugData
--- @field spec vim.pack.SpecResolved A |vim.pack.Spec| with defaults made explicit.
--- @field path string Plugin's path on disk.
--- @field active boolean Whether plugin was added via |vim.pack.add()| to current session. --- @field active boolean Whether plugin was added via |vim.pack.add()| to current session.
--- @field branches? string[] Available Git branches (first is default). Missing if `info=false`.
--- @field path string Plugin's path on disk.
--- @field rev? string Current Git revision. Missing if `info=false`.
--- @field spec vim.pack.SpecResolved A |vim.pack.Spec| with resolved `name`.
--- @field tags? string[] Available Git tags. Missing if `info=false`.
--- Get data about all plugins managed by |vim.pack| --- @class vim.pack.keyset.get
--- @inlinedoc
--- @field info boolean Whether to include extra plugin info. Default `true`.
--- @param p_data_list vim.pack.PlugData[]
local function add_p_data_info(p_data_list)
local funs = {} --- @type (async fun())[]
for i, p_data in ipairs(p_data_list) do
local path = p_data.path
--- @async
funs[i] = function()
p_data.branches = git_get_branches(path)
p_data.rev = git_get_hash('HEAD', path)
p_data.tags = git_get_tags(path)
end
end
--- @async
local function joined_f()
async.join(n_threads, funs)
end
async.run(joined_f):wait()
end
--- Gets |vim.pack| plugin info, optionally filtered by `names`.
--- @param names? string[] List of plugin names. Default: all plugins managed by |vim.pack|.
--- @param opts? vim.pack.keyset.get
--- @return vim.pack.PlugData[] --- @return vim.pack.PlugData[]
function M.get() function M.get(names, opts)
vim.validate('names', names, vim.islist, true, 'list')
opts = vim.tbl_extend('force', { info = true }, opts or {})
-- Process active plugins in order they were added. Take into account that -- Process active plugins in order they were added. Take into account that
-- there might be "holes" after `vim.pack.del()`. -- there might be "holes" after `vim.pack.del()`.
local active = {} --- @type table<integer,vim.pack.Plug?> local active = {} --- @type table<integer,vim.pack.Plug?>
@@ -1001,11 +1016,12 @@ function M.get()
active[p_active.id] = p_active.plug active[p_active.id] = p_active.plug
end end
--- @type vim.pack.PlugData[] local res = {} --- @type vim.pack.PlugData[]
local res = {} local used_names = {} --- @type table<string,boolean>
for i = 1, n_active_plugins do for i = 1, n_active_plugins do
if active[i] then if active[i] and (not names or vim.tbl_contains(names, active[i].spec.name)) then
res[#res + 1] = { spec = vim.deepcopy(active[i].spec), path = active[i].path, active = true } res[#res + 1] = { spec = vim.deepcopy(active[i].spec), path = active[i].path, active = true }
used_names[active[i].spec.name] = true
end end
end end
@@ -1015,21 +1031,34 @@ function M.get()
local plug_dir = get_plug_dir() local plug_dir = get_plug_dir()
for n, t in vim.fs.dir(plug_dir, { depth = 1 }) do for n, t in vim.fs.dir(plug_dir, { depth = 1 }) do
local path = vim.fs.joinpath(plug_dir, n) local path = vim.fs.joinpath(plug_dir, n)
if t == 'directory' and not active_plugins[path] then local is_in_names = not names or vim.tbl_contains(names, n)
if t == 'directory' and not active_plugins[path] and is_in_names then
local spec = { name = n, src = git_cmd({ 'remote', 'get-url', 'origin' }, path) } local spec = { name = n, src = git_cmd({ 'remote', 'get-url', 'origin' }, path) }
res[#res + 1] = { spec = spec, path = path, active = false } res[#res + 1] = { spec = spec, path = path, active = false }
end used_names[n] = true
end
-- Make default `version` explicit
for _, p_data in ipairs(res) do
if not p_data.spec.version then
p_data.spec.version = git_get_default_branch(p_data.path)
end end
end end
end end
async.run(do_get):wait() async.run(do_get):wait()
if names ~= nil then
-- Align result with input
local names_order = {} --- @type table<string,integer>
for i, n in ipairs(names) do
if not used_names[n] then
error(('Plugin `%s` is not installed'):format(tostring(n)))
end
names_order[n] = i
end
table.sort(res, function(a, b)
return names_order[a.spec.name] < names_order[b.spec.name]
end)
end
if opts.info then
add_p_data_info(res)
end
return res return res
end end

View File

@@ -465,7 +465,7 @@ describe('vim.pack', function()
watch_events({ 'PackChangedPre', 'PackChanged' }) watch_events({ 'PackChangedPre', 'PackChanged' })
exec_lua(function() exec_lua(function()
-- Should provide event-data respecting manual and inferred default `version` -- Should provide event-data respecting manual `version` without inferring default
vim.pack.add({ { src = repos_src.basic, version = 'feat-branch' }, repos_src.defbranch }) vim.pack.add({ { src = repos_src.basic, version = 'feat-branch' }, repos_src.defbranch })
end) end)
@@ -473,11 +473,11 @@ describe('vim.pack', function()
local installpre_basic = find_in_log(log, 'PackChangedPre', 'install', 'basic', 'feat-branch') local installpre_basic = find_in_log(log, 'PackChangedPre', 'install', 'basic', 'feat-branch')
local installpre_defbranch = find_in_log(log, 'PackChangedPre', 'install', 'defbranch', nil) local installpre_defbranch = find_in_log(log, 'PackChangedPre', 'install', 'defbranch', nil)
local updatepre_basic = find_in_log(log, 'PackChangedPre', 'update', 'basic', 'feat-branch') local updatepre_basic = find_in_log(log, 'PackChangedPre', 'update', 'basic', 'feat-branch')
local updatepre_defbranch = find_in_log(log, 'PackChangedPre', 'update', 'defbranch', 'dev') local updatepre_defbranch = find_in_log(log, 'PackChangedPre', 'update', 'defbranch', nil)
local update_basic = find_in_log(log, 'PackChanged', 'update', 'basic', 'feat-branch') local update_basic = find_in_log(log, 'PackChanged', 'update', 'basic', 'feat-branch')
local update_defbranch = find_in_log(log, 'PackChanged', 'update', 'defbranch', 'dev') local update_defbranch = find_in_log(log, 'PackChanged', 'update', 'defbranch', nil)
local install_basic = find_in_log(log, 'PackChanged', 'install', 'basic', 'feat-branch') local install_basic = find_in_log(log, 'PackChanged', 'install', 'basic', 'feat-branch')
local install_defbranch = find_in_log(log, 'PackChanged', 'install', 'defbranch', 'dev') local install_defbranch = find_in_log(log, 'PackChanged', 'install', 'defbranch', nil)
eq(8, #log) eq(8, #log)
-- NOTE: There is no guaranteed installation order among separate plugins (as it is async) -- NOTE: There is no guaranteed installation order among separate plugins (as it is async)
@@ -571,11 +571,9 @@ describe('vim.pack', function()
eq({}, n.exec_lua('return { vim.g._plugin, vim.g._after_plugin }')) eq({}, n.exec_lua('return { vim.g._plugin, vim.g._after_plugin }'))
-- Plugins should still be marked as "active", since they were added -- Plugins should still be marked as "active", since they were added
plugindirs_data.spec.version = 'main'
plugindirs_data.active = true plugindirs_data.active = true
basic_data.spec.version = 'main'
basic_data.active = true basic_data.active = true
eq({ plugindirs_data, basic_data }, n.exec_lua('return vim.pack.get()')) eq({ plugindirs_data, basic_data }, exec_lua('return vim.pack.get(nil, { info = false })'))
end end
-- Works on initial install -- Works on initial install
@@ -623,7 +621,8 @@ describe('vim.pack', function()
'`basic`:\n', '`basic`:\n',
-- Should report available branches and tags if revision is absent -- Should report available branches and tags if revision is absent
'`wrong%-version`', '`wrong%-version`',
'Available:\nTags: some%-tag\nBranches: feat%-branch, main', -- Should list default branch first
'Available:\nTags: some%-tag\nBranches: main, feat%-branch',
-- Should report available branches and versions if no constraint match -- Should report available branches and versions if no constraint match
'`semver`', '`semver`',
'Available:\nVersions: v1%.0%.0, v0%.4, 0%.3%.1, v0%.3%.0.*\nBranches: main\n', 'Available:\nVersions: v1%.0%.0, v0%.4, 0%.3%.1, v0%.3%.0.*\nBranches: main\n',
@@ -1143,8 +1142,8 @@ describe('vim.pack', function()
-- Should trigger relevant events only for actually updated plugins -- Should trigger relevant events only for actually updated plugins
n.exec('write') n.exec('write')
local log = exec_lua('return _G.event_log') local log = exec_lua('return _G.event_log')
eq(1, find_in_log(log, 'PackChangedPre', 'update', 'fetch', 'main')) eq(1, find_in_log(log, 'PackChangedPre', 'update', 'fetch', nil))
eq(2, find_in_log(log, 'PackChanged', 'update', 'fetch', 'main')) eq(2, find_in_log(log, 'PackChanged', 'update', 'fetch', nil))
eq(2, #log) eq(2, #log)
end) end)
@@ -1180,7 +1179,7 @@ describe('vim.pack', function()
vim.pack.add({ repos_src.basic }) vim.pack.add({ repos_src.basic })
end) end)
validate('The following plugins are not installed: aaa, ccc', { 'aaa', 'basic', 'ccc' }) validate('Plugin `ccc` is not installed', { 'ccc', 'basic', 'aaa' })
-- Empty list is allowed with warning -- Empty list is allowed with warning
n.exec('messages clear') n.exec('messages clear')
@@ -1192,39 +1191,73 @@ describe('vim.pack', function()
end) end)
describe('get()', function() describe('get()', function()
local basic_spec = { name = 'basic', src = repos_src.basic, version = 'main' } local make_basic_data = function(active, info)
local basic_path = pack_get_plug_path('basic') local spec = { name = 'basic', src = repos_src.basic, version = 'feat-branch' }
local defbranch_spec = { name = 'defbranch', src = repos_src.defbranch, version = 'dev' } local path = pack_get_plug_path('basic')
local defbranch_path = pack_get_plug_path('defbranch') local res = { active = active, path = path, spec = spec }
if info then
res.branches = { 'main', 'feat-branch' }
res.rev = git_get_hash('feat-branch', 'basic')
res.tags = { 'some-tag' }
end
return res
end
local make_defbranch_data = function(active, info)
local spec = { name = 'defbranch', src = repos_src.defbranch }
local path = pack_get_plug_path('defbranch')
local res = { active = active, path = path, spec = spec }
if info then
res.branches = { 'dev', 'main' }
res.rev = git_get_hash('dev', 'defbranch')
res.tags = {}
end
return res
end
it('returns list with necessary data', function()
local basic_data, defbranch_data
it('returns list of available plugins', function()
-- Should work just after installation -- Should work just after installation
exec_lua(function() exec_lua(function()
vim.pack.add({ repos_src.defbranch, repos_src.basic }) vim.pack.add({ repos_src.defbranch, { src = repos_src.basic, version = 'feat-branch' } })
end) end)
eq({ defbranch_data = make_defbranch_data(true, true)
basic_data = make_basic_data(true, true)
-- Should preserve order in which plugins were `vim.pack.add()`ed -- Should preserve order in which plugins were `vim.pack.add()`ed
{ active = true, path = defbranch_path, spec = defbranch_spec }, eq({ defbranch_data, basic_data }, exec_lua('return vim.pack.get()'))
{ active = true, path = basic_path, spec = basic_spec },
}, exec_lua('return vim.pack.get()'))
-- Should also list non-active plugins -- Should also list non-active plugins
n.clear() n.clear()
exec_lua(function() exec_lua(function()
vim.pack.add({ repos_src.basic }) vim.pack.add({ { src = repos_src.basic, version = 'feat-branch' } })
end) end)
eq({ defbranch_data = make_defbranch_data(false, true)
basic_data = make_basic_data(true, true)
-- Should first list active, then non-active -- Should first list active, then non-active
{ active = true, path = basic_path, spec = basic_spec }, eq({ basic_data, defbranch_data }, exec_lua('return vim.pack.get()'))
{ active = false, path = defbranch_path, spec = defbranch_spec },
}, exec_lua('return vim.pack.get()')) -- Should respect `names` for both active and not active plugins
eq({ basic_data }, exec_lua('return vim.pack.get({ "basic" })'))
eq({ defbranch_data }, exec_lua('return vim.pack.get({ "defbranch" })'))
eq({ defbranch_data, basic_data }, exec_lua('return vim.pack.get({ "defbranch", "basic" })'))
local bad_get_cmd = 'return vim.pack.get({ "ccc", "basic", "aaa" })'
matches('Plugin `ccc` is not installed', pcall_err(exec_lua, bad_get_cmd))
-- Should respect `opts.info`
defbranch_data = make_defbranch_data(false, false)
basic_data = make_basic_data(true, false)
eq({ basic_data, defbranch_data }, exec_lua('return vim.pack.get(nil, { info = false })'))
eq({ basic_data }, exec_lua('return vim.pack.get({ "basic" }, { info = false })'))
eq({ defbranch_data }, exec_lua('return vim.pack.get({ "defbranch" }, { info = false })'))
end) end)
it('respects `data` field', function() it('respects `data` field', function()
local out = exec_lua(function() local out = exec_lua(function()
vim.pack.add({ vim.pack.add({
{ src = repos_src.basic, data = { test = 'value' } }, { src = repos_src.basic, version = 'feat-branch', data = { test = 'value' } },
{ src = repos_src.defbranch, data = 'value' }, { src = repos_src.defbranch, data = 'value' },
}) })
local plugs = vim.pack.get() local plugs = vim.pack.get()
@@ -1236,7 +1269,7 @@ describe('vim.pack', function()
it('works with `del()`', function() it('works with `del()`', function()
exec_lua(function() exec_lua(function()
vim.pack.add({ repos_src.defbranch, repos_src.basic }) vim.pack.add({ repos_src.defbranch, { src = repos_src.basic, version = 'feat-branch' } })
end) end)
exec_lua(function() exec_lua(function()
@@ -1251,15 +1284,9 @@ describe('vim.pack', function()
-- Should not include removed plugins immediately after they are removed, -- Should not include removed plugins immediately after they are removed,
-- while still returning list without holes -- while still returning list without holes
exec_lua('vim.pack.del({ "defbranch" })') exec_lua('vim.pack.del({ "defbranch" })')
eq({ local defbranch_data = make_defbranch_data(true, true)
{ local basic_data = make_basic_data(true, true)
{ active = true, path = defbranch_path, spec = defbranch_spec }, eq({ { defbranch_data, basic_data }, { basic_data } }, exec_lua('return _G.get_log'))
{ active = true, path = basic_path, spec = basic_spec },
},
{
{ active = true, path = basic_path, spec = basic_spec },
},
}, exec_lua('return _G.get_log'))
end) end)
end) end)
@@ -1281,16 +1308,16 @@ describe('vim.pack', function()
eq(false, pack_exists('plugindirs')) eq(false, pack_exists('plugindirs'))
eq( eq(
"vim.pack: Removed plugin 'plugindirs'\nvim.pack: Removed plugin 'basic'", "vim.pack: Removed plugin 'basic'\nvim.pack: Removed plugin 'plugindirs'",
n.exec_capture('messages') n.exec_capture('messages')
) )
-- Should trigger relevant events in order as specified in `vim.pack.add()` -- Should trigger relevant events in order as specified in `vim.pack.add()`
local log = exec_lua('return _G.event_log') local log = exec_lua('return _G.event_log')
eq(1, find_in_log(log, 'PackChangedPre', 'delete', 'plugindirs', 'main')) eq(1, find_in_log(log, 'PackChangedPre', 'delete', 'basic', 'feat-branch'))
eq(2, find_in_log(log, 'PackChanged', 'delete', 'plugindirs', 'main')) eq(2, find_in_log(log, 'PackChanged', 'delete', 'basic', 'feat-branch'))
eq(3, find_in_log(log, 'PackChangedPre', 'delete', 'basic', 'feat-branch')) eq(3, find_in_log(log, 'PackChangedPre', 'delete', 'plugindirs', nil))
eq(4, find_in_log(log, 'PackChanged', 'delete', 'basic', 'feat-branch')) eq(4, find_in_log(log, 'PackChanged', 'delete', 'plugindirs', nil))
eq(4, #log) eq(4, #log)
end) end)
@@ -1310,7 +1337,7 @@ describe('vim.pack', function()
vim.pack.add({ repos_src.basic }) vim.pack.add({ repos_src.basic })
end) end)
validate('The following plugins are not installed: aaa, ccc', { 'aaa', 'basic', 'ccc' }) validate('Plugin `ccc` is not installed', { 'ccc', 'basic', 'aaa' })
eq(true, pack_exists('basic')) eq(true, pack_exists('basic'))
-- Empty list is allowed with warning -- Empty list is allowed with warning