From 8d100483e0662916cd30e99ceb7216532c58f903 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sun, 17 May 2026 10:49:48 +0300 Subject: feat(pack): update `get()` to take `rev` from actual repo if `info=true` Problem: `vim.pack.get()` always uses lockfile as the source for the `rev` field. This is fast, but may be misleading in case of a corrupted lockfile. Solution: Compute revision from Git repo on disk if `info=true` (default), use lockfile otherwise. This does increase execution time (as a result of one extra `git ...` call for every plugin), but `info=true` is already designed to be informative and not necessarily fast. --- runtime/lua/vim/pack.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/pack.lua') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index bd693904cd..655d6f14d6 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -1434,7 +1434,7 @@ end --- @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. +--- @field rev string Current Git revision. Taken from |vim.pack-lockfile| 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`. @@ -1450,6 +1450,7 @@ local function add_p_data_info(p_data_list) --- @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 -- cgit From b9c4329c35552a5be71f99899528699018b2562c Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sun, 17 May 2026 10:51:09 +0300 Subject: feat(pack): update `get()` to return revision of a pending update Problem: No convenient way to programmatically get the revision that would be checked out after `vim.pack.update()` (with `offline=true`). Doing this manually requires resolving `spec.version` which is not trivial. This data can be useful for custom reporting of pending updates or third party confirmation step. Solution: Make `get()` include a new field for the revision that points at the state after applying pending update. This is also the same as the revision of resolved `spec.version`. --- runtime/lua/vim/pack.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/pack.lua') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index 655d6f14d6..7eddacc3e2 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -1435,6 +1435,9 @@ end --- @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. Taken from |vim.pack-lockfile| if `info=false`. +--- Git revision of a pending update. The same as used during |vim.pack.update()| and which +--- points to a resolved `spec.version`. Missing if `info=false`. +--- @field rev_to? string --- @field spec vim.pack.SpecResolved A |vim.pack.Spec| with resolved `name`. --- @field tags? string[] Available Git tags. Missing if `info=false`. @@ -1445,13 +1448,18 @@ end --- @param p_data_list vim.pack.PlugData[] local function add_p_data_info(p_data_list) local funs = {} --- @type (async fun())[] + local plug_dir = get_plug_dir() for i, p_data in ipairs(p_data_list) do + local plug = new_plug(p_data.spec, plug_dir) 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) + + infer_revisions(plug) + p_data.rev = plug.info.sha_head + p_data.rev_to = plug.info.sha_target end end async_join_run_wait(funs) -- cgit From 8f379be2619a7d6d25c102937e8425fdc952b1ab Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sun, 17 May 2026 10:52:19 +0300 Subject: feat(pack): update `get()` to be able to fetch data from plugin source Problem: There is currently no convenient way to programmatically check for new updates from plugin source. Running `vim.pack.update()` is one approach, but it opens a confirmation buffer that requires a manual action to close. Solution: Add `opts.offline` to `vim.pack.get()` that will first fetch new updates from plugin source before computing the output. --- runtime/lua/vim/pack.lua | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'runtime/lua/vim/pack.lua') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index 7eddacc3e2..0d2472d082 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -156,6 +156,12 @@ ---- Use |:packdel| with plugin names to remove. Use `:packdel ++all` to delete --- all inactive plugins. --- +---Check for pending updates ~ +--- +---- Run `vim.pack.get(nil, { offline = false })` and check the output for items +--- with different `rev` and `rev_to` fields. To not download new updates +--- from source, use plain `vim.pack.get()`. +--- ---
help
 --- Commands                                             *vim.pack-commands* *E5807*
 ---
@@ -317,6 +323,14 @@ local function git_get_hash(ref, cwd)
   return git_cmd({ 'rev-list', '-1', ref }, cwd)
 end
 
+--- @async
+--- @param cwd string
+local function git_fetch(cwd)
+  -- Using '--tags --force' means conflicting tags will be synced with remote
+  local args = { 'fetch', '--quiet', '--tags', '--force', '--recurse-submodules=yes', 'origin' }
+  git_cmd(args, cwd)
+end
+
 --- @async
 --- @param cwd string
 --- @return string
@@ -1313,9 +1327,7 @@ function M.update(names, opts)
 
     -- Fetch
     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)
+      git_fetch(p.path)
     end
 
     -- Compute change info: changelog if any, new tags if nothing to update
@@ -1443,10 +1455,13 @@ end
 
 --- @class vim.pack.keyset.get
 --- @inlinedoc
---- @field info boolean Whether to include extra plugin info. Default `true`.
+--- @field info? boolean Whether to include extra plugin info. Default `true`.
+--- Whether to skip downloading new updates. Requires `info=true`. Default: `true`.
+--- @field offline? boolean
 
 --- @param p_data_list vim.pack.PlugData[]
-local function add_p_data_info(p_data_list)
+--- @param offline boolean
+local function add_p_data_info(p_data_list, offline)
   local funs = {} --- @type (async fun())[]
   local plug_dir = get_plug_dir()
   for i, p_data in ipairs(p_data_list) do
@@ -1457,6 +1472,10 @@ local function add_p_data_info(p_data_list)
       p_data.branches = git_get_branches(path)
       p_data.tags = git_get_tags(path)
 
+      if not offline then
+        git_fetch(path)
+      end
+
       infer_revisions(plug)
       p_data.rev = plug.info.sha_head
       p_data.rev_to = plug.info.sha_target
@@ -1471,7 +1490,7 @@ end
 --- @return vim.pack.PlugData[]
 function M.get(names, opts)
   vim.validate('names', names, vim.islist, true, 'list')
-  opts = vim.tbl_extend('force', { info = true }, opts or {})
+  opts = vim.tbl_extend('force', { info = true, offline = true }, opts or {})
 
   -- Process active plugins in order they were added. Take into account that
   -- there might be "holes" after `vim.pack.del()`.
@@ -1520,7 +1539,7 @@ function M.get(names, opts)
 
   if opts.info then
     git_ensure_exec()
-    add_p_data_info(res)
+    add_p_data_info(res, opts.offline)
   end
 
   return res
-- 
cgit