From 4438faf9a9a72c95d88c620804db99fa44485ec9 Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Wed, 30 Nov 2022 00:18:59 +0100 Subject: [PATCH] perf: removed partial spec caching. not worth the tiny performance boost --- lua/lazy/core/cache.lua | 23 ++--- lua/lazy/core/handler.lua | 32 +++--- lua/lazy/core/loader.lua | 12 --- lua/lazy/core/module.lua | 10 +- lua/lazy/core/plugin.lua | 198 ++++++++----------------------------- lua/lazy/init.lua | 17 +--- lua/lazy/manage/init.lua | 4 +- tests/core/plugin_spec.lua | 9 +- 8 files changed, 77 insertions(+), 228 deletions(-) diff --git a/lua/lazy/core/cache.lua b/lua/lazy/core/cache.lua index 270d6b5..8614190 100644 --- a/lua/lazy/core/cache.lua +++ b/lua/lazy/core/cache.lua @@ -68,27 +68,20 @@ function M.setup() end function M.autosave() - vim.api.nvim_create_autocmd("User", { - pattern = "LazyDone", - once = true, + vim.api.nvim_create_autocmd("VimLeavePre", { callback = function() - vim.api.nvim_create_autocmd("VimLeavePre", { - callback = function() - if M.dirty then - local hash = M.hash(cache_path) - -- abort when the file was changed in the meantime - if hash == nil or cache_hash == hash then - M.save() - end - end - end, - }) + if M.dirty then + local hash = M.hash(cache_path) + -- abort when the file was changed in the meantime + if hash == nil or cache_hash == hash then + M.save() + end + end end, }) end function M.save() - require("lazy.core.plugin").save() require("lazy.core.module").save() local f = assert(io.open(cache_path, "wb")) diff --git a/lua/lazy/core/handler.lua b/lua/lazy/core/handler.lua index b8f5682..fb20810 100644 --- a/lua/lazy/core/handler.lua +++ b/lua/lazy/core/handler.lua @@ -1,5 +1,6 @@ local Util = require("lazy.core.util") local Loader = require("lazy.core.loader") +local Config = require("lazy.core.config") ---@class LazyPluginHandlers ---@field event? string|string[] @@ -12,34 +13,25 @@ local M = {} ---@alias LazyHandler fun(grouped:table) ----@type table> -M._groups = nil - ----@param plugins LazyPlugin[] ----@param rebuild? boolean -function M.group(plugins, rebuild) - if M._groups == nil or rebuild then - M._groups = {} - local types = vim.tbl_keys(M.handlers) --[[@as string[] ]] - for _, key in ipairs(types) do - M._groups[key] = {} - for _, plugin in pairs(plugins) do - if plugin[key] then - ---@diagnostic disable-next-line: no-unknown - for _, value in pairs(type(plugin[key]) == "table" and plugin[key] or { plugin[key] }) do - M._groups[key][value] = M._groups[key][value] or {} - table.insert(M._groups[key][value], plugin.name) - end +function M.setup() + for key, handler in pairs(M.handlers) do + ---@type table + local group = {} + for _, plugin in pairs(Config.plugins) do + if plugin[key] then + ---@diagnostic disable-next-line: no-unknown + for _, value in pairs(type(plugin[key]) == "table" and plugin[key] or { plugin[key] }) do + group[value] = group[value] or {} + table.insert(group[value], plugin.name) end end end + handler(group) end - return M._groups end ---@type table M.handlers = {} - function M.handlers.event(grouped) local group = vim.api.nvim_create_augroup("lazy_handler_event", { clear = true }) for event, plugins in pairs(grouped) do diff --git a/lua/lazy/core/loader.lua b/lua/lazy/core/loader.lua index 462e4b7..f8be35e 100644 --- a/lua/lazy/core/loader.lua +++ b/lua/lazy/core/loader.lua @@ -6,18 +6,6 @@ local M = {} ---@type LazyPlugin[] M.loading = {} -function M.setup() - local Handler = require("lazy.core.handler") - local groups = Handler.group(Config.plugins) - for t, handler in pairs(Handler.handlers) do - if groups[t] then - Util.track(t) - handler(groups[t]) - Util.track() - end - end -end - function M.init_plugins() Util.track("plugin_init") for _, plugin in pairs(Config.plugins) do diff --git a/lua/lazy/core/module.lua b/lua/lazy/core/module.lua index 5b0a233..3eb5780 100644 --- a/lua/lazy/core/module.lua +++ b/lua/lazy/core/module.lua @@ -5,13 +5,9 @@ local M = {} ---@type table M.hashes = {} -function M.is_dirty(modname, modpath) - return not (Cache.get(modname) and M.hashes[modname] and M.hashes[modname] == Cache.hash(modpath)) -end - ---@param modname string ---@param modpath string ----@return any, boolean +---@return any function M.load(modname, modpath) local err ---@type (string|fun())? @@ -24,9 +20,7 @@ function M.load(modname, modpath) chunk = nil end - local cached = false if chunk then - cached = true chunk, err = load(chunk --[[@as string]], "@" .. modpath, "b") else vim.schedule(function() @@ -39,7 +33,7 @@ function M.load(modname, modpath) end if chunk then - return chunk(), cached + return chunk() else error(err) end diff --git a/lua/lazy/core/plugin.lua b/lua/lazy/core/plugin.lua index 0f20b24..815a57e 100644 --- a/lua/lazy/core/plugin.lua +++ b/lua/lazy/core/plugin.lua @@ -1,17 +1,10 @@ local Config = require("lazy.core.config") local Util = require("lazy.core.util") local Module = require("lazy.core.module") -local Cache = require("lazy.core.cache") local Handler = require("lazy.core.handler") local M = {} ----@alias CachedPlugin LazyPlugin | {_funs: string[]} -local skip = { _ = true, dir = true } -local funs = { config = true, init = true, run = true } - -M.dirty = false - ---@class LazyPluginHooks ---@field init? fun(LazyPlugin) Will always be run ---@field config? fun(LazyPlugin) Will be executed when loading the plugin @@ -48,10 +41,7 @@ M.dirty = false ---@alias LazySpec string|LazyPlugin|LazySpec[]|{dependencies:LazySpec} ---@class LazySpecLoader ----@field modname string ----@field modpath string ---@field plugins table ----@field funs? table local Spec = {} M.Spec = Spec @@ -59,30 +49,12 @@ M.Spec = Spec function Spec.new(spec) local self = setmetatable({}, { __index = Spec }) self.plugins = {} - self.modname = nil - self.modpath = nil if spec then self:normalize(spec) end return self end ----@param modname string ----@param modpath string -function Spec.load(modname, modpath) - local self = setmetatable({}, { __index = Spec }) - self.plugins = {} - self.modname = modname - self.modpath = modpath - local mod, cached = Module.load(modname, modpath) - M.dirty = M.dirty or not cached - self:normalize(assert(mod)) - if modname == Config.options.plugins and not self.plugins["lazy.nvim"] then - self:add({ "folke/lazy.nvim", opt = false }) - end - return self -end - ---@param plugin LazyPlugin ---@param is_dep? boolean function Spec:add(plugin, is_dep) @@ -113,9 +85,16 @@ function Spec:add(plugin, is_dep) plugin.dep = is_dep - M.process_local(plugin) + -- check for plugins that should be local + for _, pattern in ipairs(Config.options.plugins_local.patterns) do + if plugin[1]:find(pattern, 1, true) then + plugin.uri = Config.options.plugins_local.path .. "/" .. plugin.name + break + end + end + local other = self.plugins[plugin.name] - self.plugins[plugin.name] = other and M.merge(other, plugin) or plugin + self.plugins[plugin.name] = other and self:merge(other, plugin) or plugin return self.plugins[plugin.name] end @@ -140,28 +119,10 @@ function Spec:normalize(spec, results, is_dep) return results end ----@param spec LazySpecLoader -function Spec.revive(spec) - if spec.funs then - ---@type LazySpecLoader - local loaded = nil - for fun, plugins in pairs(spec.funs) do - for _, name in pairs(plugins) do - ---@diagnostic disable-next-line: no-unknown - spec.plugins[name][fun] = function(...) - loaded = loaded or Spec.load(spec.modname, spec.modpath) - return loaded.plugins[name][fun](...) - end - end - end - end - return spec -end - ---@param old LazyPlugin ---@param new LazyPlugin ---@return LazyPlugin -function M.merge(old, new) +function Spec:merge(old, new) local is_dep = old.dep and new.dep ---@diagnostic disable-next-line: no-unknown @@ -185,25 +146,19 @@ function M.merge(old, new) return old end ----@param opts? {clean:boolean, installed:boolean, plugins?: LazyPlugin[]} -function M.update_state(opts) - opts = opts or {} - +function M.update_state() ---@type table<"opt"|"start", table> local installed = { opt = {}, start = {} } - if opts.installed ~= false then - for opt, packs in pairs(installed) do - Util.ls(Config.options.packpath .. "/" .. opt, function(_, name, type) - if type == "directory" or type == "link" then - packs[name] = type - end - end) - end + for opt, packs in pairs(installed) do + Util.ls(Config.options.packpath .. "/" .. opt, function(_, name, type) + if type == "directory" or type == "link" then + packs[name] = type + end + end) end - for _, plugin in pairs(opts.plugins or Config.plugins) do + for _, plugin in pairs(Config.plugins) do plugin._ = plugin._ or {} - plugin[1] = plugin["1"] or plugin[1] if plugin.opt == nil then plugin.opt = plugin.dep or Config.options.opt @@ -224,121 +179,52 @@ function M.update_state(opts) end end - if opts.clean then - Config.to_clean = {} - for opt, packs in pairs(installed) do - for pack in pairs(packs) do - table.insert(Config.to_clean, { - name = pack, - pack = pack, - dir = Config.options.packpath .. "/" .. opt .. "/" .. pack, - opt = opt == "opt", - _ = { - installed = true, - }, - }) - end + Config.to_clean = {} + for opt, packs in pairs(installed) do + for pack, dir_type in pairs(packs) do + table.insert(Config.to_clean, { + name = pack, + dir = Config.options.packpath .. "/" .. opt .. "/" .. pack, + opt = opt == "opt", + _ = { + installed = true, + is_symlink = dir_type == "link", + is_local = dir_type == "link", + }, + }) end end end ----@param plugin LazyPlugin -function M.process_local(plugin) - for _, pattern in ipairs(Config.options.plugins_local.patterns) do - if plugin[1]:find(pattern, 1, true) then - plugin.uri = Config.options.plugins_local.path .. "/" .. plugin.name - return - end - end -end - ----@param cache? table -function M.specs(cache) - ---@type LazySpecLoader[] - local specs = {} +function M.spec() + local spec = Spec.new() local function _load(name, modpath) local modname = Config.options.plugins .. (name and ("." .. name) or "") Util.try(function() - local spec = cache and cache[modname] - spec = spec and not Module.is_dirty(modname, modpath) and Spec.revive(spec) or Spec.load(modname, modpath) - table.insert(specs, spec) + local mod = Module.load(modname, modpath) + spec:normalize(assert(mod)) end, "Failed to load **" .. modname .. "**") end _load(nil, Config.paths.main) Util.lsmod(Config.paths.plugins, _load) - return specs + return spec end function M.load() - ---@type boolean, LazyState? - local ok, state = pcall(vim.json.decode, Cache.get("cache.state")) - if not (ok and state and vim.deep_equal(Config.options, state.config)) then - M.dirty = true - state = nil - end - -- load specs - Util.track("specs") - local specs = M.specs(state and state.specs) - Util.track() - - -- merge - Config.plugins = {} - for _, spec in ipairs(specs) do - for _, plugin in pairs(spec.plugins) do - local other = Config.plugins[plugin.name] - Config.plugins[plugin.name] = other and M.merge(other, plugin) or plugin - end + Util.track("spec") + local spec = M.spec() + if not spec.plugins["lazy.nvim"] then + spec:add({ "folke/lazy.nvim", opt = false }) end + Config.plugins = spec.plugins + Util.track() Util.track("state") M.update_state() Util.track() - - if M.dirty then - Cache.dirty = true - elseif state then - require("lazy.core.handler")._groups = state.handlers - end -end - -function M.save() - ---@class LazyState - local state = { - ---@type table - specs = {}, - handlers = require("lazy.core.handler").group(Config.plugins, true), - config = Config.options, - } - - for _, spec in ipairs(M.specs()) do - spec.funs = {} - state.specs[spec.modname] = spec - for _, plugin in pairs(spec.plugins) do - if plugin.init or (plugin.opt == false and plugin.config) then - -- no use in caching specs that need init, - -- or specs that are in start and have a config, - -- since we'll load the real spec during startup anyway - state.specs[spec.modname] = nil - break - end - ---@cast plugin CachedPlugin - for k, v in pairs(plugin) do - if type(v) == "function" then - if funs[k] then - spec.funs[k] = spec.funs[k] or {} - table.insert(spec.funs[k], plugin.name) - end - plugin[k] = nil - elseif skip[k] then - plugin[k] = nil - end - end - end - end - Cache.set("cache.state", vim.json.encode(state)) end return M diff --git a/lua/lazy/init.lua b/lua/lazy/init.lua index 06fa663..50aa05f 100644 --- a/lua/lazy/init.lua +++ b/lua/lazy/init.lua @@ -10,6 +10,7 @@ function M.setup(opts) local Util = require("lazy.core.util") local Config = require("lazy.core.config") local Loader = require("lazy.core.loader") + local Handler = require("lazy.core.handler") local Plugin = require("lazy.core.plugin") Util.track("cache", module_start - cache_start) @@ -21,9 +22,7 @@ function M.setup(opts) Config.setup(opts) Util.track() - Util.track("state") Plugin.load() - Util.track() if Config.options.install_missing then Util.track("install") @@ -40,12 +39,13 @@ function M.setup(opts) Util.track() end - Util.track("loader") - Loader.setup() + Util.track("handlers") + Handler.setup() Util.track() local lazy_delta = vim.loop.hrtime() - cache_start + Util.track() -- end setup Loader.init_plugins() if Config.plugins["lazy.nvim"] then @@ -53,23 +53,16 @@ function M.setup(opts) end vim.cmd("do User LazyDone") - Util.track() -- end setup end function M.stats() - local ret = { - count = 0, - loaded = 0, - } - + local ret = { count = 0, loaded = 0 } for _, plugin in pairs(require("lazy.core.config").plugins) do ret.count = ret.count + 1 - if plugin._.loaded then ret.loaded = ret.loaded + 1 end end - return ret end diff --git a/lua/lazy/manage/init.lua b/lua/lazy/manage/init.lua index d77115f..5dac6e9 100644 --- a/lua/lazy/manage/init.lua +++ b/lua/lazy/manage/init.lua @@ -115,7 +115,7 @@ end ---@param opts? ManagerOpts function M.clean(opts) - Plugin.update_state({ clean = true }) + Plugin.update_state() M.run({ pipeline = { "fs.clean" }, plugins = Config.to_clean, @@ -123,7 +123,7 @@ function M.clean(opts) end function M.clear() - Plugin.update_state({ clean = true }) + Plugin.update_state() for _, plugin in pairs(Config.plugins) do plugin._.updated = nil plugin._.cloned = nil diff --git a/tests/core/plugin_spec.lua b/tests/core/plugin_spec.lua index 1e47788..acf3424 100644 --- a/tests/core/plugin_spec.lua +++ b/tests/core/plugin_spec.lua @@ -38,7 +38,8 @@ describe("plugin spec opt", function() } for _, test in ipairs(tests) do local spec = Plugin.Spec.new(test) - Plugin.update_state({ plugins = spec.plugins }) + Config.plugins = spec.plugins + Plugin.update_state() assert(vim.tbl_count(spec.plugins) == 3) assert(#spec.plugins.bar.dependencies == 2) assert(spec.plugins.bar.dep ~= true) @@ -53,7 +54,8 @@ describe("plugin spec opt", function() it("handles opt from dep", function() Config.options.opt = false local spec = Plugin.Spec.new({ "foo/dep1", { "foo/bar", dependencies = { "foo/dep1", "foo/dep2" } } }) - Plugin.update_state({ plugins = spec.plugins }) + Config.plugins = spec.plugins + Plugin.update_state() assert.same(3, vim.tbl_count(spec.plugins)) assert(spec.plugins.bar.dep ~= true) assert(spec.plugins.bar.opt == false) @@ -66,7 +68,8 @@ describe("plugin spec opt", function() it("handles opt from dep", function() Config.options.opt = false local spec = Plugin.Spec.new({ "foo/bar", module = "foo" }) - Plugin.update_state({ plugins = spec.plugins }) + Config.plugins = spec.plugins + Plugin.update_state() assert.same(1, vim.tbl_count(spec.plugins)) assert(spec.plugins.bar.dep ~= true) assert(spec.plugins.bar.opt == true)