mirror of https://github.com/folke/lazy.nvim.git
fix(fragments): prevent adding the same spec instance more than once
This commit is contained in:
parent
fd04bc62f9
commit
dbffad6f44
|
@ -1,13 +1,5 @@
|
||||||
local Config = require("lazy.core.config")
|
local Config = require("lazy.core.config")
|
||||||
|
local Util = require("lazy.core.util")
|
||||||
local M = {}
|
|
||||||
|
|
||||||
M._fid = 0
|
|
||||||
|
|
||||||
local function next_id()
|
|
||||||
M._fid = M._fid + 1
|
|
||||||
return M._fid
|
|
||||||
end
|
|
||||||
|
|
||||||
--- This class is used to manage the fragments of a plugin spec.
|
--- This class is used to manage the fragments of a plugin spec.
|
||||||
--- It keeps track of the fragments and their relations to other fragments.
|
--- It keeps track of the fragments and their relations to other fragments.
|
||||||
|
@ -17,30 +9,39 @@ end
|
||||||
---@field frag_stack number[]
|
---@field frag_stack number[]
|
||||||
---@field dep_stack number[]
|
---@field dep_stack number[]
|
||||||
---@field dirty table<number, boolean>
|
---@field dirty table<number, boolean>
|
||||||
|
---@field plugins table<LazyPlugin, number>
|
||||||
---@field spec LazySpecLoader
|
---@field spec LazySpecLoader
|
||||||
local F = {}
|
local M = {}
|
||||||
|
|
||||||
|
M._fid = 0
|
||||||
|
|
||||||
|
local function next_id()
|
||||||
|
M._fid = M._fid + 1
|
||||||
|
return M._fid
|
||||||
|
end
|
||||||
|
|
||||||
---@param spec LazySpecLoader
|
---@param spec LazySpecLoader
|
||||||
---@return LazyFragments
|
---@return LazyFragments
|
||||||
function M.new(spec)
|
function M.new(spec)
|
||||||
local self = setmetatable({}, { __index = F })
|
local self = setmetatable({}, { __index = M })
|
||||||
self.fragments = {}
|
self.fragments = {}
|
||||||
self.frag_stack = {}
|
self.frag_stack = {}
|
||||||
self.dep_stack = {}
|
self.dep_stack = {}
|
||||||
self.spec = spec
|
self.spec = spec
|
||||||
self.dirty = {}
|
self.dirty = {}
|
||||||
|
self.plugins = {}
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param id number
|
---@param id number
|
||||||
function F:get(id)
|
function M:get(id)
|
||||||
return self.fragments[id]
|
return self.fragments[id]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove a fragment and all its children.
|
--- Remove a fragment and all its children.
|
||||||
--- This will also remove the fragment from its parent's children list.
|
--- This will also remove the fragment from its parent's children list.
|
||||||
---@param id number
|
---@param id number
|
||||||
function F:del(id)
|
function M:del(id)
|
||||||
-- del fragment
|
-- del fragment
|
||||||
local fragment = self.fragments[id]
|
local fragment = self.fragments[id]
|
||||||
if not fragment then
|
if not fragment then
|
||||||
|
@ -55,13 +56,13 @@ function F:del(id)
|
||||||
local parent = self.fragments[pid]
|
local parent = self.fragments[pid]
|
||||||
if parent.frags then
|
if parent.frags then
|
||||||
---@param fid number
|
---@param fid number
|
||||||
parent.frags = vim.tbl_filter(function(fid)
|
parent.frags = Util.filter(function(fid)
|
||||||
return fid ~= id
|
return fid ~= id
|
||||||
end, parent.frags)
|
end, parent.frags)
|
||||||
end
|
end
|
||||||
if parent.deps then
|
if parent.deps then
|
||||||
---@param fid number
|
---@param fid number
|
||||||
parent.deps = vim.tbl_filter(function(fid)
|
parent.deps = Util.filter(function(fid)
|
||||||
return fid ~= id
|
return fid ~= id
|
||||||
end, parent.deps)
|
end, parent.deps)
|
||||||
end
|
end
|
||||||
|
@ -81,8 +82,15 @@ end
|
||||||
--- Add a fragment to the fragments list.
|
--- Add a fragment to the fragments list.
|
||||||
--- This also resolves its name, url, dir, dependencies and child specs.
|
--- This also resolves its name, url, dir, dependencies and child specs.
|
||||||
---@param plugin LazyPluginSpec
|
---@param plugin LazyPluginSpec
|
||||||
function F:add(plugin)
|
function M:add(plugin)
|
||||||
|
if self.plugins[plugin] then
|
||||||
|
return self.fragments[self.plugins[plugin]]
|
||||||
|
end
|
||||||
|
|
||||||
local id = next_id()
|
local id = next_id()
|
||||||
|
setmetatable(plugin, nil)
|
||||||
|
|
||||||
|
self.plugins[plugin] = id
|
||||||
|
|
||||||
local pid = self.frag_stack[#self.frag_stack]
|
local pid = self.frag_stack[#self.frag_stack]
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,7 @@ function M:load_pkgs()
|
||||||
if not Config.options.pkg.enabled then
|
if not Config.options.pkg.enabled then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local specs = Pkg.get()
|
for _, pkg in ipairs(Pkg.get()) do
|
||||||
for dir, pkg in pairs(specs) do
|
|
||||||
local meta, fragment = self:add(pkg.spec)
|
local meta, fragment = self:add(pkg.spec)
|
||||||
if meta and fragment then
|
if meta and fragment then
|
||||||
meta._.pkg = pkg
|
meta._.pkg = pkg
|
||||||
|
@ -44,7 +43,7 @@ function M:load_pkgs()
|
||||||
frag.spec.optional = true
|
frag.spec.optional = true
|
||||||
end
|
end
|
||||||
-- keep track of the top-level package fragment
|
-- keep track of the top-level package fragment
|
||||||
self.pkgs[dir] = fragment.id
|
self.pkgs[pkg.dir] = fragment.id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -128,7 +127,7 @@ function M:rebuild()
|
||||||
-- fragment was deleted, so remove it from plugin
|
-- fragment was deleted, so remove it from plugin
|
||||||
self.frag_to_meta[fid] = nil
|
self.frag_to_meta[fid] = nil
|
||||||
---@param f number
|
---@param f number
|
||||||
meta._.frags = vim.tbl_filter(function(f)
|
meta._.frags = Util.filter(function(f)
|
||||||
return f ~= fid
|
return f ~= fid
|
||||||
end, meta._.frags)
|
end, meta._.frags)
|
||||||
-- if no fragments left, delete plugin
|
-- if no fragments left, delete plugin
|
||||||
|
@ -167,10 +166,10 @@ function M:_rebuild(name)
|
||||||
assert(#plugin._.frags > 0, "no fragments found for plugin " .. name)
|
assert(#plugin._.frags > 0, "no fragments found for plugin " .. name)
|
||||||
|
|
||||||
---@type table<number, boolean>
|
---@type table<number, boolean>
|
||||||
local done = {}
|
local added = {}
|
||||||
for _, fid in ipairs(plugin._.frags) do
|
for _, fid in ipairs(plugin._.frags) do
|
||||||
if not done[fid] then
|
if not added[fid] then
|
||||||
done[fid] = true
|
added[fid] = true
|
||||||
local fragment = self.fragments:get(fid)
|
local fragment = self.fragments:get(fid)
|
||||||
assert(fragment, "fragment " .. fid .. " not found, for plugin " .. name)
|
assert(fragment, "fragment " .. fid .. " not found, for plugin " .. name)
|
||||||
---@diagnostic disable-next-line: no-unknown
|
---@diagnostic disable-next-line: no-unknown
|
||||||
|
|
|
@ -170,10 +170,10 @@ function Spec:import(spec)
|
||||||
self.importing = nil
|
self.importing = nil
|
||||||
return self:error(
|
return self:error(
|
||||||
"Invalid spec module: `"
|
"Invalid spec module: `"
|
||||||
.. modname
|
.. modname
|
||||||
.. "`\nExpected a `table` of specs, but a `"
|
.. "`\nExpected a `table` of specs, but a `"
|
||||||
.. type(mod)
|
.. type(mod)
|
||||||
.. "` was returned instead"
|
.. "` was returned instead"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
self:normalize(mod)
|
self:normalize(mod)
|
||||||
|
@ -216,11 +216,11 @@ function M.update_state()
|
||||||
plugin._ = plugin._ or {}
|
plugin._ = plugin._ or {}
|
||||||
if plugin.lazy == nil then
|
if plugin.lazy == nil then
|
||||||
local lazy = plugin._.dep
|
local lazy = plugin._.dep
|
||||||
or Config.options.defaults.lazy
|
or Config.options.defaults.lazy
|
||||||
or plugin.event
|
or plugin.event
|
||||||
or plugin.keys
|
or plugin.keys
|
||||||
or plugin.ft
|
or plugin.ft
|
||||||
or plugin.cmd
|
or plugin.cmd
|
||||||
plugin.lazy = lazy and true or false
|
plugin.lazy = lazy and true or false
|
||||||
end
|
end
|
||||||
if plugin.dir:find(Config.options.root, 1, true) == 1 then
|
if plugin.dir:find(Config.options.root, 1, true) == 1 then
|
||||||
|
@ -342,7 +342,6 @@ function M.load()
|
||||||
Config.plugins[name]._ = plugin._
|
Config.plugins[name]._ = plugin._
|
||||||
Config.plugins[name]._.dep = new_state.dep
|
Config.plugins[name]._.dep = new_state.dep
|
||||||
Config.plugins[name]._.frags = new_state.frags
|
Config.plugins[name]._.frags = new_state.frags
|
||||||
-- Config.plugins[name]._.tasks = new_state.tasks
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Util.track()
|
Util.track()
|
||||||
|
|
|
@ -28,6 +28,20 @@ function M.track(data, time)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@generic T
|
||||||
|
---@param list T[]
|
||||||
|
---@param fn fun(v: T):boolean?
|
||||||
|
---@return T[]
|
||||||
|
function M.filter(fn, list)
|
||||||
|
local ret = {}
|
||||||
|
for _, v in ipairs(list) do
|
||||||
|
if fn(v) then
|
||||||
|
table.insert(ret, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
---@generic F: fun()
|
---@generic F: fun()
|
||||||
---@param data (string|{[string]:string})?
|
---@param data (string|{[string]:string})?
|
||||||
---@param fn F
|
---@param fn F
|
||||||
|
|
|
@ -25,7 +25,7 @@ M.dirty = false
|
||||||
---@field pkgs LazyPkg[]
|
---@field pkgs LazyPkg[]
|
||||||
---@field version number
|
---@field version number
|
||||||
|
|
||||||
---@type table<string, LazyPkg>?
|
---@type LazyPkg[]?
|
||||||
M.cache = nil
|
M.cache = nil
|
||||||
|
|
||||||
function M.update()
|
function M.update()
|
||||||
|
@ -65,6 +65,9 @@ function M.update()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
table.sort(ret.pkgs, function(a, b)
|
||||||
|
return a.name < b.name
|
||||||
|
end)
|
||||||
local code = "return " .. Util.dump(ret)
|
local code = "return " .. Util.dump(ret)
|
||||||
vim.fn.mkdir(vim.fn.fnamemodify(Config.options.pkg.cache, ":h"), "p")
|
vim.fn.mkdir(vim.fn.fnamemodify(Config.options.pkg.cache, ":h"), "p")
|
||||||
Util.write_file(Config.options.pkg.cache, code)
|
Util.write_file(Config.options.pkg.cache, code)
|
||||||
|
@ -91,8 +94,8 @@ local function _load()
|
||||||
end
|
end
|
||||||
-- wrap in the scope of the plugin
|
-- wrap in the scope of the plugin
|
||||||
pkg.spec = { pkg.name, specs = pkg.spec }
|
pkg.spec = { pkg.name, specs = pkg.spec }
|
||||||
M.cache[pkg.dir] = pkg
|
|
||||||
end
|
end
|
||||||
|
M.cache = ret.pkgs
|
||||||
end
|
end
|
||||||
end, "Error loading pkg:")
|
end, "Error loading pkg:")
|
||||||
end
|
end
|
||||||
|
@ -107,10 +110,15 @@ end
|
||||||
|
|
||||||
---@param dir string
|
---@param dir string
|
||||||
---@return LazyPkg?
|
---@return LazyPkg?
|
||||||
---@overload fun():table<string, LazyPkg>
|
---@overload fun():LazyPkg[]
|
||||||
function M.get(dir)
|
function M.get(dir)
|
||||||
if dir then
|
if dir then
|
||||||
return M.cache[dir]
|
for _, pkg in ipairs(M.cache) do
|
||||||
|
if pkg.dir == dir then
|
||||||
|
return pkg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return
|
||||||
end
|
end
|
||||||
return M.cache
|
return M.cache
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue