feat(plugin): add hot-reload support for plugin configs
This commit is contained in:
@@ -1,3 +1,23 @@
|
|||||||
vim.api.nvim_create_user_command("W", "w", { desc = "Alias to :w" })
|
vim.api.nvim_create_user_command("W", "w", { desc = "Alias to :w" })
|
||||||
vim.api.nvim_create_user_command("Q", "q", { desc = "Alias to :q" })
|
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("Qa", "q", { desc = "Alias to :qa" })
|
||||||
|
|
||||||
|
vim.api.nvim_create_user_command("PluginWatch", function()
|
||||||
|
require("plugin").watch()
|
||||||
|
end, { desc = "Watch plugin configs for changes and hot-reload" })
|
||||||
|
|
||||||
|
vim.api.nvim_create_user_command("PluginUnwatch", function()
|
||||||
|
require("plugin").unwatch()
|
||||||
|
end, { desc = "Stop watching plugin configs" })
|
||||||
|
|
||||||
|
vim.api.nvim_create_user_command("PluginReload", function(opts)
|
||||||
|
require("plugin").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,
|
||||||
|
desc = "Reload a plugin config by name",
|
||||||
|
})
|
||||||
|
|||||||
+130
-1
@@ -13,6 +13,23 @@ local log = require("log")
|
|||||||
---@type ow.Plugin[]
|
---@type ow.Plugin[]
|
||||||
local plugins = {}
|
local plugins = {}
|
||||||
|
|
||||||
|
---@param path string
|
||||||
|
---@return boolean success
|
||||||
|
---@return string? err
|
||||||
|
local function exec(path)
|
||||||
|
local chunk, load_err = loadfile(path)
|
||||||
|
if not chunk then
|
||||||
|
return false, load_err
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, call_err = pcall(chunk)
|
||||||
|
if not ok then
|
||||||
|
return false, call_err
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
---@param plugin ow.Plugin
|
---@param plugin ow.Plugin
|
||||||
local function load(plugin)
|
local function load(plugin)
|
||||||
vim.cmd.packadd(plugin.name)
|
vim.cmd.packadd(plugin.name)
|
||||||
@@ -25,7 +42,7 @@ local function load(plugin)
|
|||||||
)
|
)
|
||||||
|
|
||||||
if vim.uv.fs_stat(path) then
|
if vim.uv.fs_stat(path) then
|
||||||
local ok, err = pcall(dofile, path)
|
local ok, err = exec(path)
|
||||||
if not ok then
|
if not ok then
|
||||||
log.error("Failed to load %s: %s", name, err)
|
log.error("Failed to load %s: %s", name, err)
|
||||||
end
|
end
|
||||||
@@ -97,6 +114,9 @@ local function handle_pack_events(plugin, events)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type uv.uv_fs_event_t?
|
||||||
|
local watcher = nil
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
function M.get_paths()
|
function M.get_paths()
|
||||||
@@ -109,6 +129,115 @@ function M.get_paths()
|
|||||||
return paths
|
return paths
|
||||||
end
|
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
|
||||||
|
|
||||||
|
---@param name string
|
||||||
|
function M.reload(name)
|
||||||
|
local path = string.format(
|
||||||
|
"%s/lua/plugins/%s.lua",
|
||||||
|
vim.fn.stdpath("config"),
|
||||||
|
name
|
||||||
|
)
|
||||||
|
|
||||||
|
if not vim.uv.fs_stat(path) then
|
||||||
|
log.error("No config file found for %s", name)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, err = exec(path)
|
||||||
|
if ok then
|
||||||
|
log.info("Reloaded %s", name)
|
||||||
|
else
|
||||||
|
log.error("Failed to reload %s: %s", name, err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.watch()
|
||||||
|
if watcher then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local plugins_dir = string.format(
|
||||||
|
"%s/lua/plugins",
|
||||||
|
vim.fn.stdpath("config")
|
||||||
|
)
|
||||||
|
|
||||||
|
watcher = vim.uv.new_fs_event()
|
||||||
|
if not watcher then
|
||||||
|
log.error("Failed to create fs_event watcher")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
---@type table<string, uv.uv_timer_t>
|
||||||
|
local timers = {}
|
||||||
|
|
||||||
|
watcher:start(
|
||||||
|
plugins_dir,
|
||||||
|
{},
|
||||||
|
vim.schedule_wrap(function(err, filename)
|
||||||
|
if err then
|
||||||
|
log.error("Watch error: %s", err)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not filename or not filename:match("%.lua$") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if timers[filename] then
|
||||||
|
timers[filename]:stop()
|
||||||
|
else
|
||||||
|
timers[filename] = vim.uv.new_timer()
|
||||||
|
end
|
||||||
|
|
||||||
|
timers[filename]:start(
|
||||||
|
100,
|
||||||
|
0,
|
||||||
|
vim.schedule_wrap(function()
|
||||||
|
timers[filename]:stop()
|
||||||
|
timers[filename]:close()
|
||||||
|
timers[filename] = nil
|
||||||
|
|
||||||
|
local path = plugins_dir .. "/" .. filename
|
||||||
|
if not vim.uv.fs_stat(path) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, load_err = exec(path)
|
||||||
|
if ok then
|
||||||
|
log.info("Reloaded %s", filename)
|
||||||
|
else
|
||||||
|
log.error(
|
||||||
|
"Failed to reload %s: %s",
|
||||||
|
filename,
|
||||||
|
load_err
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.unwatch()
|
||||||
|
if not watcher then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
watcher:stop()
|
||||||
|
watcher:close()
|
||||||
|
watcher = nil
|
||||||
|
end
|
||||||
|
|
||||||
---@param specs (string | ow.Plugin.Spec)[]
|
---@param specs (string | ow.Plugin.Spec)[]
|
||||||
function M.setup(specs)
|
function M.setup(specs)
|
||||||
---@type ow.Plugin.PackEvent[]
|
---@type ow.Plugin.PackEvent[]
|
||||||
|
|||||||
Reference in New Issue
Block a user