Skip to content

Commit e7334d8

Browse files
abeldekatabeldekat
and
abeldekat
authored
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 <[email protected]>
1 parent af4d24b commit e7334d8

File tree

2 files changed

+65
-24
lines changed

2 files changed

+65
-24
lines changed

lua/lazy/core/plugin.lua

+46-24
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,31 @@ function Spec:warn(msg)
146146
self:log(msg, vim.log.levels.WARN)
147147
end
148148

149+
---@param gathered_deps string[]
150+
---@param dep_of table<string,string[]>
151+
---@param on_disable fun(string):nil
152+
function Spec:fix_dependencies(gathered_deps, dep_of, on_disable)
153+
local function should_disable(dep_name)
154+
for _, parent in ipairs(dep_of[dep_name] or {}) do
155+
if self.plugins[parent] then
156+
return false
157+
end
158+
end
159+
return true
160+
end
161+
162+
for _, dep_name in ipairs(gathered_deps) do
163+
-- only check if the plugin is still enabled and it is a dep
164+
if self.plugins[dep_name] and self.plugins[dep_name]._.dep then
165+
-- check if the dep is still used by another plugin
166+
if should_disable(dep_name) then
167+
-- disable the dep when no longer needed
168+
on_disable(dep_name)
169+
end
170+
end
171+
end
172+
end
173+
149174
function Spec:fix_cond()
150175
for _, plugin in pairs(self.plugins) do
151176
local cond = plugin.cond
@@ -159,7 +184,9 @@ function Spec:fix_cond()
159184
end
160185
end
161186

187+
---@return string[]
162188
function Spec:fix_optional()
189+
local all_optional_deps = {}
163190
if not self.optional then
164191
---@param plugin LazyPlugin
165192
local function all_optional(plugin)
@@ -170,9 +197,13 @@ function Spec:fix_optional()
170197
for _, plugin in pairs(self.plugins) do
171198
if plugin.optional and all_optional(plugin) then
172199
self.plugins[plugin.name] = nil
200+
if plugin.dependencies then
201+
vim.list_extend(all_optional_deps, plugin.dependencies)
202+
end
173203
end
174204
end
175205
end
206+
return all_optional_deps
176207
end
177208

178209
function Spec:fix_disabled()
@@ -183,15 +214,16 @@ function Spec:fix_disabled()
183214
end
184215
end
185216

186-
self:fix_optional()
187-
self:fix_cond()
188-
189217
---@type table<string,string[]> plugin to parent plugin
190218
local dep_of = {}
191219

192220
---@type string[] dependencies of disabled plugins
193221
local disabled_deps = {}
194222

223+
---@type string[] dependencies of plugins that are completely optional
224+
local all_optional_deps = self:fix_optional()
225+
self:fix_cond()
226+
195227
for _, plugin in pairs(self.plugins) do
196228
local enabled = not (plugin.enabled == false or (type(plugin.enabled) == "function" and not plugin.enabled()))
197229
if enabled then
@@ -209,27 +241,17 @@ function Spec:fix_disabled()
209241
end
210242
end
211243

212-
-- check deps of disabled plugins
213-
for _, dep in ipairs(disabled_deps) do
214-
-- only check if the plugin is still enabled and it is a dep
215-
if self.plugins[dep] and self.plugins[dep]._.dep then
216-
-- check if the dep is still used by another plugin
217-
local keep = false
218-
for _, parent in ipairs(dep_of[dep] or {}) do
219-
if self.plugins[parent] then
220-
keep = true
221-
break
222-
end
223-
end
224-
-- disable the dep when no longer needed
225-
if not keep then
226-
local plugin = self.plugins[dep]
227-
plugin._.kind = "disabled"
228-
self.plugins[plugin.name] = nil
229-
self.disabled[plugin.name] = plugin
230-
end
231-
end
232-
end
244+
-- fix deps of plugins that are completely optional
245+
self:fix_dependencies(all_optional_deps, dep_of, function(dep_name)
246+
self.plugins[dep_name] = nil
247+
end)
248+
-- fix deps of disabled plugins
249+
self:fix_dependencies(disabled_deps, dep_of, function(dep_name)
250+
local plugin = self.plugins[dep_name]
251+
plugin._.kind = "disabled"
252+
self.plugins[plugin.name] = nil
253+
self.disabled[plugin.name] = plugin
254+
end)
233255
end
234256

235257
---@param msg string

tests/core/plugin_spec.lua

+19
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,25 @@ describe("plugin spec opt", function()
273273
end
274274
end
275275
end)
276+
277+
it("handles the optional keyword", function()
278+
local tests = {
279+
[{ { "foo/bax" }, { "foo/bar", optional = true, dependencies = "foo/dep1" } }] = false,
280+
[{ { "foo/bax", dependencies = "foo/dep1" }, { "foo/bar", optional = true, dependencies = "foo/dep1" } }] = true,
281+
}
282+
for test, ret in pairs(tests) do
283+
local spec = Plugin.Spec.new(test)
284+
assert(#spec.notifs == 0)
285+
assert(spec.plugins.bax)
286+
assert(not spec.plugins.bar)
287+
assert(#spec.disabled == 0)
288+
if ret then
289+
assert(spec.plugins.dep1)
290+
else
291+
assert(not spec.plugins.opt1)
292+
end
293+
end
294+
end)
276295
end)
277296

278297
describe("plugin opts", function()

0 commit comments

Comments
 (0)