From dbffad6f44674a3c1b23c649a0abab299d7349d8 Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Mon, 24 Jun 2024 16:42:57 +0200 Subject: [PATCH] fix(fragments): prevent adding the same spec instance more than once --- lua/lazy/core/fragments.lua | 40 ++++++++++++++++++++++--------------- lua/lazy/core/meta.lua | 13 ++++++------ lua/lazy/core/plugin.lua | 19 +++++++++--------- lua/lazy/core/util.lua | 14 +++++++++++++ lua/lazy/pkg/init.lua | 16 +++++++++++---- 5 files changed, 65 insertions(+), 37 deletions(-) diff --git a/lua/lazy/core/fragments.lua b/lua/lazy/core/fragments.lua index 1ca018c..e0e6723 100644 --- a/lua/lazy/core/fragments.lua +++ b/lua/lazy/core/fragments.lua @@ -1,13 +1,5 @@ local Config = require("lazy.core.config") - -local M = {} - -M._fid = 0 - -local function next_id() - M._fid = M._fid + 1 - return M._fid -end +local Util = require("lazy.core.util") --- This class is used to manage the fragments of a plugin spec. --- It keeps track of the fragments and their relations to other fragments. @@ -17,30 +9,39 @@ end ---@field frag_stack number[] ---@field dep_stack number[] ---@field dirty table +---@field plugins table ---@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 ---@return LazyFragments function M.new(spec) - local self = setmetatable({}, { __index = F }) + local self = setmetatable({}, { __index = M }) self.fragments = {} self.frag_stack = {} self.dep_stack = {} self.spec = spec self.dirty = {} + self.plugins = {} return self end ---@param id number -function F:get(id) +function M:get(id) return self.fragments[id] end --- Remove a fragment and all its children. --- This will also remove the fragment from its parent's children list. ---@param id number -function F:del(id) +function M:del(id) -- del fragment local fragment = self.fragments[id] if not fragment then @@ -55,13 +56,13 @@ function F:del(id) local parent = self.fragments[pid] if parent.frags then ---@param fid number - parent.frags = vim.tbl_filter(function(fid) + parent.frags = Util.filter(function(fid) return fid ~= id end, parent.frags) end if parent.deps then ---@param fid number - parent.deps = vim.tbl_filter(function(fid) + parent.deps = Util.filter(function(fid) return fid ~= id end, parent.deps) end @@ -81,8 +82,15 @@ end --- Add a fragment to the fragments list. --- This also resolves its name, url, dir, dependencies and child specs. ---@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() + setmetatable(plugin, nil) + + self.plugins[plugin] = id local pid = self.frag_stack[#self.frag_stack] diff --git a/lua/lazy/core/meta.lua b/lua/lazy/core/meta.lua index 43bd642..679a16f 100644 --- a/lua/lazy/core/meta.lua +++ b/lua/lazy/core/meta.lua @@ -33,8 +33,7 @@ function M:load_pkgs() if not Config.options.pkg.enabled then return end - local specs = Pkg.get() - for dir, pkg in pairs(specs) do + for _, pkg in ipairs(Pkg.get()) do local meta, fragment = self:add(pkg.spec) if meta and fragment then meta._.pkg = pkg @@ -44,7 +43,7 @@ function M:load_pkgs() frag.spec.optional = true end -- keep track of the top-level package fragment - self.pkgs[dir] = fragment.id + self.pkgs[pkg.dir] = fragment.id end end end @@ -128,7 +127,7 @@ function M:rebuild() -- fragment was deleted, so remove it from plugin self.frag_to_meta[fid] = nil ---@param f number - meta._.frags = vim.tbl_filter(function(f) + meta._.frags = Util.filter(function(f) return f ~= fid end, meta._.frags) -- if no fragments left, delete plugin @@ -167,10 +166,10 @@ function M:_rebuild(name) assert(#plugin._.frags > 0, "no fragments found for plugin " .. name) ---@type table - local done = {} + local added = {} for _, fid in ipairs(plugin._.frags) do - if not done[fid] then - done[fid] = true + if not added[fid] then + added[fid] = true local fragment = self.fragments:get(fid) assert(fragment, "fragment " .. fid .. " not found, for plugin " .. name) ---@diagnostic disable-next-line: no-unknown diff --git a/lua/lazy/core/plugin.lua b/lua/lazy/core/plugin.lua index 875b580..e93555c 100644 --- a/lua/lazy/core/plugin.lua +++ b/lua/lazy/core/plugin.lua @@ -170,10 +170,10 @@ function Spec:import(spec) self.importing = nil return self:error( "Invalid spec module: `" - .. modname - .. "`\nExpected a `table` of specs, but a `" - .. type(mod) - .. "` was returned instead" + .. modname + .. "`\nExpected a `table` of specs, but a `" + .. type(mod) + .. "` was returned instead" ) end self:normalize(mod) @@ -216,11 +216,11 @@ function M.update_state() plugin._ = plugin._ or {} if plugin.lazy == nil then local lazy = plugin._.dep - or Config.options.defaults.lazy - or plugin.event - or plugin.keys - or plugin.ft - or plugin.cmd + or Config.options.defaults.lazy + or plugin.event + or plugin.keys + or plugin.ft + or plugin.cmd plugin.lazy = lazy and true or false end 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]._.dep = new_state.dep Config.plugins[name]._.frags = new_state.frags - -- Config.plugins[name]._.tasks = new_state.tasks end end Util.track() diff --git a/lua/lazy/core/util.lua b/lua/lazy/core/util.lua index d4fa47c..0504dd8 100644 --- a/lua/lazy/core/util.lua +++ b/lua/lazy/core/util.lua @@ -28,6 +28,20 @@ function M.track(data, time) 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() ---@param data (string|{[string]:string})? ---@param fn F diff --git a/lua/lazy/pkg/init.lua b/lua/lazy/pkg/init.lua index 48e755c..0037b26 100644 --- a/lua/lazy/pkg/init.lua +++ b/lua/lazy/pkg/init.lua @@ -25,7 +25,7 @@ M.dirty = false ---@field pkgs LazyPkg[] ---@field version number ----@type table? +---@type LazyPkg[]? M.cache = nil function M.update() @@ -65,6 +65,9 @@ function M.update() end end end + table.sort(ret.pkgs, function(a, b) + return a.name < b.name + end) local code = "return " .. Util.dump(ret) vim.fn.mkdir(vim.fn.fnamemodify(Config.options.pkg.cache, ":h"), "p") Util.write_file(Config.options.pkg.cache, code) @@ -91,8 +94,8 @@ local function _load() end -- wrap in the scope of the plugin pkg.spec = { pkg.name, specs = pkg.spec } - M.cache[pkg.dir] = pkg end + M.cache = ret.pkgs end end, "Error loading pkg:") end @@ -107,10 +110,15 @@ end ---@param dir string ---@return LazyPkg? ----@overload fun():table +---@overload fun():LazyPkg[] function M.get(dir) 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 return M.cache end