From c522cb0e96dad3bf3a834df5c6a8988f5c13a1a3 Mon Sep 17 00:00:00 2001 From: Birdee <85372418+BirdeeHub@users.noreply.github.com> Date: Thu, 21 Aug 2025 10:08:29 -0700 Subject: [PATCH] feat(pack): support user-defined `data` in plugin spec #35360 Problem: The load function in opts was difficult to use if you wished to customize based on the plugin being loaded. You could get the name, but without some way to mark a spec, that was of limited usefulness unless you wanted to hardcode a list of names in the function, or write a wrapper around the whole thing Solution: Allow users to provide an arbitrary data field in plugin specs so that they may receive info as to how to handle that plugin in load, get() and events, and act upon it Co-authored-by: BirdeeHub Co-authored-by: Evgeni Chasnovski --- runtime/doc/pack.txt | 1 + runtime/lua/vim/pack.lua | 6 ++-- test/functional/plugin/pack_spec.lua | 45 ++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/runtime/doc/pack.txt b/runtime/doc/pack.txt index a3b479c54e..29482354af 100644 --- a/runtime/doc/pack.txt +++ b/runtime/doc/pack.txt @@ -309,6 +309,7 @@ Each event populates the following |event-data| fields: • String to use specific branch, tag, or commit hash. • Output of |vim.version.range()| to install the greatest/last semver tag inside the version constraint. + • {data}? (`any`) Arbitrary data associated with a plugin. add({specs}, {opts}) *vim.pack.add()* diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index da4456d399..3b6d9c92ae 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -234,8 +234,10 @@ end --- - Output of |vim.version.range()| to install the greatest/last semver tag --- inside the version constraint. --- @field version? string|vim.VersionRange +--- +--- @field data? any Arbitrary data associated with a plugin. ---- @alias vim.pack.SpecResolved { src: string, name: string, version: nil|string|vim.VersionRange } +--- @alias vim.pack.SpecResolved { src: string, name: string, version: nil|string|vim.VersionRange, data: any|nil } --- @param spec string|vim.pack.Spec --- @return vim.pack.SpecResolved @@ -247,7 +249,7 @@ local function normalize_spec(spec) 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 } + return { src = spec.src, name = name, version = spec.version, data = spec.data } end --- @class (private) vim.pack.PlugInfo diff --git a/test/functional/plugin/pack_spec.lua b/test/functional/plugin/pack_spec.lua index 165afa1f49..6029e84f30 100644 --- a/test/functional/plugin/pack_spec.lua +++ b/test/functional/plugin/pack_spec.lua @@ -311,6 +311,34 @@ describe('vim.pack', function() eq(exec_lua('return #_G.event_log'), 0) end) + it('passes data field through to opts.load', function() + eq( + 2, + exec_lua(function() + local successes = 0 + vim.pack.add({ + { name = 'tabletest', src = repos_src.basic, data = { test = 'value' } }, + { name = 'stringtest', src = repos_src.basic, data = 'value' }, + }, { + confirm = false, + load = function(p) + if p.spec.name == 'tabletest' then + if p.spec.data.test == 'value' then + successes = successes + 1 + end + end + if p.spec.name == 'stringtest' then + if p.spec.data == 'value' then + successes = successes + 1 + end + end + end, + }) + return successes + end) + ) + end) + it('asks for installation confirmation', function() exec_lua(function() ---@diagnostic disable-next-line: duplicate-set-field @@ -1179,6 +1207,23 @@ describe('vim.pack', function() }, exec_lua('return vim.pack.get()')) end) + it('respects data field', function() + eq( + true, + exec_lua(function() + vim.pack.add { + { src = repos_src.basic, data = { test = 'value' } }, + } + for _, p in ipairs(vim.pack.get()) do + if p.spec.name == 'basic' and p.spec.data.test == 'value' then + return true + end + end + return false + end) + ) + end) + it('works with `del()`', function() exec_lua(function() vim.pack.add({ repos_src.defbranch, repos_src.basic })