diff --git a/lua/lazy/core/handler.lua b/lua/lazy/core/handler.lua deleted file mode 100644 index 111bca5..0000000 --- a/lua/lazy/core/handler.lua +++ /dev/null @@ -1,220 +0,0 @@ -local Util = require("lazy.core.util") -local Config = require("lazy.core.config") - ----@class LazyPluginHandlers ----@field event? string|string[] ----@field cmd? string|string[] ----@field ft? string|string[] ----@field keys? string|string[] - -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() - 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 - 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 -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 - if autocmd.group then - groups[autocmd.group] = true - end - end - return groups -end - ----@param event string|string[] ----@param pattern? string ----@param groups table -function M.trigger(event, pattern, groups) - local events = M.trigger_events[event] or { event } - ---@cast events string[] - 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 - Util.info({ - "# Firing Events", - " - **group:** `" .. autocmd.group_name .. "`", - " - **event:** " .. autocmd.event, - pattern and "- **pattern:** ", - }) - end - Util.try(function() - vim.api.nvim_exec_autocmds(autocmd.event, { group = autocmd.group, modeline = false }) - end) - end - end - end -end - -function M.event() - local Loader = require("lazy.core.loader") - local group = vim.api.nvim_create_augroup("lazy_handler_event", { clear = true }) - - 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.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(plugin, { keys = keys }) - vim.api.nvim_input(keys) - Util.track() - end) - end) -end - -function M.ft() - local Loader = require("lazy.core.loader") - local group = vim.api.nvim_create_augroup("lazy_handler_ft", { clear = true }) - M.foreach_group("ft", function(plugins, ft) - vim.api.nvim_create_autocmd("FileType", { - once = true, - pattern = ft, - group = group, - callback = function() - Util.track({ ft = ft }) - local groups = M.get_augroups("FileType", ft) - Loader.load(plugins, { ft = ft }) - M.trigger("FileType", ft, groups) - Util.track() - end, - }) - end) -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(plugin, cmd) - vim.cmd( - ("%s %s%s%s %s"):format( - event.mods or "", - event.line1 == event.line2 and "" or event.line1 .. "," .. event.line2, - cmd, - event.bang and "!" or "", - event.args or "" - ) - ) - end, { - bang = true, - nargs = "*", - complete = function() - _load(plugin, cmd) - -- HACK: trick Neovim to show the newly loaded command completion - vim.api.nvim_input("") - end, - }) - end) -end - -return M diff --git a/lua/lazy/core/handler/cmd.lua b/lua/lazy/core/handler/cmd.lua new file mode 100644 index 0000000..3ebba86 --- /dev/null +++ b/lua/lazy/core/handler/cmd.lua @@ -0,0 +1,45 @@ +local Util = require("lazy.core.util") +local Loader = require("lazy.core.loader") + +---@class LazyCmdHandler:LazyHandler +local M = {} + +local function _load(plugin, cmd) + vim.api.nvim_del_user_command(cmd) + Util.track({ cmd = cmd }) + Loader.load(plugin, { cmd = cmd }) + Util.track() +end + +---@param plugin LazyPlugin +---@param cmd string +function M:_add(plugin, cmd) + vim.api.nvim_create_user_command(cmd, function(event) + _load(plugin, cmd) + vim.cmd( + ("%s %s%s%s %s"):format( + event.mods or "", + event.line1 == event.line2 and "" or event.line1 .. "," .. event.line2, + cmd, + event.bang and "!" or "", + event.args or "" + ) + ) + end, { + bang = true, + nargs = "*", + complete = function() + _load(plugin, cmd) + -- HACK: trick Neovim to show the newly loaded command completion + vim.api.nvim_input("") + end, + }) +end + +---@param _plugin LazyPlugin +---@param value string +function M:_del(_plugin, value) + pcall(vim.api.nvim_del_user_command, value) +end + +return M diff --git a/lua/lazy/core/handler/event.lua b/lua/lazy/core/handler/event.lua new file mode 100644 index 0000000..545f42b --- /dev/null +++ b/lua/lazy/core/handler/event.lua @@ -0,0 +1,97 @@ +local Util = require("lazy.core.util") +local Config = require("lazy.core.config") +local Loader = require("lazy.core.loader") + +---@class LazyEventHandler:LazyHandler +---@field events table +---@field group number +local M = {} + +M.trigger_events = { + BufRead = { "BufReadPre", "BufRead" }, + BufReadPost = { "BufReadPre", "BufRead", "BufReadPost" }, +} + +function M:init() + self.group = vim.api.nvim_create_augroup("lazy_handler_" .. self.type, { clear = true }) + self.events = {} +end + +---@param event_spec string +function M:_add(_, event_spec) + if not self.events[event_spec] then + self:listen(event_spec) + end +end + +---@param value string +function M:_value(value) + return value == "VeryLazy" and "User VeryLazy" or value +end + +function M:listen(event_spec) + self.events[event_spec] = true + ---@type string?, string? + local event, pattern = event_spec:match("^(%w+)%s+(.*)$") + event = event or event_spec + vim.api.nvim_create_autocmd(event, { + group = self.group, + once = true, + pattern = pattern, + callback = function() + if not self.active[event_spec] then + return + end + Util.track({ [self.type] = event_spec }) + local groups = M.get_augroups(event, pattern) + -- load the plugins + Loader.load(self.active[event_spec], { [self.type] = event_spec }) + self.events[event_spec] = nil + -- check if any plugin created an event handler for this event and fire the group + M.trigger(event, pattern, groups) + Util.track() + end, + }) +end + +-- Get all augroups for the events +---@param event string +---@param pattern? string +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 + if autocmd.group then + groups[autocmd.group] = true + end + end + return groups +end + +---@param event string|string[] +---@param pattern? string +---@param groups table +function M.trigger(event, pattern, groups) + local events = M.trigger_events[event] or { event } + ---@cast events string[] + 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 + Util.info({ + "# Firing Events", + " - **group:** `" .. autocmd.group_name .. "`", + " - **event:** " .. autocmd.event, + pattern and "- **pattern:** ", + }) + end + Util.try(function() + vim.api.nvim_exec_autocmds(autocmd.event, { group = autocmd.group, modeline = false }) + end) + end + end + end +end + +return M diff --git a/lua/lazy/core/handler/ft.lua b/lua/lazy/core/handler/ft.lua new file mode 100644 index 0000000..c9ff096 --- /dev/null +++ b/lua/lazy/core/handler/ft.lua @@ -0,0 +1,20 @@ +local Event = require("lazy.core.handler.event") +local Loader = require("lazy.core.loader") + +---@class LazyFiletypeHandler:LazyEventHandler +local M = {} +M.extends = Event + +---@param value string +function M:_value(value) + return "FileType " .. value +end + +---@param plugin LazyPlugin +---@param value string +function M:_add(plugin, value) + Loader.ftdetect(plugin) + Event._add(self, plugin, value) +end + +return M diff --git a/lua/lazy/core/handler/init.lua b/lua/lazy/core/handler/init.lua new file mode 100644 index 0000000..be229c1 --- /dev/null +++ b/lua/lazy/core/handler/init.lua @@ -0,0 +1,123 @@ +local Config = require("lazy.core.config") + +---@class LazyPluginHandlers: table +---@field event? string|string[] +---@field cmd? string|string[] +---@field ft? string|string[] +---@field keys? string|string[] + +---@class LazyHandler +---@field type LazyHandlerTypes +---@field extends? LazyHandler +---@field active table> +local M = {} + +---@enum LazyHandlerTypes +M.types = { + keys = "keys", + event = "event", + cmd = "cmd", + ft = "ft", +} + +---@type table +M.handlers = {} + +function M.setup() + for _, type in pairs(M.types) do + M.handlers[type] = M.new(type) + end + for _, plugin in pairs(Config.plugins) do + M.enable(plugin) + end +end + +---@param plugin LazyPlugin +function M.disable(plugin) + for type, handler in pairs(M.handlers) do + if plugin[type] then + handler:del(plugin) + end + end +end + +---@param plugin LazyPlugin +function M.enable(plugin) + if not plugin._.loaded then + for type, handler in pairs(M.handlers) do + if plugin[type] then + handler:add(plugin) + end + end + end +end + +---@param type LazyHandlerTypes +function M.new(type) + ---@type LazyHandler + local handler = require("lazy.core.handler." .. type) + local self = setmetatable({}, { + __index = function(_, k) + return handler[k] or (handler.extends and handler.extends[k]) or M[k] + end, + }) + self.active = {} + self.type = type + self:init() + return self +end + +---@protected +function M:init() end + +---@param plugin LazyPlugin +---@param value string +---@protected +function M:_add(plugin, value) end + +---@param plugin LazyPlugin +---@param value string +---@protected +function M:_del(plugin, value) end + +---@param value string +function M:_value(value) + return value +end + +---@param values? string|string[] +---@param fn fun(value:string) +function M:foreach(values, fn) + if type(values) == "string" then + fn(values) + elseif values ~= nil then + for _, value in ipairs(values) do + fn(value) + end + end +end + +---@param plugin LazyPlugin +function M:add(plugin) + self:foreach(plugin[self.type], function(value) + value = self:_value(value) + if not (self.active[value] and self.active[value][plugin.name]) then + self.active[value] = self.active[value] or {} + self.active[value][plugin.name] = plugin.name + self:_add(plugin, value) + end + end) +end + +---@param plugin LazyPlugin +function M:del(plugin) + self:foreach(plugin[self.type], function(value) + value = self:_value(value) + if self.active[value] and self.active[value][plugin.name] then + self.active[value][plugin.name] = nil + self:_del(plugin, value) + end + end) +end + +return M diff --git a/lua/lazy/core/handler/keys.lua b/lua/lazy/core/handler/keys.lua new file mode 100644 index 0000000..14827f2 --- /dev/null +++ b/lua/lazy/core/handler/keys.lua @@ -0,0 +1,25 @@ +local Util = require("lazy.core.util") +local Loader = require("lazy.core.loader") + +---@class LazyKeysHandler:LazyHandler +local M = {} + +---@param plugin LazyPlugin +---@param keys string +function M:_add(plugin, keys) + vim.keymap.set("n", keys, function() + vim.keymap.del("n", keys) + Util.track({ keys = keys }) + Loader.load(plugin, { keys = keys }) + vim.api.nvim_input(keys) + Util.track() + end) +end + +---@param _plugin LazyPlugin +---@param value string +function M:_del(_plugin, value) + pcall(vim.keymap.del, "n", value) +end + +return M diff --git a/lua/lazy/core/loader.lua b/lua/lazy/core/loader.lua index d2f9c1c..95a0c80 100644 --- a/lua/lazy/core/loader.lua +++ b/lua/lazy/core/loader.lua @@ -62,7 +62,7 @@ function M.load(plugins, reason) plugins = (type(plugins) == "string" or plugins.name) and { plugins } or plugins ---@cast plugins (string|LazyPlugin)[] - for _, plugin in ipairs(plugins) do + for _, plugin in pairs(plugins) do plugin = type(plugin) == "string" and Config.plugins[plugin] or plugin ---@cast plugin LazyPlugin @@ -81,7 +81,7 @@ function M.load(plugins, reason) table.insert(M.loading, plugin) Util.track({ plugin = plugin.name, start = reason.start }) - Handler.cleanup(plugin) + Handler.disable(plugin) vim.opt.runtimepath:prepend(plugin.dir) if not M.init_done then @@ -114,18 +114,20 @@ end ---@param plugin LazyPlugin function M.packadd(plugin) - -- FIXME: investigate further what else is needed - -- vim.cmd.packadd(plugin.name) - -- M.source_runtime(plugin, "/after/plugin") if M.init_done then M.source_runtime(plugin.dir, "plugin") - if vim.g.did_load_filetypes == 1 then - M.source_runtime(plugin.dir, "ftdetect") - end + M.ftdetect(plugin) M.source_runtime(plugin.dir, "after/plugin") end end +---@param plugin LazyPlugin +function M.ftdetect(plugin) + vim.cmd("augroup filetypedetect") + M.source_runtime(plugin.dir, "ftdetect") + vim.cmd("augroup END") +end + ---@param ... string function M.source_runtime(...) local dir = table.concat({ ... }, "/")