Skip to content

Commit

Permalink
feat: cleanup keys/cmd handlers when loading a plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
folke committed Dec 3, 2022
1 parent c98e722 commit 3f517ab
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 99 deletions.
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/...
Expand Down
213 changes: 129 additions & 84 deletions lua/lazy/core/handler.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
local Util = require("lazy.core.util")
local Loader = require("lazy.core.loader")
local Config = require("lazy.core.config")

---@class LazyPluginHandlers
Expand All @@ -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<string, string[]>)

function M.setup()
for key, handler in pairs(M.handlers) do
---@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)
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<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
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<string,true>
local groups = {}
for _, autocmd in ipairs(vim.api.nvim_get_autocmds({ event = events, pattern = pattern })) do
Expand All @@ -43,25 +102,22 @@ function M.get_augroups(events, pattern)
return groups
end

---@param groups table<string,true>
---@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<string,true>
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 })
Expand All @@ -71,61 +127,48 @@ function M.trigger(groups, events, pattern)
end
end

---@type table<string, LazyHandler>
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,
Expand All @@ -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 "",
Expand All @@ -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("<space><bs><tab>")
end,
})
end
end)
end

return M
3 changes: 2 additions & 1 deletion lua/lazy/core/loader.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local Util = require("lazy.core.util")
local Config = require("lazy.core.config")
local Handler = require("lazy.core.handler")

local M = {}

Expand Down Expand Up @@ -27,7 +28,6 @@ function M.setup()

-- setup handlers
Util.track("handlers")
local Handler = require("lazy.core.handler")
Handler.setup()
Util.track()

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lua/lazy/core/plugin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion lua/lazy/core/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lua/lazy/view/render.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 3f517ab

Please sign in to comment.