mirror of
https://github.com/neovim/neovim.git
synced 2025-12-11 09:02:40 +00:00
fix(pack)!: adjust install confirm (no error on "No", show names)
Problem: Installation confirmation has several usability issues:
- Choosing "No" results in a `vim.pack.add()` error. This was by
design to ensure that all later code that *might* reference
presumably installed plugin will not get executed. However, this
is often too restrictive since there might be no such code (like
if plugin's effects are automated in its 'plugin/' directory).
Instead the potential code using not installed plugin will throw
an error.
No error on "No" will also be useful for planned lockfile repair.
- List of soon-to-be-installed plugins doesn't mention plugin names.
This might be confusing if plugins are installed under different
name.
Solution: Silently drop installation step if user chose "No" and show
plugin names in confirmation text (together with their pretty aligned
sources).
This commit is contained in:
@@ -545,16 +545,24 @@ local function confirm_install(plug_list)
|
||||
return true
|
||||
end
|
||||
|
||||
local src = {} --- @type string[]
|
||||
for _, p in ipairs(plug_list) do
|
||||
src[#src + 1] = p.spec.src
|
||||
-- Gather pretty aligned list of plugins to install
|
||||
local name_width, name_max_width = {}, 0 --- @type integer[], integer
|
||||
for i, p in ipairs(plug_list) do
|
||||
name_width[i] = api.nvim_strwidth(p.spec.name)
|
||||
name_max_width = math.max(name_max_width, name_width[i])
|
||||
end
|
||||
local src_text = table.concat(src, '\n')
|
||||
local confirm_msg = ('These plugins will be installed:\n\n%s\n'):format(src_text)
|
||||
local res = vim.fn.confirm(confirm_msg, 'Proceed? &Yes\n&No\n&Always', 1, 'Question')
|
||||
confirm_all = res == 3
|
||||
local lines = {} --- @type string[]
|
||||
for i, p in ipairs(plug_list) do
|
||||
local pad = (' '):rep(name_max_width - name_width[i] + 1)
|
||||
lines[i] = ('%s%sfrom %s'):format(p.spec.name, pad, p.spec.src)
|
||||
end
|
||||
|
||||
local text = table.concat(lines, '\n')
|
||||
local confirm_msg = ('These plugins will be installed:\n\n%s\n'):format(text)
|
||||
local choice = vim.fn.confirm(confirm_msg, 'Proceed? &Yes\n&No\n&Always', 1, 'Question')
|
||||
confirm_all = choice == 3
|
||||
vim.cmd.redraw()
|
||||
return res ~= 2
|
||||
return choice ~= 2
|
||||
end
|
||||
|
||||
--- @param tags string[]
|
||||
@@ -662,14 +670,6 @@ end
|
||||
|
||||
--- @param plug_list vim.pack.Plug[]
|
||||
local function install_list(plug_list, confirm)
|
||||
-- Get user confirmation to install plugins
|
||||
if confirm and not confirm_install(plug_list) then
|
||||
for _, p in ipairs(plug_list) do
|
||||
p.info.err = 'Installation was not confirmed'
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local timestamp = get_timestamp()
|
||||
--- @async
|
||||
--- @param p vim.pack.Plug
|
||||
@@ -688,7 +688,18 @@ local function install_list(plug_list, confirm)
|
||||
|
||||
trigger_event(p, 'PackChanged', 'install')
|
||||
end
|
||||
|
||||
-- Install possibly after user confirmation
|
||||
if not confirm or confirm_install(plug_list) then
|
||||
run_list(plug_list, do_install, 'Installing plugins')
|
||||
end
|
||||
|
||||
-- Ensure that not installed plugins are absent in lockfile
|
||||
for _, p in ipairs(plug_list) do
|
||||
if not p.info.installed then
|
||||
plugin_lock.plugins[p.spec.name] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @async
|
||||
@@ -845,11 +856,6 @@ function M.add(specs, opts)
|
||||
if #plugs_to_install > 0 then
|
||||
git_ensure_exec()
|
||||
install_list(plugs_to_install, opts.confirm)
|
||||
for _, p in ipairs(plugs_to_install) do
|
||||
if not p.info.installed then
|
||||
plugin_lock.plugins[p.spec.name] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if needs_lock_write then
|
||||
|
||||
@@ -387,18 +387,22 @@ describe('vim.pack', function()
|
||||
end)
|
||||
|
||||
it('asks for installation confirmation', function()
|
||||
-- Do not confirm installation to see what happens
|
||||
-- Do not confirm installation to see what happens (should not error)
|
||||
mock_confirm(2)
|
||||
|
||||
local err = pcall_err(exec_lua, function()
|
||||
vim.pack.add({ repos_src.basic })
|
||||
exec_lua(function()
|
||||
vim.pack.add({ repos_src.basic, { src = repos_src.defbranch, name = 'other-name' } })
|
||||
end)
|
||||
|
||||
matches('`basic`:\nInstallation was not confirmed', err)
|
||||
eq(false, exec_lua('return pcall(require, "basic")'))
|
||||
eq(false, exec_lua('return pcall(require, "defbranch")'))
|
||||
|
||||
local confirm_msg = 'These plugins will be installed:\n\n' .. repos_src.basic .. '\n'
|
||||
local ref_log = { { confirm_msg, 'Proceed? &Yes\n&No\n&Always', 1, 'Question' } }
|
||||
local confirm_msg_lines = ([[
|
||||
These plugins will be installed:
|
||||
|
||||
basic from %s
|
||||
other-name from %s]]):format(repos_src.basic, repos_src.defbranch)
|
||||
local confirm_msg = vim.trim(vim.text.indent(0, confirm_msg_lines))
|
||||
local ref_log = { { confirm_msg .. '\n', 'Proceed? &Yes\n&No\n&Always', 1, 'Question' } }
|
||||
eq(ref_log, exec_lua('return _G.confirm_log'))
|
||||
end)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user