feat: cleanup keys/cmd handlers when loading a plugin

This commit is contained in:
Folke Lemaitre 2022-12-03 23:15:50 +01:00
parent c98e722fa4
commit 3f517abfa4
No known key found for this signature in database
GPG Key ID: 41F8B1FBACAE2040
6 changed files with 154 additions and 99 deletions

View File

@ -27,26 +27,28 @@
- [ ] unsupported props or props from other managers - [ ] unsupported props or props from other managers
- [ ] other packages still in site? - [ ] other packages still in site?
- [ ] other package manager artifacts still present? compiled etc - [ ] other package manager artifacts still present? compiled etc
- [x] rename `run` to `build` - [ ] status page showing running handlers and cache stats
- [ ] delete lazy keymaps when a plugin loads - [x] delete lazy keymaps when a plugin loads. Reset handlers for a plugin?
- [x] temp colorscheme - [ ] fix plugin details
- [x] allow setting up plugins through config **fooo** - [ ] show disabled plugins (strikethrough?)
- [x] task timeout
- [ ] log file - [ ] log file
- [ ] deal with re-sourcing init.lua. Check a global? - [ ] deal with re-sourcing init.lua. Check a global?
- [x] incorrect when switching TN from opt to start
- [ ] git tests - [ ] 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 - [ ] 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) - [ ] [packspec](https://github.com/nvim-lua/nvim-package-specification)
- [ ] add support to specify `engines`, `os` and `cpu` like in `package.json` - [ ] 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 - [ ] 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? - default semver merging strategy: if no version matches all, then use highest version?
- [ ] package meta index (package.lua cache for all packages) - [ ] 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] support for Plugin.lock
- [x] defaults for git log - [x] defaults for git log
- [x] view keybindings for update/clean/... - [x] view keybindings for update/clean/...

View File

@ -1,5 +1,4 @@
local Util = require("lazy.core.util") local Util = require("lazy.core.util")
local Loader = require("lazy.core.loader")
local Config = require("lazy.core.config") local Config = require("lazy.core.config")
---@class LazyPluginHandlers ---@class LazyPluginHandlers
@ -10,29 +9,89 @@ local Config = require("lazy.core.config")
local M = {} 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<string, string[]>) ---@alias LazyHandler fun(grouped:table<string, string[]>)
function M.setup() function M.setup()
for key, handler in pairs(M.handlers) do M.cmd()
---@type table<string, string[]> M.event()
local group = {} M.ft()
for _, plugin in pairs(Config.plugins) do M.keys()
if plugin[key] then end
---@diagnostic disable-next-line: no-unknown
for _, value in pairs(type(plugin[key]) == "table" and plugin[key] or { plugin[key] }) do ---@param key string
group[value] = group[value] or {} ---@param fn fun(plugins:LazyPlugin[], value:string)
table.insert(group[value], plugin.name) function M.foreach_group(key, fn)
end ---@type table<string, string[]>
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 end
handler(group) end
for value, plugins in pairs(group) do
fn(plugins, value)
end end
end end
---@param events string|string[] ---@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
end
end
---@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 ---@param pattern? string
function M.get_augroups(events, pattern) function M.get_augroups(event, pattern)
-- Check for all autocmd groups listening for the events local events = M.trigger_events[event] or { event }
---@type table<string,true> ---@type table<string,true>
local groups = {} local groups = {}
for _, autocmd in ipairs(vim.api.nvim_get_autocmds({ event = events, pattern = pattern })) do 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 return groups
end end
---@param groups table<string,true> ---@param event string|string[]
---@param events string|string[]
---@param pattern? string ---@param pattern? string
function M.trigger(groups, events, pattern) ---@param groups table<string,true>
events = type(events) == "string" and { events } or events function M.trigger(event, pattern, groups)
local events = M.trigger_events[event] or { event }
---@cast events string[] ---@cast events string[]
for _, event in ipairs(events) do for _, e in ipairs(events) do
for _, autocmd in ipairs(vim.api.nvim_get_autocmds({ event = event, pattern = pattern })) do for _, autocmd in ipairs(vim.api.nvim_get_autocmds({ event = e, pattern = pattern })) do
if autocmd.event == event and autocmd.group and not groups[autocmd.group] then if autocmd.event == e and autocmd.group and not groups[autocmd.group] then
if Config.options.debug then if Config.options.debug then
local lines = { Util.info({
"# Firing Events", "# Firing Events",
" - **event:** " .. autocmd.event,
" - **group:** `" .. autocmd.group_name .. "`", " - **group:** `" .. autocmd.group_name .. "`",
} " - **event:** " .. autocmd.event,
if pattern then pattern and "- **pattern:** ",
table.insert(lines, 2, "- **pattern:** " .. pattern) })
end
Util.info(lines)
end end
Util.try(function() Util.try(function()
vim.api.nvim_exec_autocmds(autocmd.event, { group = autocmd.group, modeline = false }) vim.api.nvim_exec_autocmds(autocmd.event, { group = autocmd.group, modeline = false })
@ -71,61 +127,48 @@ function M.trigger(groups, events, pattern)
end end
end end
---@type table<string, LazyHandler> function M.event()
M.handlers = {} local Loader = require("lazy.core.loader")
function M.handlers.event(grouped)
local group = vim.api.nvim_create_augroup("lazy_handler_event", { clear = true }) 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) M.foreach_group("event", function(plugins, event_spec)
event_spec = event_spec == "VeryLazy" and "User VeryLazy" or event_spec
-- load the plugins local event, pattern = event_spec:match("^(%w+)%s+(.*)$")
Loader.load(plugins, { event = event_spec }) event = event or event_spec
vim.api.nvim_create_autocmd(event, {
-- check if any plugin created an event handler for this event and fire the group group = group,
M.trigger(groups, events, pattern) once = true,
Util.track() pattern = pattern,
end, callback = function()
}) Util.track({ event = event_spec })
end local groups = M.get_augroups(event, pattern)
end -- 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 end
function M.handlers.keys(grouped) function M.keys()
for keys, plugins in pairs(grouped) do local Loader = require("lazy.core.loader")
M.foreach_value("keys", function(plugin, keys)
vim.keymap.set("n", keys, function() vim.keymap.set("n", keys, function()
vim.keymap.del("n", keys) vim.keymap.del("n", keys)
Util.track({ keys = keys }) Util.track({ keys = keys })
Loader.load(plugins, { keys = keys }) Loader.load(plugin, { keys = keys })
vim.api.nvim_input(keys) vim.api.nvim_input(keys)
Util.track() Util.track()
end) end)
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 }) 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", { vim.api.nvim_create_autocmd("FileType", {
once = true, once = true,
pattern = ft, pattern = ft,
@ -134,23 +177,25 @@ function M.handlers.ft(grouped)
Util.track({ ft = ft }) Util.track({ ft = ft })
local groups = M.get_augroups("FileType", ft) local groups = M.get_augroups("FileType", ft)
Loader.load(plugins, { ft = ft }) Loader.load(plugins, { ft = ft })
M.trigger(groups, "FileType", ft) M.trigger("FileType", ft, groups)
Util.track() Util.track()
end, end,
}) })
end end)
end end
function M.handlers.cmd(grouped) function M.cmd()
for cmd, plugins in pairs(grouped) do local Loader = require("lazy.core.loader")
local function _load() local function _load(plugin, cmd)
vim.api.nvim_del_user_command(cmd) vim.api.nvim_del_user_command(cmd)
Util.track({ cmd = cmd }) Util.track({ cmd = cmd })
Loader.load(plugins, { cmd = cmd }) Loader.load(plugin, { cmd = cmd })
Util.track() Util.track()
end end
M.foreach_value("cmd", function(plugin, cmd)
vim.api.nvim_create_user_command(cmd, function(event) vim.api.nvim_create_user_command(cmd, function(event)
_load() _load(plugin, cmd)
vim.cmd( vim.cmd(
("%s %s%s%s %s"):format( ("%s %s%s%s %s"):format(
event.mods or "", event.mods or "",
@ -164,12 +209,12 @@ function M.handlers.cmd(grouped)
bang = true, bang = true,
nargs = "*", nargs = "*",
complete = function() complete = function()
_load() _load(plugin, cmd)
-- HACK: trick Neovim to show the newly loaded command completion -- HACK: trick Neovim to show the newly loaded command completion
vim.api.nvim_input("<space><bs><tab>") vim.api.nvim_input("<space><bs><tab>")
end, end,
}) })
end end)
end end
return M return M

View File

@ -1,5 +1,6 @@
local Util = require("lazy.core.util") local Util = require("lazy.core.util")
local Config = require("lazy.core.config") local Config = require("lazy.core.config")
local Handler = require("lazy.core.handler")
local M = {} local M = {}
@ -27,7 +28,6 @@ function M.setup()
-- setup handlers -- setup handlers
Util.track("handlers") Util.track("handlers")
local Handler = require("lazy.core.handler")
Handler.setup() Handler.setup()
Util.track() Util.track()
@ -81,6 +81,7 @@ function M.load(plugins, reason)
table.insert(M.loading, plugin) table.insert(M.loading, plugin)
Util.track({ plugin = plugin.name, start = reason.start }) Util.track({ plugin = plugin.name, start = reason.start })
Handler.cleanup(plugin)
vim.opt.runtimepath:prepend(plugin.dir) vim.opt.runtimepath:prepend(plugin.dir)
if not M.init_done then if not M.init_done then

View File

@ -127,7 +127,7 @@ function Spec:merge(old, new)
for k, v in pairs(new) do for k, v in pairs(new) do
if k == "_" then if k == "_" then
elseif old[k] ~= nil and old[k] ~= v 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 local values = type(v) == "string" and { v } or v
vim.list_extend(values, type(old[k]) == "string" and { old[k] } or old[k]) vim.list_extend(values, type(old[k]) == "string" and { old[k] } or old[k])
---@diagnostic disable-next-line: no-unknown ---@diagnostic disable-next-line: no-unknown

View File

@ -161,7 +161,14 @@ end
---@param msg string|string[] ---@param msg string|string[]
function M.notify(msg, level) 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, { vim.notify(msg, level, {
on_open = function(win) on_open = function(win)
vim.wo[win].conceallevel = 3 vim.wo[win].conceallevel = 3

View File

@ -382,7 +382,7 @@ function M:details(plugin)
end end
end) end)
for handler in pairs(Handler.handlers) do for handler in pairs(Handler.types) do
if plugin[handler] then if plugin[handler] then
table.insert(props, { table.insert(props, {
handler, handler,