From 1ee18b40611487e50abbec425d74d3af7de7897d Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Tue, 29 Jul 2025 16:00:03 +0300 Subject: fix(pack): use 'coxpcall.lua' on non-LuaJIT Problem: `attempt to yield across metamethod/C-call boundary` error when trying to use `vim.pack.add()`. Solution: use `pcall()` variant from 'coxpcall' on non-LuaJIT version of Lua. --- runtime/lua/vim/_async.lua | 3 ++- runtime/lua/vim/pack.lua | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_async.lua b/runtime/lua/vim/_async.lua index 8abe206a51..47f37b675b 100644 --- a/runtime/lua/vim/_async.lua +++ b/runtime/lua/vim/_async.lua @@ -1,6 +1,7 @@ local M = {} local max_timeout = 30000 +local copcall = package.loaded.jit and pcall or require('coxpcall').pcall --- @param thread thread --- @param on_finish fun(err: string?, ...:any) @@ -21,7 +22,7 @@ local function resume(thread, on_finish, ...) --- @cast fn -string --- @type boolean, string? - local ok, err = pcall(fn, function(...) + local ok, err = copcall(fn, function(...) resume(thread, on_finish, ...) end) diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index cf5dc00d01..210e01b9e6 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -374,6 +374,7 @@ local function new_progress_report(title) end local n_threads = 2 * #(uv.cpu_info() or { {} }) +local copcall = package.loaded.jit and pcall or require('coxpcall').pcall --- Execute function in parallel for each non-errored plugin in the list --- @param plug_list vim.pack.Plug[] @@ -390,7 +391,7 @@ local function run_list(plug_list, f, progress_title) if p.info.err == '' then --- @async funs[#funs + 1] = function() - local ok, err = pcall(f, p) --[[@as string]] + local ok, err = copcall(f, p) --[[@as string]] if not ok then p.info.err = err --- @as string end @@ -458,7 +459,7 @@ local function resolve_version(p) local tags = git_get_tags(p.path) if type(version) == 'string' then local is_branch = vim.tbl_contains(branches, version) - local is_tag_or_hash = pcall(git_get_hash, version, p.path) + local is_tag_or_hash = copcall(git_get_hash, version, p.path) if not (is_branch or is_tag_or_hash) then local err = ('`%s` is not a branch/tag/commit. Available:'):format(version) .. list_in_line('Tags', tags) @@ -529,7 +530,7 @@ local function checkout(p, timestamp, skip_same_sha) -- directory or if it is empty. local doc_dir = vim.fs.joinpath(p.path, 'doc') vim.fn.delete(vim.fs.joinpath(doc_dir, 'tags')) - pcall(vim.cmd.helptags, vim.fn.fnameescape(doc_dir)) + copcall(vim.cmd.helptags, vim.fn.fnameescape(doc_dir)) end --- @param plug_list vim.pack.Plug[] -- cgit From 28e2a5c1513dd3adb6fc085a92f66bf7d7786317 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Tue, 29 Jul 2025 16:06:01 +0300 Subject: fix(pack): improve `vim.pack.add()` input validation --- runtime/lua/vim/pack.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index 210e01b9e6..0a0635b6e0 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -209,7 +209,11 @@ end --- @param x string|vim.VersionRange --- @return boolean local function is_version(x) - return type(x) == 'string' or (pcall(x.has, x, '1')) + return type(x) == 'string' or (type(x) == 'table' and pcall(x.has, x, '1')) +end + +local function is_nonempty_string(x) + return type(x) == 'string' and x ~= '' end --- @return string @@ -239,9 +243,10 @@ end local function normalize_spec(spec) spec = type(spec) == 'string' and { src = spec } or spec vim.validate('spec', spec, 'table') - vim.validate('spec.src', spec.src, 'string') - local name = (spec.name or spec.src:gsub('%.git$', '')):match('[^/]+$') - vim.validate('spec.name', name, 'string') + vim.validate('spec.src', spec.src, is_nonempty_string, false, 'non-empty string') + local name = spec.name or spec.src:gsub('%.git$', '') + name = (type(name) == 'string' and name or ''):match('[^/]+$') or '' + vim.validate('spec.name', name, is_nonempty_string, true, 'non-empty string') vim.validate('spec.version', spec.version, is_version, true, 'string or vim.VersionRange') return { src = spec.src, name = name, version = spec.version } end -- cgit From 3f34f083db0694032477c8fa6a1ca85c52d59bec Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Tue, 29 Jul 2025 16:06:40 +0300 Subject: fix(pack): ignore 'loadplugins' when sourcing 'after/plugin' scripts Problem: Sourcing of 'after/plugin' scripts depends on the value of 'loadplugins' option. It is redundant, as it has effect only during startup, while it is combined with `vim.v.vim_did_enter == 1` (i.e. "it is after starting up") condition. Solution: Ignore it. --- runtime/lua/vim/pack.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index 0a0635b6e0..879be4b97d 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -626,8 +626,7 @@ local function pack_add(plug, load) -- automatically), as `:packadd` only sources plain 'plugin/' files. -- See https://github.com/vim/vim/issues/15584 -- Deliberately do so after executing all currently known 'plugin/' files. - local should_load_after_dir = vim.v.vim_did_enter == 1 and load and vim.o.loadplugins - if should_load_after_dir then + if vim.v.vim_did_enter == 1 and load then local after_paths = vim.fn.glob(plug.path .. '/after/plugin/**/*.{vim,lua}', false, true) --- @param path string vim.tbl_map(function(path) -- cgit From a203961535057ca335b8a02b65c032a287bba37a Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Tue, 29 Jul 2025 16:16:40 +0300 Subject: feat(pack): use colored `nvim_echo` chunks to show progress report Problem: using `print()` to show progress report writes to `stdout` when in `--headless` mode (interferes with the testing output) and doesn't allow coloring. Solution: use `nvim_echo` with colored chunks. --- runtime/lua/vim/pack.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index 879be4b97d..7d83921763 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -372,7 +372,9 @@ local function new_progress_report(title) return vim.schedule_wrap(function(kind, percent, fmt, ...) local progress = kind == 'end' and 'done' or ('%3d%%'):format(percent) - print(('(vim.pack) %s: %s %s'):format(progress, title, fmt:format(...))) + local details = (': %s %s'):format(title, fmt:format(...)) + local chunks = { { '(vim.pack)', 'ModeMsg' }, { ' ' }, { progress, 'WarningMsg' }, { details } } + vim.api.nvim_echo(chunks, true, { kind = 'progress' }) -- Force redraw to show installation progress during startup vim.cmd.redraw({ bang = true }) end) -- cgit From 267bbe64cb4fc1e5d3055307d11872f948a4e44f Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Tue, 29 Jul 2025 20:15:58 +0300 Subject: fix(pack): validate installed plugins in `update()` and `del()` Problem: Currently `update()` and `del()` silently ignore input plugin names that are not for already installed plugin. This might lead to confusion because they are not explicitly reported. Solution: Check that all input names are for installed plugins and error otherwise. --- runtime/lua/vim/pack.lua | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index 7d83921763..3693fbe5b1 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -324,6 +324,7 @@ end local function plug_list_from_names(names) local all_plugins = M.get() local plugs = {} --- @type vim.pack.Plug[] + local used_names = {} --- @type table -- 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 @@ -333,9 +334,18 @@ local function plug_list_from_names(names) --- @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) + used_names[p_data.spec.name] = true 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 end @@ -878,11 +888,6 @@ function M.update(names, opts) --- @async --- @param p vim.pack.Plug local function do_update(p) - if not p.info.installed then - notify(('Cannot update %s - not found'):format(p.spec.name), 'WARN') - return - end - -- Fetch -- Using '--tags --force' means conflicting tags will be synced with remote git_cmd( @@ -945,17 +950,13 @@ function M.del(names) end for _, p in ipairs(plug_list) do - if not p.info.installed then - notify(("Plugin '%s' is not installed"):format(p.spec.name), 'WARN') - else - trigger_event(p, 'PackChangedPre', 'delete') + trigger_event(p, 'PackChangedPre', 'delete') - vim.fs.rm(p.path, { recursive = true, force = true }) - active_plugins[p.path] = nil - notify(("Removed plugin '%s'"):format(p.spec.name), 'INFO') + vim.fs.rm(p.path, { recursive = true, force = true }) + active_plugins[p.path] = nil + notify(("Removed plugin '%s'"):format(p.spec.name), 'INFO') - trigger_event(p, 'PackChanged', 'delete') - end + trigger_event(p, 'PackChanged', 'delete') end end -- cgit From 8200223ee7a8dd9882367582c4a6e1d280012fff Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 2 Aug 2025 14:57:59 +0300 Subject: fix(pack): use `vim.pack:` as message/progress prefix --- runtime/lua/vim/pack.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index 3693fbe5b1..c75f185de3 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -202,7 +202,7 @@ end --- @param level ('DEBUG'|'TRACE'|'INFO'|'WARN'|'ERROR')? local function notify(msg, level) msg = type(msg) == 'table' and table.concat(msg, '\n') or msg - vim.notify('(vim.pack) ' .. msg, vim.log.levels[level or 'INFO']) + vim.notify('vim.pack: ' .. msg, vim.log.levels[level or 'INFO']) vim.cmd.redraw() end @@ -382,8 +382,8 @@ local function new_progress_report(title) return vim.schedule_wrap(function(kind, percent, fmt, ...) local progress = kind == 'end' and 'done' or ('%3d%%'):format(percent) - local details = (': %s %s'):format(title, fmt:format(...)) - local chunks = { { '(vim.pack)', 'ModeMsg' }, { ' ' }, { progress, 'WarningMsg' }, { details } } + local details = (' %s %s'):format(title, fmt:format(...)) + local chunks = { { 'vim.pack', 'ModeMsg' }, { ': ' }, { progress, 'WarningMsg' }, { details } } vim.api.nvim_echo(chunks, true, { kind = 'progress' }) -- Force redraw to show installation progress during startup vim.cmd.redraw({ bang = true }) @@ -535,7 +535,7 @@ local function checkout(p, timestamp, skip_same_sha) trigger_event(p, 'PackChangedPre', 'update') - local msg = ('(vim.pack) %s Stash before checkout'):format(timestamp) + local msg = ('vim.pack: %s Stash before checkout'):format(timestamp) git_cmd({ 'stash', '--quiet', '--message', msg }, p.path) git_cmd({ 'checkout', '--quiet', p.info.sha_target }, p.path) -- cgit From ed73ed82837455ad5dae6d6917a20c3679016343 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 2 Aug 2025 14:58:03 +0300 Subject: fix(pack): ensure explicit default `version` in events (where possible) Problem: Both `PackChangedPre` and `PackChanged` contain |event-data| with plugin's `spec`. It looks like a good idea to have all its triggers contain the same format across all kinds ("install", "update", "delete"). There are several choices: - Have it be as verbatim as supplied to `vim.pack.add()`, i.e. can be either string or table. A bit too ambiguous. - Have it be table with `src` and `name` inferred. This requires less work for "install", but more work for "update" and "delete" (since they use `vim.pack.get()` which already infers default `version`). - Have it be table with *all* defaults made explicit. This looks like the best approach, but requires extra care to only infer default `version` when needed (i.e. avoid inferring during regular load) because it is costly in terms of startup time. This might also introduce inconsistency when dealing with lockfile(s) as information there should be as close to what user supplied as possible. Address that when dealing with lockfile. Solution: Ensure explicit `version` in all events where possible. --- runtime/lua/vim/pack.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index c75f185de3..78945e3950 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -88,7 +88,7 @@ --- Each event populates the following |event-data| fields: --- - `kind` - one of "install" (install on disk), "update" (update existing --- plugin), "delete" (delete from disk). ---- - `spec` - plugin's specification. +--- - `spec` - plugin's specification with defaults made explicit. --- - `path` - full path to plugin's directory. local api = vim.api @@ -569,6 +569,9 @@ local function install_list(plug_list) git_clone(p.spec.src, p.path) p.info.installed = true + -- Infer default branch for fuller `event-data` + p.spec.version = p.spec.version or git_get_default_branch(p.path) + -- Do not skip checkout even if HEAD and target have same commit hash to -- have new repo in expected detached HEAD state and generated help files. checkout(p, timestamp, false) -- cgit From 6721128cc8341b9519a1b46eb8932524613cf7ed Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 2 Aug 2025 14:59:47 +0300 Subject: refactor(pack): use `vim.cmd` methods with structured input --- runtime/lua/vim/pack.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index 78945e3950..7ebd9b21e8 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -547,7 +547,7 @@ local function checkout(p, timestamp, skip_same_sha) -- directory or if it is empty. local doc_dir = vim.fs.joinpath(p.path, 'doc') vim.fn.delete(vim.fs.joinpath(doc_dir, 'tags')) - copcall(vim.cmd.helptags, vim.fn.fnameescape(doc_dir)) + copcall(vim.cmd.helptags, { doc_dir, magic = { file = false } }) end --- @param plug_list vim.pack.Plug[] @@ -635,7 +635,8 @@ local function pack_add(plug, load) n_active_plugins = n_active_plugins + 1 active_plugins[plug.path] = { plug = plug, id = n_active_plugins } - vim.cmd.packadd({ plug.spec.name, bang = not load }) + -- NOTE: The `:packadd` specifically seems to not handle spaces in dir name + vim.cmd.packadd({ vim.fn.escape(plug.spec.name, ' '), bang = not load, magic = { file = false } }) -- Execute 'after/' scripts if not during startup (when they will be sourced -- automatically), as `:packadd` only sources plain 'plugin/' files. @@ -645,7 +646,7 @@ local function pack_add(plug, load) local after_paths = vim.fn.glob(plug.path .. '/after/plugin/**/*.{vim,lua}', false, true) --- @param path string vim.tbl_map(function(path) - vim.cmd.source(vim.fn.fnameescape(path)) + vim.cmd.source({ path, magic = { file = false } }) end, after_paths) end end -- cgit From 89a72f11e5fe8c06a2b8e8ae994359d3316ee576 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 2 Aug 2025 14:58:13 +0300 Subject: fix(pack): make newer version suggestions more robust Problem: New version suggestions in update confirmation buffer might include semver tags that were committed later but for versions that are not greater than current. Like if versions committed in order `v0.2.0` - `v0.3.0` - `v0.2.1` - `v0.3.1`, then when on `v0.3.0` both `v0.2.1` and `v0.3.1` are suggested, but only the latter is newer as a version. This is because those tags are computed with post-processed `git tag --list --contains HEAD`. Solution: Compute all semver tags and filter only those greater than the latest version available at HEAD. --- runtime/lua/vim/pack.lua | 76 ++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 31 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index 7ebd9b21e8..db3777103f 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -178,16 +178,9 @@ end --- @async --- @param cwd string ---- @param opts? { contains?: string, points_at?: string } --- @return string[] -local function git_get_tags(cwd, opts) +local function git_get_tags(cwd) local cmd = { 'tag', '--list', '--sort=-v:refname' } - if opts and opts.contains then - vim.list_extend(cmd, { '--contains', opts.contains }) - end - if opts and opts.points_at then - vim.list_extend(cmd, { '--points-at', opts.points_at }) - end return vim.split(git_cmd(cmd, cwd), '\n') end @@ -212,6 +205,12 @@ local function is_version(x) return type(x) == 'string' or (type(x) == 'table' and pcall(x.has, x, '1')) end +--- @param x string +--- @return boolean +local function is_semver(x) + return vim.version.parse(x) ~= nil +end + local function is_nonempty_string(x) return type(x) == 'string' and x ~= '' end @@ -451,6 +450,21 @@ local function confirm_install(plug_list) return res end +--- @param tags string[] +--- @param version_range vim.VersionRange +local function get_last_semver_tag(tags, version_range) + local last_tag, last_ver_tag --- @type string, vim.Version + for _, tag in ipairs(tags) do + local ver_tag = vim.version.parse(tag) + if ver_tag then + if version_range:has(ver_tag) and (not last_ver_tag or ver_tag > last_ver_tag) then + last_tag, last_ver_tag = tag, ver_tag + end + end + end + return last_tag +end + --- @async --- @param p vim.pack.Plug local function resolve_version(p) @@ -491,19 +505,10 @@ local function resolve_version(p) --- @cast version vim.VersionRange -- Choose the greatest/last version among all matching semver tags - local last_ver_tag --- @type vim.Version - local semver_tags = {} --- @type string[] - for _, tag in ipairs(tags) do - local ver_tag = vim.version.parse(tag) - if ver_tag then - semver_tags[#semver_tags + 1] = tag - if version:has(ver_tag) and (not last_ver_tag or ver_tag > last_ver_tag) then - p.info.version_str, last_ver_tag = tag, ver_tag - end - end - end - + p.info.version_str = get_last_semver_tag(tags, version) if p.info.version_str == nil then + local semver_tags = vim.tbl_filter(is_semver, tags) + table.sort(semver_tags, vim.version.gt) local err = 'No versions fit constraint. Relax it or switch to branch. Available:' .. list_in_line('Versions', semver_tags) .. list_in_line('Branches', branches) @@ -590,6 +595,7 @@ local function infer_update_details(p) local sha_head = assert(p.info.sha_head) local sha_target = assert(p.info.sha_target) + -- Try showing log of changes (if any) if sha_head ~= sha_target then -- `--topo-order` makes showing divergent branches nicer -- `--decorate-refs` shows only tags near commits (not `origin/main`, etc.) @@ -600,21 +606,29 @@ local function infer_update_details(p) '--decorate-refs=refs/tags', sha_head .. '...' .. sha_target, }, p.path) - else - p.info.update_details = table.concat(git_get_tags(p.path, { contains = sha_target }), '\n') + return end - if p.info.sha_head ~= p.info.sha_target or p.info.update_details == '' then + -- Suggest newer semver tags (i.e. greater than greatest past semver tag) + local all_semver_tags = vim.tbl_filter(is_semver, git_get_tags(p.path)) + if #all_semver_tags == 0 then return end - -- Remove tags pointing at target (there might be several) - local cur_tags = git_get_tags(p.path, { points_at = sha_target }) - local new_tags_arr = vim.split(p.info.update_details, '\n') - local function is_not_cur_tag(s) - return not vim.tbl_contains(cur_tags, s) - end - p.info.update_details = table.concat(vim.tbl_filter(is_not_cur_tag, new_tags_arr), '\n') + local older_tags = git_cmd({ 'tag', '--list', '--no-contains', sha_head }, p.path) + local cur_tags = git_cmd({ 'tag', '--list', '--points-at', sha_head }, p.path) + local past_tags = vim.split(older_tags, '\n') + vim.list_extend(past_tags, vim.split(cur_tags, '\n')) + + local any_version = vim.version.range('*') --[[@as vim.VersionRange]] + local last_version = get_last_semver_tag(past_tags, any_version) + + local newer_semver_tags = vim.tbl_filter(function(x) --- @param x string + return vim.version.gt(x, last_version) + end, all_semver_tags) + + table.sort(newer_semver_tags, vim.version.gt) + p.info.update_details = table.concat(newer_semver_tags, '\n') end --- Map from plugin path to its data. @@ -735,7 +749,7 @@ local function compute_feedback_lines_single(p) if p.info.update_details ~= '' then local details = p.info.update_details:gsub('\n', '\n• ') - parts[#parts + 1] = '\n\nAvailable newer tags:\n• ' .. details + parts[#parts + 1] = '\n\nAvailable newer versions:\n• ' .. details end else parts[#parts + 1] = table.concat({ -- cgit From d3bea4ace94a16e75f7dfe609fba0ae9e5775308 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 2 Aug 2025 14:58:17 +0300 Subject: fix(pack): ensure consistent order of changelog during update Problem: Left (`<` prefix) and right (`>` prefix) parts of update changelog come in not fixed order: it can be left-right or right-left. Solution: Ensure left-right order. --- runtime/lua/vim/pack.lua | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index db3777103f..d793b36a0e 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -591,21 +591,23 @@ end --- @async --- @param p vim.pack.Plug local function infer_update_details(p) + p.info.update_details = '' infer_states(p) local sha_head = assert(p.info.sha_head) local sha_target = assert(p.info.sha_target) -- Try showing log of changes (if any) if sha_head ~= sha_target then - -- `--topo-order` makes showing divergent branches nicer - -- `--decorate-refs` shows only tags near commits (not `origin/main`, etc.) - p.info.update_details = git_cmd({ - 'log', - '--pretty=format:%m %h │ %s%d', - '--topo-order', - '--decorate-refs=refs/tags', - sha_head .. '...' .. sha_target, - }, p.path) + local range = sha_head .. '...' .. sha_target + local format = '--pretty=format:%m %h │ %s%d' + -- Show only tags near commits (not `origin/main`, etc.) + local decorate = '--decorate-refs=refs/tags' + -- `--topo-order` makes showing divergent branches nicer, but by itself + -- doesn't ensure that reverted ("left", shown with `<`) and added + -- ("right", shown with `>`) commits have fixed order. + local l = git_cmd({ 'log', format, '--topo-order', '--left-only', decorate, range }, p.path) + local r = git_cmd({ 'log', format, '--topo-order', '--right-only', decorate, range }, p.path) + p.info.update_details = l == '' and r or (r == '' and l or (l .. '\n' .. r)) return end -- cgit From 2e62f3576f7f0e7844e3fef2792503c7e10c1801 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 2 Aug 2025 14:58:20 +0300 Subject: fix(pack): open confirmation buffer in tabpage after the current one --- runtime/lua/vim/pack.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index d793b36a0e..200f08e311 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -819,7 +819,7 @@ local function show_confirm_buf(lines, on_finish) local bufnr = api.nvim_create_buf(true, true) api.nvim_buf_set_name(bufnr, 'nvim-pack://' .. bufnr .. '/confirm-update') api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) - vim.cmd.sbuffer({ bufnr, mods = { tab = vim.fn.tabpagenr('#') } }) + vim.cmd.sbuffer({ bufnr, mods = { tab = vim.fn.tabpagenr() } }) local tab_id = api.nvim_get_current_tabpage() local win_id = api.nvim_get_current_win() -- cgit