refactor: simplify plugin loader

This commit is contained in:
2026-04-11 22:55:51 +02:00
parent eb96536a8f
commit ec81afbab7
5 changed files with 82 additions and 117 deletions
+2 -12
View File
@@ -1,19 +1,9 @@
My Neovim config.
## System Requirements
Only supports Linux, macOS and other BSD variants. Requires neovim v0.12.
Below is a list of dependencies and the respective plugins that require it.
| Dependency | Plugins |
| ------------ | ----------------------------------------- |
| git | lazy, mason |
| C compiler | treesitter, LuaSnip, telescope-fzf-native |
| make | LuaSnip, telescope-fzf-native |
| curl or wget | mason |
| unzip | mason |
| GNU tar | mason |
| gzip | mason |
## License
BSD-3-Clause, see [LICENSE](LICENSE) for more information.
+2 -2
View File
@@ -1,7 +1,7 @@
local lsp = require("lsp")
local lua_library_paths = require("plugin").get_paths()
table.insert(lua_library_paths, vim.env.VIMRUNTIME)
local lua_library_paths = { vim.env.VIMRUNTIME }
vim.list_extend(lua_library_paths, require("pack").paths)
---@type vim.lsp.Config
return {
+1 -1
View File
@@ -21,7 +21,7 @@ for _, file in ipairs(files) do
end
end
require("plugin").setup({
require("pack").setup({
"https://github.com/navarasu/onedark.nvim",
"https://github.com/nvim-lua/plenary.nvim",
"https://github.com/rcarriga/nvim-notify",
+4 -4
View File
@@ -3,21 +3,21 @@ vim.api.nvim_create_user_command("Q", "q", { desc = "Alias to :q" })
vim.api.nvim_create_user_command("Qa", "q", { desc = "Alias to :qa" })
vim.api.nvim_create_user_command("PluginWatch", function()
require("plugin").watch()
require("pack").watch()
end, { desc = "Watch plugin configs for changes and hot-reload" })
vim.api.nvim_create_user_command("PluginUnwatch", function()
require("plugin").unwatch()
require("pack").unwatch()
end, { desc = "Stop watching plugin configs" })
vim.api.nvim_create_user_command("PluginReload", function(opts)
require("plugin").reload(opts.args)
require("pack").reload(opts.args)
end, {
nargs = 1,
complete = function(lead)
return vim.tbl_filter(function(name)
return name:find(lead, 1, true) == 1
end, require("plugin").get_names())
end, require("pack").names)
end,
desc = "Reload a plugin config by name",
})
+72 -97
View File
@@ -1,17 +1,6 @@
local log = require("log")
---@class ow.Plugin.Spec
---@field [1] string
---@field name? string
---@field version? string | vim.VersionRange
---@field lazy? boolean
---@field build? string[] | fun(self: ow.Plugin): boolean
---@class ow.Plugin : ow.Plugin.Spec
---@field path string
---@type ow.Plugin[]
local plugins = {}
local config_dir = vim.fn.stdpath("config")
---@param path string
---@return boolean success
@@ -30,16 +19,20 @@ local function exec(path)
return true
end
---@param plugin ow.Plugin
local function load(plugin)
vim.cmd.packadd(plugin.name)
---@class ow.Pack.PluginSpec
---@field [1] string
---@field name? string
---@field version? string | vim.VersionRange
---@field build? string[] | fun(self: ow.Pack.Plugin)
---@class ow.Pack.Plugin : ow.Pack.PluginSpec
---@field name string
---@field path string
---@param plugin ow.Pack.Plugin
local function load(plugin)
local name = plugin.name:match("[^.]+"):lower()
local path = string.format(
"%s/lua/plugins/%s.lua",
vim.fn.stdpath("config"),
name
)
local path = string.format("%s/lua/plugins/%s.lua", config_dir, name)
if vim.uv.fs_stat(path) then
local ok, err = exec(path)
@@ -49,7 +42,7 @@ local function load(plugin)
end
end
---@param spec string | ow.Plugin.Spec
---@param spec string | ow.Pack.PluginSpec
---@return vim.pack.Spec
local function to_pack_spec(spec)
if type(spec) == "string" then
@@ -61,44 +54,44 @@ local function to_pack_spec(spec)
name = spec.name,
version = spec.version,
data = {
lazy = spec.lazy,
build = spec.build,
},
}
end
---@param plugin ow.Plugin
---@return boolean success
---@param plugin ow.Pack.Plugin
local function run_build(plugin)
if type(plugin.build) == "function" then
return plugin.build(plugin)
plugin.build(plugin)
return
elseif type(plugin.build) == "table" then
local ret = vim.system(
plugin.build --[[@as table]],
{ cwd = plugin.path }
):wait()
return ret.code == 0 and ret.signal == 0
if ret.code ~= 0 then
log.error("Build failed for %s: %s", plugin.name, ret.stderr or "")
end
return
end
log.error("invalid build parameter for %s", plugin.name)
return false
end
---@class ow.Plugin.PackEvent.Data
---@class ow.Pack.Event.Data
---@field active boolean
---@field kind "install" | "update" | "delete"
---@field spec vim.pack.Spec
---@field path string
---@class ow.Plugin.PackEvent : vim.api.keyset.create_autocmd.callback_args
---@field data ow.Plugin.PackEvent.Data
---@class ow.Pack.Event : vim.api.keyset.create_autocmd.callback_args
---@field data ow.Pack.Event.Data
---@param plugin ow.Plugin
---@param events ow.Plugin.PackEvent[]
---@return boolean success
local function handle_pack_events(plugin, events)
---@param plugin ow.Pack.Plugin
---@param events ow.Pack.Event[]
local function process_events(plugin, events)
if not plugin.build then
return true
return
end
for _, ev in ipairs(events) do
@@ -106,47 +99,30 @@ local function handle_pack_events(plugin, events)
and ev.event == "PackChanged"
and (ev.data.kind == "install" or ev.data.kind == "update")
then
vim.cmd.packadd(plugin.name)
return run_build(plugin)
run_build(plugin)
end
end
return true
end
---@type uv.uv_fs_event_t?
local watcher = nil
local M = {}
---@type table<string, uv.uv_timer_t>
local timers = {}
function M.get_paths()
local paths = {}
for _, plugin in ipairs(plugins) do
table.insert(paths, plugin.path)
end
return paths
end
---@return string[]
function M.get_names()
local names = {}
for _, plugin in ipairs(plugins) do
table.insert(names, plugin.name:match("[^.]+"):lower())
end
return names
end
---@class ow.Pack
---@field names string[]
---@field paths string[]
---@field plugins ow.Pack.Plugin[]
local M = {
names = {},
paths = {},
plugins = {},
}
---@param name string
function M.reload(name)
local path = string.format(
"%s/lua/plugins/%s.lua",
vim.fn.stdpath("config"),
name
)
local path = string.format("%s/lua/plugins/%s.lua", config_dir, name)
if not vim.uv.fs_stat(path) then
log.error("No config file found for %s", name)
@@ -166,10 +142,7 @@ function M.watch()
return
end
local plugins_dir = string.format(
"%s/lua/plugins",
vim.fn.stdpath("config")
)
local plugins_dir = config_dir .. "/lua/plugins"
watcher = vim.uv.new_fs_event()
if not watcher then
@@ -177,9 +150,6 @@ function M.watch()
return
end
---@type table<string, uv.uv_timer_t>
local timers = {}
watcher:start(
plugins_dir,
{},
@@ -233,62 +203,67 @@ function M.unwatch()
return
end
for key, timer in pairs(timers) do
timer:stop()
timer:close()
timers[key] = nil
end
watcher:stop()
watcher:close()
watcher = nil
end
---@param specs (string | ow.Plugin.Spec)[]
---@param specs (string | ow.Pack.PluginSpec)[]
function M.setup(specs)
---@type ow.Plugin.PackEvent[]
---@type table<string, ow.Pack.Event[]?>
local events = {}
local group = vim.api.nvim_create_augroup("ow.Pack", { clear = true })
local id = vim.api.nvim_create_autocmd(
{ "PackChangedPre", "PackChanged" },
{
---@param ev ow.Plugin.PackEvent
group = group,
---@param ev ow.Pack.Event
callback = function(ev)
table.insert(events, ev)
local name = ev.data.spec.name
if not name then return end
if not events[name] then
events[name] = {}
end
table.insert(events[name], ev)
end
}
)
vim.pack.add(vim.tbl_map(to_pack_spec, specs), {
load = function(data)
if not data.spec.name then
log.error("Missing name for plugin: %s", data.spec.src)
return
end
local d = data.spec.data or {}
---@type ow.Plugin
---@type ow.Pack.Plugin
local plugin = {
[1] = data.spec.src,
name = data.spec.name,
version = data.spec.version,
lazy = d.lazy or false,
build = d.build,
path = data.path,
}
table.insert(plugins, plugin)
table.insert(M.plugins, plugin)
table.insert(M.names, plugin.name)
table.insert(M.paths, plugin.path)
vim.cmd.packadd(plugin.name)
end
})
vim.api.nvim_del_autocmd(id)
local lazy_plugins = {}
for _, plugin in ipairs(plugins) do
if not handle_pack_events(plugin, events) then
return
for _, plugin in ipairs(M.plugins) do
local ev = events[plugin.name]
if ev then
process_events(plugin, ev)
end
if plugin.lazy then
table.insert(lazy_plugins, plugin)
else
load(plugin)
end
end
vim.api.nvim_create_autocmd("UIEnter", {
once = true,
callback = vim.schedule_wrap(function()
for _, plugin in ipairs(lazy_plugins) do
load(plugin)
end
end)
})
end
return M