Files
nvim/lua/plugin.lua
T

166 lines
3.9 KiB
Lua

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 = {}
---@param plugin ow.Plugin
local function load(plugin)
vim.cmd.packadd(plugin.name)
local name = plugin.name:match("[^.]+"):lower()
local path = string.format(
"%s/lua/plugins/%s.lua",
vim.fn.stdpath("config"),
name
)
if vim.uv.fs_stat(path) then
local ok, err = pcall(dofile, path)
if not ok then
log.error("Failed to load %s: %s", name, err)
end
end
end
---@param spec string | ow.Plugin.Spec
---@return vim.pack.Spec
local function to_pack_spec(spec)
if type(spec) == "string" then
return { src = spec }
end
return {
src = spec[1],
name = spec.name,
version = spec.version,
data = {
lazy = spec.lazy,
build = spec.build,
},
}
end
---@param plugin ow.Plugin
---@return boolean success
local function run_build(plugin)
if type(plugin.build) == "function" then
return plugin.build(plugin)
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
end
log.error("invalid build parameter for %s", plugin.name)
return false
end
---@class ow.Plugin.PackEvent.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
---@param plugin ow.Plugin
---@param events ow.Plugin.PackEvent[]
---@return boolean success
local function handle_pack_events(plugin, events)
if not plugin.build then
return true
end
for _, ev in ipairs(events) do
if ev.data.spec.name == plugin.name
and ev.event == "PackChanged"
and (ev.data.kind == "install" or ev.data.kind == "update")
then
vim.cmd.packadd(plugin.name)
return run_build(plugin)
end
end
return true
end
local M = {}
function M.get_paths()
local paths = {}
for _, plugin in ipairs(plugins) do
table.insert(paths, plugin.path)
end
return paths
end
---@param specs (string | ow.Plugin.Spec)[]
function M.setup(specs)
---@type ow.Plugin.PackEvent[]
local events = {}
local id = vim.api.nvim_create_autocmd(
{ "PackChangedPre", "PackChanged" },
{
---@param ev ow.Plugin.PackEvent
callback = function(ev)
table.insert(events, ev)
end
}
)
vim.pack.add(vim.tbl_map(to_pack_spec, specs), {
load = function(data)
local d = data.spec.data or {}
---@type ow.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)
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
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