feat(pack): allow running update() without Internet connection

Problem: There is now way to run `update()` without Internet connection
  while there are some workflows that do not require it. Like "switch
  plugin version" and "revert latest update".

Solution: Add `opts.offline` to `update()`. This also allows now to
  treat `vim.pack.update(nil, { offline = true })` as a way to
  interactively explore currently installed plugins.
This commit is contained in:
Evgeni Chasnovski
2025-12-26 20:05:12 +02:00
parent 8c28507fcf
commit c9965491d0
4 changed files with 49 additions and 8 deletions

View File

@@ -288,12 +288,18 @@ Another approach is to utilize Git's `insteadOf` configuration:
These sources will be used verbatim in |vim.pack-lockfile|, so reusing the
config on different machine will require the same Git configuration.
Explore installed plugins ~
• `vim.pack.update(nil, { offline = true })`
• Navigate between plugins with `[[` and `]]`. List them with `gO`
(|vim.lsp.buf.document_symbol()|).
Switch plugin's version and/or source ~
• Update 'init.lua' for plugin to have desired `version` and/or `src`. Let's
say, the switch is for plugin named 'plugin1'.
• |:restart|. The plugin's state on disk (revision and/or tracked source) is
not yet changed. Only plugin's `version` in |vim.pack-lockfile| is updated.
• Execute `vim.pack.update({ 'plugin1' })`. The plugin's source is updated.
• Execute `vim.pack.update({ 'plugin1' })`. The plugin's source is updated. If
only switching version, use `{ offline = true }` option table.
• Review changes and either confirm or discard them. If discarded, revert
`version` change in 'init.lua' as well or you will be prompted again next
time you run |vim.pack.update()|.
@@ -315,7 +321,8 @@ Revert plugin after an update ~
locate the revisions before the latest update, and (carefully) adjust
current lockfile to have those revisions.
• |:restart|.
• `vim.pack.update({ 'plugin' }, { target = 'lockfile' })`. Read and confirm.
• `vim.pack.update({ 'plugin' }, { offline = true, target = 'lockfile' })`.
Read and confirm.
Synchronize config across machines ~
• On main machine:
@@ -491,6 +498,8 @@ update({names}, {opts}) *vim.pack.update()*
• {opts} (`table?`) A table with the following fields:
• {force}? (`boolean`) Whether to skip confirmation and make
updates immediately. Default `false`.
• {offline}? (`boolean`) Whether to skip downloading new
updates. Default: `false`.
• {target}? (`string`) How to compute a new plugin revision.
One of:
• "version" (default) - use latest revision matching

View File

@@ -88,6 +88,12 @@
--- These sources will be used verbatim in |vim.pack-lockfile|, so reusing
--- the config on different machine will require the same Git configuration.
---
---Explore installed plugins ~
---
---- `vim.pack.update(nil, { offline = true })`
---- Navigate between plugins with `[[` and `]]`. List them with `gO`
--- (|vim.lsp.buf.document_symbol()|).
---
---Switch plugin's version and/or source ~
---
---- Update 'init.lua' for plugin to have desired `version` and/or `src`.
@@ -95,6 +101,7 @@
---- |:restart|. The plugin's state on disk (revision and/or tracked source)
--- is not yet changed. Only plugin's `version` in |vim.pack-lockfile| is updated.
---- Execute `vim.pack.update({ 'plugin1' })`. The plugin's source is updated.
--- If only switching version, use `{ offline = true }` option table.
---- Review changes and either confirm or discard them. If discarded, revert
--- `version` change in 'init.lua' as well or you will be prompted again next time
--- you run |vim.pack.update()|.
@@ -119,7 +126,8 @@
--- locate the revisions before the latest update, and (carefully) adjust
--- current lockfile to have those revisions.
---- |:restart|.
---- `vim.pack.update({ 'plugin' }, { target = 'lockfile' })`. Read and confirm.
---- `vim.pack.update({ 'plugin' }, { offline = true, target = 'lockfile' })`.
--- Read and confirm.
---
---Synchronize config across machines ~
---
@@ -1152,6 +1160,8 @@ end
--- @inlinedoc
--- @field force? boolean Whether to skip confirmation and make updates immediately. Default `false`.
---
--- @field offline? boolean Whether to skip downloading new updates. Default: `false`.
---
--- How to compute a new plugin revision. One of:
--- - "version" (default) - use latest revision matching `version` from plugin specification.
--- - "lockfile" - use revision from the lockfile. Useful for reverting or performing controlled
@@ -1191,7 +1201,7 @@ end
--- @param opts? vim.pack.keyset.update
function M.update(names, opts)
vim.validate('names', names, vim.islist, true, 'list')
opts = vim.tbl_extend('force', { force = false, target = 'version' }, opts or {})
opts = vim.tbl_extend('force', { force = false, offline = false, target = 'version' }, opts or {})
local plug_list = plug_list_from_names(names)
if #plug_list == 0 then
@@ -1217,7 +1227,7 @@ function M.update(names, opts)
end
-- Fetch
if not opts._offline then
if not opts.offline then
-- Using '--tags --force' means conflicting tags will be synced with remote
local args = { 'fetch', '--quiet', '--tags', '--force', '--recurse-submodules=yes', 'origin' }
git_cmd(args, p.path)
@@ -1237,8 +1247,8 @@ function M.update(names, opts)
trigger_event(p, 'PackChanged', 'update')
end
end
local progress_title = opts.force and (opts._offline and 'Applying updates' or 'Updating')
or 'Downloading updates'
local progress_title = opts.force and (opts.offline and 'Applying updates' or 'Updating')
or (opts.offline and 'Computing updates' or 'Downloading updates')
run_list(plug_list, do_update, progress_title)
if needs_lock_write then

View File

@@ -157,7 +157,7 @@ end
local commands = {
update_plugin = function(plug_data)
vim.pack.update({ plug_data.name }, { force = true, _offline = true })
vim.pack.update({ plug_data.name }, { force = true, offline = true })
end,
skip_update_plugin = function(_) end,
delete_plugin = function(plug_data)

View File

@@ -1765,6 +1765,28 @@ describe('vim.pack', function()
assert_origin(basic_src)
end)
it('can do offline update', function()
local defbranch_path = pack_get_plug_path('defbranch')
local defbranch_lua_file = vim.fs.joinpath(defbranch_path, 'lua', 'defbranch.lua')
n.exec_lua(function()
vim.pack.add({ { src = repos_src.defbranch, version = 'main' } })
end)
track_nvim_echo()
eq('return "defbranch dev"', fn.readblob(defbranch_lua_file))
n.exec_lua(function()
vim.pack.update({ 'defbranch' }, { offline = true })
end)
-- There should be no progress report about downloading updates
assert_progress_report('Computing updates', { 'defbranch' })
n.exec('write')
eq('return "defbranch main"', fn.readblob(defbranch_lua_file))
end)
it('shows progress report', function()
track_nvim_echo()
exec_lua(function()