Skip to content

Commit 4bf771a

Browse files
committed
feat(spec): allow using plugin names in dependencies
1 parent eb01b6d commit 4bf771a

File tree

2 files changed

+179
-5
lines changed

2 files changed

+179
-5
lines changed

lua/lazy/core/plugin.lua

+15-3
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,15 @@ local M = {}
5050

5151
---@class LazySpecLoader
5252
---@field plugins table<string, LazyPlugin>
53+
---@field errors string[]
5354
local Spec = {}
5455
M.Spec = Spec
5556

5657
---@param spec? LazySpec
5758
function Spec.new(spec)
5859
local self = setmetatable({}, { __index = Spec })
5960
self.plugins = {}
61+
self.errors = {}
6062
if spec then
6163
self:normalize(spec)
6264
end
@@ -100,7 +102,7 @@ function Spec:add(plugin, is_dep)
100102
plugin.dir = Config.options.root .. "/" .. plugin.name
101103
end
102104
else
103-
Util.error("Invalid plugin spec " .. vim.inspect(plugin))
105+
self:error("Invalid plugin spec " .. vim.inspect(plugin))
104106
end
105107

106108
plugin.event = type(plugin.event) == "string" and { plugin.event } or plugin.event
@@ -116,13 +118,23 @@ function Spec:add(plugin, is_dep)
116118
return self.plugins[plugin.name]
117119
end
118120

121+
function Spec:error(error)
122+
self.errors[#self.errors + 1] = error
123+
Util.error(error)
124+
end
125+
119126
---@param spec LazySpec
120127
---@param results? string[]
121128
---@param is_dep? boolean
122129
function Spec:normalize(spec, results, is_dep)
123130
results = results or {}
124131
if type(spec) == "string" then
125-
table.insert(results, self:add({ spec }, is_dep).name)
132+
if is_dep and not spec:find("/", 1, true) then
133+
-- spec is a plugin name
134+
table.insert(results, spec)
135+
else
136+
table.insert(results, self:add({ spec }, is_dep).name)
137+
end
126138
elseif #spec > 1 or Util.is_list(spec) then
127139
---@cast spec LazySpec[]
128140
for _, s in ipairs(spec) do
@@ -160,7 +172,7 @@ function Spec:merge(old, new)
160172
---@diagnostic disable-next-line: no-unknown
161173
old[k] = values
162174
else
163-
Util.error("Merging plugins is not supported for key `" .. k .. "`\n" .. vim.inspect({ old = old, new = new }))
175+
self:error("Merging plugins is not supported for key `" .. k .. "`\n" .. vim.inspect({ old = old, new = new }))
164176
end
165177
else
166178
---@diagnostic disable-next-line: no-unknown

tests/core/plugin_spec.lua

+164-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ describe("plugin spec url/name", function()
2626
end
2727
local spec = Plugin.Spec.new(test[1])
2828
local plugins = vim.tbl_values(spec.plugins)
29+
assert(#spec.errors == 0)
2930
assert.equal(1, #plugins)
3031
assert.same(test[2], plugins[1])
3132
end)
@@ -41,7 +42,8 @@ describe("plugin spec opt", function()
4142
{ { { "foo/bar", dependencies = { { "foo/dep1" }, "foo/dep2" } } } },
4243
}
4344
for _, test in ipairs(tests) do
44-
local spec = Plugin.Spec.new(test)
45+
local spec = Plugin.Spec.new(vim.deepcopy(test))
46+
assert(#spec.errors == 0)
4547
Config.plugins = spec.plugins
4648
Plugin.update_state()
4749
assert(vim.tbl_count(spec.plugins) == 3)
@@ -52,12 +54,168 @@ describe("plugin spec opt", function()
5254
assert(spec.plugins.dep1.lazy == true)
5355
assert(spec.plugins.dep2._.dep == true)
5456
assert(spec.plugins.dep2.lazy == true)
57+
spec = Plugin.Spec.new(test)
58+
for _, plugin in pairs(spec.plugins) do
59+
plugin.dir = nil
60+
end
61+
assert.same(spec.plugins, {
62+
bar = {
63+
"foo/bar",
64+
_ = {},
65+
dependencies = { "dep1", "dep2" },
66+
name = "bar",
67+
url = "https://github.com/foo/bar.git",
68+
},
69+
dep1 = {
70+
"foo/dep1",
71+
_ = {
72+
dep = true,
73+
},
74+
name = "dep1",
75+
url = "https://github.com/foo/dep1.git",
76+
},
77+
dep2 = {
78+
"foo/dep2",
79+
_ = {
80+
dep = true,
81+
},
82+
name = "dep2",
83+
url = "https://github.com/foo/dep2.git",
84+
},
85+
})
5586
end
5687
end)
5788

89+
describe("deps", function()
90+
it("handles dep names", function()
91+
Config.options.defaults.lazy = false
92+
local tests = {
93+
{ { "foo/bar", dependencies = { { "dep1" }, "foo/dep2" } }, "foo/dep1" },
94+
{ "foo/dep1", { "foo/bar", dependencies = { { "dep1" }, "foo/dep2" } } },
95+
}
96+
for _, test in ipairs(tests) do
97+
local spec = Plugin.Spec.new(vim.deepcopy(test))
98+
assert(#spec.errors == 0)
99+
Config.plugins = spec.plugins
100+
Plugin.update_state()
101+
spec = Plugin.Spec.new(test)
102+
for _, plugin in pairs(spec.plugins) do
103+
plugin.dir = nil
104+
end
105+
assert.same(spec.plugins, {
106+
bar = {
107+
"foo/bar",
108+
_ = {},
109+
dependencies = { "dep1", "dep2" },
110+
name = "bar",
111+
url = "https://github.com/foo/bar.git",
112+
},
113+
dep1 = {
114+
"foo/dep1",
115+
_ = {},
116+
name = "dep1",
117+
url = "https://github.com/foo/dep1.git",
118+
},
119+
dep2 = {
120+
"foo/dep2",
121+
_ = {
122+
dep = true,
123+
},
124+
name = "dep2",
125+
url = "https://github.com/foo/dep2.git",
126+
},
127+
})
128+
end
129+
end)
130+
131+
it("handles opt from dep", function()
132+
Config.options.defaults.lazy = false
133+
local spec = Plugin.Spec.new({ "foo/dep1", { "foo/bar", dependencies = { "foo/dep1", "foo/dep2" } } })
134+
assert(#spec.errors == 0)
135+
Config.plugins = spec.plugins
136+
Plugin.update_state()
137+
assert.same(3, vim.tbl_count(spec.plugins))
138+
assert(spec.plugins.bar._.dep ~= true)
139+
assert(spec.plugins.bar.lazy == false)
140+
assert(spec.plugins.dep2._.dep == true)
141+
assert(spec.plugins.dep2.lazy == true)
142+
assert(spec.plugins.dep1._.dep ~= true)
143+
assert(spec.plugins.dep1.lazy == false)
144+
end)
145+
146+
it("handles defaults opt", function()
147+
do
148+
Config.options.defaults.lazy = true
149+
local spec = Plugin.Spec.new({ "foo/bar" })
150+
assert(#spec.errors == 0)
151+
Config.plugins = spec.plugins
152+
Plugin.update_state()
153+
assert(spec.plugins.bar.lazy == true)
154+
end
155+
do
156+
Config.options.defaults.lazy = false
157+
local spec = Plugin.Spec.new({ "foo/bar" })
158+
Config.plugins = spec.plugins
159+
Plugin.update_state()
160+
assert(spec.plugins.bar.lazy == false)
161+
end
162+
end)
163+
164+
it("handles opt from dep", function()
165+
Config.options.defaults.lazy = false
166+
local spec = Plugin.Spec.new({ "foo/bar", event = "foo" })
167+
assert(#spec.errors == 0)
168+
Config.plugins = spec.plugins
169+
Plugin.update_state()
170+
assert.same(1, vim.tbl_count(spec.plugins))
171+
assert(spec.plugins.bar._.dep ~= true)
172+
assert(spec.plugins.bar.lazy == true)
173+
end)
174+
175+
it("merges lazy loaders", function()
176+
local tests = {
177+
{ { "foo/bar", event = "mod1" }, { "foo/bar", event = "mod2" } },
178+
{ { "foo/bar", event = { "mod1" } }, { "foo/bar", event = { "mod2" } } },
179+
{ { "foo/bar", event = "mod1" }, { "foo/bar", event = { "mod2" } } },
180+
}
181+
for _, test in ipairs(tests) do
182+
local spec = Plugin.Spec.new(test)
183+
assert(#spec.errors == 0)
184+
assert(vim.tbl_count(spec.plugins) == 1)
185+
assert(type(spec.plugins.bar.event) == "table")
186+
assert(#spec.plugins.bar.event == 2)
187+
assert(vim.tbl_contains(spec.plugins.bar.event, "mod1"))
188+
assert(vim.tbl_contains(spec.plugins.bar.event, "mod2"))
189+
end
190+
end)
191+
192+
it("refuses to merge", function()
193+
local spec = Plugin.Spec.new({
194+
{ "foo/dep1", config = 1 },
195+
{
196+
"foo/bar",
197+
dependencies = { { "foo/dep1", config = 2 }, "foo/dep2" },
198+
},
199+
})
200+
assert(#spec.errors > 0)
201+
end)
202+
203+
-- it("recursive deps", function()
204+
-- local spec = Plugin.Spec.new({
205+
-- "nvim-telescope/telescope.nvim",
206+
-- dependencies = {
207+
-- "nvim-lua/plenary.nvim",
208+
-- { "nvim-telescope/telescope-fzf-native.nvim", build = "make" },
209+
-- { "nvim-telescope/telescope-frecency.nvim", dependencies = "kkharji/sqlite.lua" },
210+
-- },
211+
-- })
212+
-- end)
213+
end)
214+
58215
it("handles opt from dep", function()
59216
Config.options.defaults.lazy = false
60217
local spec = Plugin.Spec.new({ "foo/dep1", { "foo/bar", dependencies = { "foo/dep1", "foo/dep2" } } })
218+
assert(#spec.errors == 0)
61219
Config.plugins = spec.plugins
62220
Plugin.update_state()
63221
assert.same(3, vim.tbl_count(spec.plugins))
@@ -73,6 +231,7 @@ describe("plugin spec opt", function()
73231
do
74232
Config.options.defaults.lazy = true
75233
local spec = Plugin.Spec.new({ "foo/bar" })
234+
assert(#spec.errors == 0)
76235
Config.plugins = spec.plugins
77236
Plugin.update_state()
78237
assert(spec.plugins.bar.lazy == true)
@@ -89,6 +248,7 @@ describe("plugin spec opt", function()
89248
it("handles opt from dep", function()
90249
Config.options.defaults.lazy = false
91250
local spec = Plugin.Spec.new({ "foo/bar", event = "foo" })
251+
assert(#spec.errors == 0)
92252
Config.plugins = spec.plugins
93253
Plugin.update_state()
94254
assert.same(1, vim.tbl_count(spec.plugins))
@@ -104,6 +264,7 @@ describe("plugin spec opt", function()
104264
}
105265
for _, test in ipairs(tests) do
106266
local spec = Plugin.Spec.new(test)
267+
assert(#spec.errors == 0)
107268
assert(vim.tbl_count(spec.plugins) == 1)
108269
assert(type(spec.plugins.bar.event) == "table")
109270
assert(#spec.plugins.bar.event == 2)
@@ -113,13 +274,14 @@ describe("plugin spec opt", function()
113274
end)
114275

115276
it("refuses to merge", function()
116-
Plugin.Spec.new({
277+
local spec = Plugin.Spec.new({
117278
{ "foo/dep1", config = 1 },
118279
{
119280
"foo/bar",
120281
dependencies = { { "foo/dep1", config = 2 }, "foo/dep2" },
121282
},
122283
})
284+
assert(#spec.errors > 0)
123285
end)
124286

125287
-- it("recursive deps", function()

0 commit comments

Comments
 (0)