feat(plugins): Given an optional plugin, conditionally discard deps (#947)

* deps_of_all_optional: First, refactor the code responsible for disabling unneeded deps to be more generic

* deps_of_all_optional: Second, also disable unneeded deps from plugins marked as all optional

* deps_of_all_optional: add tests proving unneeded optional deps are now also discarded

* deps_of_all_optional: forgot return type

---------

Co-authored-by: abeldekat <abel@nomail.com>
This commit is contained in:
abeldekat 2023-07-22 08:20:52 +00:00 committed by GitHub
parent af4d24b8d0
commit e7334d8db5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 24 deletions

View File

@ -146,6 +146,31 @@ function Spec:warn(msg)
self:log(msg, vim.log.levels.WARN) self:log(msg, vim.log.levels.WARN)
end end
---@param gathered_deps string[]
---@param dep_of table<string,string[]>
---@param on_disable fun(string):nil
function Spec:fix_dependencies(gathered_deps, dep_of, on_disable)
local function should_disable(dep_name)
for _, parent in ipairs(dep_of[dep_name] or {}) do
if self.plugins[parent] then
return false
end
end
return true
end
for _, dep_name in ipairs(gathered_deps) do
-- only check if the plugin is still enabled and it is a dep
if self.plugins[dep_name] and self.plugins[dep_name]._.dep then
-- check if the dep is still used by another plugin
if should_disable(dep_name) then
-- disable the dep when no longer needed
on_disable(dep_name)
end
end
end
end
function Spec:fix_cond() function Spec:fix_cond()
for _, plugin in pairs(self.plugins) do for _, plugin in pairs(self.plugins) do
local cond = plugin.cond local cond = plugin.cond
@ -159,7 +184,9 @@ function Spec:fix_cond()
end end
end end
---@return string[]
function Spec:fix_optional() function Spec:fix_optional()
local all_optional_deps = {}
if not self.optional then if not self.optional then
---@param plugin LazyPlugin ---@param plugin LazyPlugin
local function all_optional(plugin) local function all_optional(plugin)
@ -170,10 +197,14 @@ function Spec:fix_optional()
for _, plugin in pairs(self.plugins) do for _, plugin in pairs(self.plugins) do
if plugin.optional and all_optional(plugin) then if plugin.optional and all_optional(plugin) then
self.plugins[plugin.name] = nil self.plugins[plugin.name] = nil
if plugin.dependencies then
vim.list_extend(all_optional_deps, plugin.dependencies)
end end
end end
end end
end end
return all_optional_deps
end
function Spec:fix_disabled() function Spec:fix_disabled()
for _, plugin in pairs(self.plugins) do for _, plugin in pairs(self.plugins) do
@ -183,15 +214,16 @@ function Spec:fix_disabled()
end end
end end
self:fix_optional()
self:fix_cond()
---@type table<string,string[]> plugin to parent plugin ---@type table<string,string[]> plugin to parent plugin
local dep_of = {} local dep_of = {}
---@type string[] dependencies of disabled plugins ---@type string[] dependencies of disabled plugins
local disabled_deps = {} local disabled_deps = {}
---@type string[] dependencies of plugins that are completely optional
local all_optional_deps = self:fix_optional()
self:fix_cond()
for _, plugin in pairs(self.plugins) do for _, plugin in pairs(self.plugins) do
local enabled = not (plugin.enabled == false or (type(plugin.enabled) == "function" and not plugin.enabled())) local enabled = not (plugin.enabled == false or (type(plugin.enabled) == "function" and not plugin.enabled()))
if enabled then if enabled then
@ -209,27 +241,17 @@ function Spec:fix_disabled()
end end
end end
-- check deps of disabled plugins -- fix deps of plugins that are completely optional
for _, dep in ipairs(disabled_deps) do self:fix_dependencies(all_optional_deps, dep_of, function(dep_name)
-- only check if the plugin is still enabled and it is a dep self.plugins[dep_name] = nil
if self.plugins[dep] and self.plugins[dep]._.dep then end)
-- check if the dep is still used by another plugin -- fix deps of disabled plugins
local keep = false self:fix_dependencies(disabled_deps, dep_of, function(dep_name)
for _, parent in ipairs(dep_of[dep] or {}) do local plugin = self.plugins[dep_name]
if self.plugins[parent] then
keep = true
break
end
end
-- disable the dep when no longer needed
if not keep then
local plugin = self.plugins[dep]
plugin._.kind = "disabled" plugin._.kind = "disabled"
self.plugins[plugin.name] = nil self.plugins[plugin.name] = nil
self.disabled[plugin.name] = plugin self.disabled[plugin.name] = plugin
end end)
end
end
end end
---@param msg string ---@param msg string

View File

@ -273,6 +273,25 @@ describe("plugin spec opt", function()
end end
end end
end) end)
it("handles the optional keyword", function()
local tests = {
[{ { "foo/bax" }, { "foo/bar", optional = true, dependencies = "foo/dep1" } }] = false,
[{ { "foo/bax", dependencies = "foo/dep1" }, { "foo/bar", optional = true, dependencies = "foo/dep1" } }] = true,
}
for test, ret in pairs(tests) do
local spec = Plugin.Spec.new(test)
assert(#spec.notifs == 0)
assert(spec.plugins.bax)
assert(not spec.plugins.bar)
assert(#spec.disabled == 0)
if ret then
assert(spec.plugins.dep1)
else
assert(not spec.plugins.opt1)
end
end
end)
end) end)
describe("plugin opts", function() describe("plugin opts", function()