fix(plugin): merge cond property of import specs

When a spec had an `import` property, the `cond` property was treated
the same as `enabled`; any specs to be imported were ignored and treated
as uninstalled if `cond` evaluated to false. This is inconsistent with
how `cond` behaves in a plugin spec without an `import` property.

To make the behavior consistent when using `import` to manage submodules
of plugin specs, merge the `cond` property of the "parent" spec(s)
containing an `import` property with any `cond` property found on the
imported "child" spec(s), including nested `import` specs. The parent
and child `cond` properties are evaluated and combined with boolean
`and`.

Signed-off-by: Ross Williams <ross@ross-williams.net>
This commit is contained in:
Ross Williams 2025-03-30 03:54:41 -04:00
parent 6c3bda4aca
commit a53c9163f5
No known key found for this signature in database

View file

@ -89,16 +89,52 @@ function Spec:report(level)
return count return count
end end
---@param ... nil|boolean|fun():boolean
---@return nil|boolean|fun():boolean
function Spec.merge_cond(...)
---@type nil|boolean|fun():boolean
local current = select(1, ...)
for i = 2, select("#", ...) do
---@type nil|boolean|fun():boolean
local next = select(i, ...)
if type(current) == "function" or type(next) == "function" then
local previous = current
current = function()
local result = true
if type(previous) == "function" then
result = previous()
elseif type(previous) == "boolean" then
result = previous
end
local next_result = true
if type(next) == "function" then
next_result = next()
elseif type(next) == "boolean" then
next_result = next
end
return result and next_result
end
elseif current == nil then
current = next
else
current = current and next
end
end
return current
end
---@param spec LazySpec|LazySpecImport ---@param spec LazySpec|LazySpecImport
function Spec:normalize(spec) ---@param cond? boolean|fun():boolean
function Spec:normalize(spec, cond)
if type(spec) == "string" then if type(spec) == "string" then
self.meta:add({ spec }) self.meta:add({ spec, cond = cond })
elseif #spec > 1 or Util.is_list(spec) then elseif #spec > 1 or Util.is_list(spec) then
---@cast spec LazySpec[] ---@cast spec LazySpec[]
for _, s in ipairs(spec) do for _, s in ipairs(spec) do
self:normalize(s) self:normalize(s, cond)
end end
elseif spec[1] or spec.dir or spec.url then elseif spec[1] or spec.dir or spec.url then
spec.cond = Spec.merge_cond(spec.cond, cond)
---@cast spec LazyPluginSpec ---@cast spec LazyPluginSpec
self.meta:add(spec) self.meta:add(spec)
---@diagnostic disable-next-line: cast-type-mismatch ---@diagnostic disable-next-line: cast-type-mismatch
@ -107,6 +143,7 @@ function Spec:normalize(spec)
self:import(spec) self:import(spec)
end end
elseif spec.import then elseif spec.import then
spec.cond = Spec.merge_cond(spec.cond, cond)
---@cast spec LazySpecImport ---@cast spec LazySpecImport
self:import(spec) self:import(spec)
else else
@ -133,9 +170,6 @@ function Spec:import(spec)
if vim.tbl_contains(self.modules, import_name) then if vim.tbl_contains(self.modules, import_name) then
return return
end end
if spec.cond == false or (type(spec.cond) == "function" and not spec.cond()) then
return
end
if spec.enabled == false or (type(spec.enabled) == "function" and not spec.enabled()) then if spec.enabled == false or (type(spec.enabled) == "function" and not spec.enabled()) then
return return
end end
@ -191,7 +225,11 @@ function Spec:import(spec)
.. "` was returned instead" .. "` was returned instead"
) )
else else
self:normalize(mod) if spec.cond == false or type(spec.cond) == "function" then
self:normalize(mod, spec.cond)
else
self:normalize(mod)
end
end end
end, { end, {
msg = "Failed to load `" .. modname .. "`", msg = "Failed to load `" .. modname .. "`",