From 3f517abfa43ec9410315e205c1ee3798b66e1153 Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Sat, 3 Dec 2022 23:15:50 +0100 Subject: [PATCH] feat: cleanup keys/cmd handlers when loading a plugin --- README.md | 24 +++-- lua/lazy/core/handler.lua | 213 +++++++++++++++++++++++--------------- lua/lazy/core/loader.lua | 3 +- lua/lazy/core/plugin.lua | 2 +- lua/lazy/core/util.lua | 9 +- lua/lazy/view/render.lua | 2 +- 6 files changed, 154 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index d09bc190..00ce00d8 100644 --- a/README.md +++ b/README.md @@ -27,26 +27,28 @@ - [ ] unsupported props or props from other managers - [ ] other packages still in site? - [ ] other package manager artifacts still present? compiled etc -- [x] rename `run` to `build` -- [ ] delete lazy keymaps when a plugin loads -- [x] temp colorscheme -- [x] allow setting up plugins through config **fooo** -- [x] task timeout +- [ ] status page showing running handlers and cache stats +- [x] delete lazy keymaps when a plugin loads. Reset handlers for a plugin? +- [ ] fix plugin details +- [ ] show disabled plugins (strikethrough?) - [ ] log file - [ ] deal with re-sourcing init.lua. Check a global? -- [x] incorrect when switching TN from opt to start - [ ] git tests -- [x] max concurrency -- [x] ui border -- [x] make sure we can reload specs while keeping state -- [ ] show disabled plugins (strikethrough?) - [ ] Import specs from other plugin managers -- [x] use uv file watcher (or stat) to check for config changes - [ ] [packspec](https://github.com/nvim-lua/nvim-package-specification) - [ ] add support to specify `engines`, `os` and `cpu` like in `package.json` - [ ] semver merging. Should check if two or more semver ranges are compatible and calculate the union range - default semver merging strategy: if no version matches all, then use highest version? - [ ] package meta index (package.lua cache for all packages) +- [x] rename `run` to `build` +- [x] temp colorscheme +- [x] allow setting up plugins through config **fooo** +- [x] task timeout +- [x] incorrect when switching TN from opt to start +- [x] max concurrency +- [x] ui border +- [x] make sure we can reload specs while keeping state +- [x] use uv file watcher (or stat) to check for config changes - [x] support for Plugin.lock - [x] defaults for git log - [x] view keybindings for update/clean/... diff --git a/lua/lazy/core/handler.lua b/lua/lazy/core/handler.lua index 043853b3..111bca52 100644 --- a/lua/lazy/core/handler.lua +++ b/lua/lazy/core/handler.lua @@ -1,5 +1,4 @@ local Util = require("lazy.core.util") -local Loader = require("lazy.core.loader") local Config = require("lazy.core.config") ---@class LazyPluginHandlers @@ -10,29 +9,89 @@ local Config = require("lazy.core.config") local M = {} +---@enum LazyPluginHandlerTYpes +M.types = { + keys = "keys", + event = "event", + cmd = "cmd", + ft = "ft", +} + +M.trigger_events = { + BufRead = { "BufReadPre", "BufRead" }, + BufReadPost = { "BufReadPre", "BufRead", "BufReadPost" }, +} + ---@alias LazyHandler fun(grouped:table) 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) + M.cmd() + M.event() + M.ft() + M.keys() +end + +---@param key string +---@param fn fun(plugins:LazyPlugin[], value:string) +function M.foreach_group(key, fn) + ---@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 + for value, plugins in pairs(group) do + fn(plugins, value) + end +end + +---@param key string +---@param fn fun(plugin:LazyPlugin, value:string) +function M.foreach_value(key, fn) + for _, plugin in pairs(Config.plugins) do + ---@type string|string[]|nil + local values = plugin[key] + if values then + if type(values) == "string" then + fn(plugin, values) + else + for _, value in ipairs(values) do + fn(plugin, value) end end end - handler(group) end end ----@param events string|string[] +---@param plugin LazyPlugin +function M.cleanup(plugin) + if plugin.keys then + local keys = type(plugin.keys) == "string" and { plugin.keys } or plugin.keys + ---@cast keys string[] + for _, k in ipairs(keys) do + pcall(vim.keymap.del, "n", k) + end + end + + if plugin.cmd then + local cmd = type(plugin.cmd) == "string" and { plugin.cmd } or plugin.cmd + ---@cast cmd string[] + for _, c in ipairs(cmd) do + pcall(vim.api.nvim_del_user_command, c) + end + end +end + +-- Get all augroups for the events +---@param event string ---@param pattern? string -function M.get_augroups(events, pattern) - -- Check for all autocmd groups listening for the events +function M.get_augroups(event, pattern) + local events = M.trigger_events[event] or { event } ---@type table local groups = {} for _, autocmd in ipairs(vim.api.nvim_get_autocmds({ event = events, pattern = pattern })) do @@ -43,25 +102,22 @@ function M.get_augroups(events, pattern) return groups end ----@param groups table ----@param events string|string[] +---@param event string|string[] ---@param pattern? string -function M.trigger(groups, events, pattern) - events = type(events) == "string" and { events } or events +---@param groups table +function M.trigger(event, pattern, groups) + local events = M.trigger_events[event] or { event } ---@cast events string[] - for _, event in ipairs(events) do - for _, autocmd in ipairs(vim.api.nvim_get_autocmds({ event = event, pattern = pattern })) do - if autocmd.event == event and autocmd.group and not groups[autocmd.group] then + for _, e in ipairs(events) do + for _, autocmd in ipairs(vim.api.nvim_get_autocmds({ event = e, pattern = pattern })) do + if autocmd.event == e and autocmd.group and not groups[autocmd.group] then if Config.options.debug then - local lines = { + Util.info({ "# Firing Events", - " - **event:** " .. autocmd.event, " - **group:** `" .. autocmd.group_name .. "`", - } - if pattern then - table.insert(lines, 2, "- **pattern:** " .. pattern) - end - Util.info(lines) + " - **event:** " .. autocmd.event, + pattern and "- **pattern:** ", + }) end Util.try(function() vim.api.nvim_exec_autocmds(autocmd.event, { group = autocmd.group, modeline = false }) @@ -71,61 +127,48 @@ function M.trigger(groups, events, pattern) end end ----@type table -M.handlers = {} -function M.handlers.event(grouped) +function M.event() + local Loader = require("lazy.core.loader") local group = vim.api.nvim_create_augroup("lazy_handler_event", { clear = true }) - for event_spec, plugins in pairs(grouped) do - if event_spec == "VeryLazy" then - event_spec = "User VeryLazy" - end - if event_spec == "VimEnter" and vim.v.vim_did_enter == 1 then - Loader.load(plugins, { event = event_spec }) - else - local event, pattern = event_spec:match("^(%w+)%s+(.*)$") - event = event or event_spec - vim.api.nvim_create_autocmd(event, { - group = group, - once = true, - pattern = pattern, - callback = function() - Util.track({ event = event_spec }) - local events = { event } - if event == "BufRead" then - events = { "BufReadPre", "BufRead" } - elseif event == "BufReadPost" then - events = { "BufReadPre", "BufRead", "BufReadPost" } - end - - local groups = M.get_augroups(events, pattern) - - -- load the plugins - Loader.load(plugins, { event = event_spec }) - - -- check if any plugin created an event handler for this event and fire the group - M.trigger(groups, events, pattern) - Util.track() - end, - }) - end - end + + M.foreach_group("event", function(plugins, event_spec) + event_spec = event_spec == "VeryLazy" and "User VeryLazy" or event_spec + local event, pattern = event_spec:match("^(%w+)%s+(.*)$") + event = event or event_spec + vim.api.nvim_create_autocmd(event, { + group = group, + once = true, + pattern = pattern, + callback = function() + Util.track({ event = event_spec }) + local groups = M.get_augroups(event, pattern) + -- load the plugins + Loader.load(plugins, { event = event_spec }) + -- check if any plugin created an event handler for this event and fire the group + M.trigger(event, pattern, groups) + Util.track() + end, + }) + end) end -function M.handlers.keys(grouped) - for keys, plugins in pairs(grouped) do +function M.keys() + local Loader = require("lazy.core.loader") + M.foreach_value("keys", function(plugin, keys) vim.keymap.set("n", keys, function() vim.keymap.del("n", keys) Util.track({ keys = keys }) - Loader.load(plugins, { keys = keys }) + Loader.load(plugin, { keys = keys }) vim.api.nvim_input(keys) Util.track() end) - end + end) end -function M.handlers.ft(grouped) +function M.ft() + local Loader = require("lazy.core.loader") local group = vim.api.nvim_create_augroup("lazy_handler_ft", { clear = true }) - for ft, plugins in pairs(grouped) do + M.foreach_group("ft", function(plugins, ft) vim.api.nvim_create_autocmd("FileType", { once = true, pattern = ft, @@ -134,23 +177,25 @@ function M.handlers.ft(grouped) Util.track({ ft = ft }) local groups = M.get_augroups("FileType", ft) Loader.load(plugins, { ft = ft }) - M.trigger(groups, "FileType", ft) + M.trigger("FileType", ft, groups) Util.track() end, }) - end + end) end -function M.handlers.cmd(grouped) - for cmd, plugins in pairs(grouped) do - local function _load() - vim.api.nvim_del_user_command(cmd) - Util.track({ cmd = cmd }) - Loader.load(plugins, { cmd = cmd }) - Util.track() - end +function M.cmd() + local Loader = require("lazy.core.loader") + local function _load(plugin, cmd) + vim.api.nvim_del_user_command(cmd) + Util.track({ cmd = cmd }) + Loader.load(plugin, { cmd = cmd }) + Util.track() + end + + M.foreach_value("cmd", function(plugin, cmd) vim.api.nvim_create_user_command(cmd, function(event) - _load() + _load(plugin, cmd) vim.cmd( ("%s %s%s%s %s"):format( event.mods or "", @@ -164,12 +209,12 @@ function M.handlers.cmd(grouped) bang = true, nargs = "*", complete = function() - _load() + _load(plugin, cmd) -- HACK: trick Neovim to show the newly loaded command completion vim.api.nvim_input("") end, }) - end + end) end return M diff --git a/lua/lazy/core/loader.lua b/lua/lazy/core/loader.lua index d57ccc38..d2f9c1c3 100644 --- a/lua/lazy/core/loader.lua +++ b/lua/lazy/core/loader.lua @@ -1,5 +1,6 @@ local Util = require("lazy.core.util") local Config = require("lazy.core.config") +local Handler = require("lazy.core.handler") local M = {} @@ -27,7 +28,6 @@ function M.setup() -- setup handlers Util.track("handlers") - local Handler = require("lazy.core.handler") Handler.setup() Util.track() @@ -81,6 +81,7 @@ function M.load(plugins, reason) table.insert(M.loading, plugin) Util.track({ plugin = plugin.name, start = reason.start }) + Handler.cleanup(plugin) vim.opt.runtimepath:prepend(plugin.dir) if not M.init_done then diff --git a/lua/lazy/core/plugin.lua b/lua/lazy/core/plugin.lua index fde3acf8..0a94fa4d 100644 --- a/lua/lazy/core/plugin.lua +++ b/lua/lazy/core/plugin.lua @@ -127,7 +127,7 @@ function Spec:merge(old, new) for k, v in pairs(new) do if k == "_" then elseif old[k] ~= nil and old[k] ~= v then - if Handler.handlers[k] then + if Handler.types[k] then local values = type(v) == "string" and { v } or v vim.list_extend(values, type(old[k]) == "string" and { old[k] } or old[k]) ---@diagnostic disable-next-line: no-unknown diff --git a/lua/lazy/core/util.lua b/lua/lazy/core/util.lua index cd734923..999c508f 100644 --- a/lua/lazy/core/util.lua +++ b/lua/lazy/core/util.lua @@ -161,7 +161,14 @@ end ---@param msg string|string[] function M.notify(msg, level) - msg = type(msg) == "table" and table.concat(msg, "\n") or msg + if type(msg) == "table" then + msg = table.concat( + vim.tbl_filter(function(line) + return line or false + end, msg), + "\n" + ) + end vim.notify(msg, level, { on_open = function(win) vim.wo[win].conceallevel = 3 diff --git a/lua/lazy/view/render.lua b/lua/lazy/view/render.lua index f9689bd7..893d14d7 100644 --- a/lua/lazy/view/render.lua +++ b/lua/lazy/view/render.lua @@ -382,7 +382,7 @@ function M:details(plugin) end end) - for handler in pairs(Handler.handlers) do + for handler in pairs(Handler.types) do if plugin[handler] then table.insert(props, { handler,