refactor(util): unify debounce helpers into Debouncer class
This commit is contained in:
+4
-3
@@ -425,11 +425,12 @@ function Linter.add(bufnr, config)
|
||||
return
|
||||
end
|
||||
|
||||
local debouncer = util.debounce(function()
|
||||
linter:run()
|
||||
end, config.debounce)
|
||||
vim.api.nvim_create_autocmd(config.events, {
|
||||
buffer = linter.bufnr,
|
||||
callback = util.debounce(function()
|
||||
linter:run()
|
||||
end, config.debounce),
|
||||
callback = function() debouncer:call() end,
|
||||
group = linter.augroup,
|
||||
})
|
||||
|
||||
|
||||
+36
-62
@@ -1,4 +1,5 @@
|
||||
local log = require("log")
|
||||
local util = require("util")
|
||||
|
||||
local config_dir = vim.fn.stdpath("config")
|
||||
|
||||
@@ -82,10 +83,9 @@ local function run_build(plugin)
|
||||
plugin.build(plugin)
|
||||
return
|
||||
elseif type(plugin.build) == "table" then
|
||||
local ret = vim.system(
|
||||
plugin.build --[[@as table]],
|
||||
{ cwd = plugin.path }
|
||||
):wait()
|
||||
local ret =
|
||||
vim.system(plugin.build --[[@as table]], { cwd = plugin.path })
|
||||
:wait()
|
||||
if ret.code ~= 0 then
|
||||
log.error("Build failed for %s: %s", plugin.name, ret.stderr or "")
|
||||
end
|
||||
@@ -120,7 +120,8 @@ local function process_events(plugin, events)
|
||||
end
|
||||
|
||||
for _, ev in ipairs(events) do
|
||||
if ev.data.spec.name == plugin.name
|
||||
if
|
||||
ev.data.spec.name == plugin.name
|
||||
and ev.event == "PackChanged"
|
||||
and (ev.data.kind == "install" or ev.data.kind == "update")
|
||||
then
|
||||
@@ -136,8 +137,8 @@ end
|
||||
---@type uv.uv_fs_event_t?
|
||||
local watcher = nil
|
||||
|
||||
---@type table<string, uv.uv_timer_t>
|
||||
local timers = {}
|
||||
---@type ow.Util.Debouncer?
|
||||
local reload = nil
|
||||
|
||||
---@class ow.Pack
|
||||
---@field plugins ow.Pack.Plugin[]
|
||||
@@ -147,12 +148,16 @@ local M = {
|
||||
|
||||
---@return string[]
|
||||
function M.get_names()
|
||||
return vim.tbl_map(function(p) return p.name end, M.plugins)
|
||||
return vim.tbl_map(function(p)
|
||||
return p.name
|
||||
end, M.plugins)
|
||||
end
|
||||
|
||||
---@return string[]
|
||||
function M.get_paths()
|
||||
return vim.tbl_map(function(p) return p.path end, M.plugins)
|
||||
return vim.tbl_map(function(p)
|
||||
return p.path
|
||||
end, M.plugins)
|
||||
end
|
||||
|
||||
---@param name string
|
||||
@@ -196,61 +201,29 @@ function M.watch()
|
||||
return
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
---@type uv.uv_timer_t?
|
||||
local timer = timers[filename]
|
||||
if not timer then
|
||||
timer, err_msg, err_name = vim.uv.new_timer()
|
||||
if not timer then
|
||||
log.error(
|
||||
"Failed to create new timer: %s (%s)", err_msg, err_name
|
||||
)
|
||||
return
|
||||
end
|
||||
timers[filename] = timer
|
||||
else
|
||||
timer:stop()
|
||||
end
|
||||
|
||||
timer:start(
|
||||
100,
|
||||
0,
|
||||
vim.schedule_wrap(function()
|
||||
timer:stop()
|
||||
timer:close()
|
||||
timers[filename] = nil
|
||||
|
||||
local path = plugins_dir .. "/" .. filename
|
||||
reload = util.debounce(function(filename)
|
||||
local path = vim.fs.joinpath(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
|
||||
)
|
||||
log.error("Failed to reload %s: %s", filename, load_err)
|
||||
end
|
||||
end, 100)
|
||||
|
||||
watcher:start(plugins_dir, {}, 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
|
||||
reload:call(filename)
|
||||
end)
|
||||
)
|
||||
end)
|
||||
)
|
||||
end
|
||||
|
||||
function M.unwatch()
|
||||
@@ -258,10 +231,9 @@ function M.unwatch()
|
||||
return
|
||||
end
|
||||
|
||||
for key, timer in pairs(timers) do
|
||||
timer:stop()
|
||||
timer:close()
|
||||
timers[key] = nil
|
||||
if reload then
|
||||
reload:cancel()
|
||||
reload = nil
|
||||
end
|
||||
|
||||
watcher:stop()
|
||||
@@ -281,12 +253,14 @@ function M.setup(specs)
|
||||
---@param ev ow.Pack.Event
|
||||
callback = function(ev)
|
||||
local name = ev.data.spec.name
|
||||
if not name then return end
|
||||
if not name then
|
||||
return
|
||||
end
|
||||
if not events[name] then
|
||||
events[name] = {}
|
||||
end
|
||||
table.insert(events[name], ev)
|
||||
end
|
||||
end,
|
||||
}
|
||||
)
|
||||
vim.pack.add(vim.tbl_map(to_pack_spec, specs), {
|
||||
@@ -309,7 +283,7 @@ function M.setup(specs)
|
||||
if not d.ts_parser then
|
||||
vim.cmd.packadd(plugin.name)
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_del_autocmd(id)
|
||||
|
||||
|
||||
+53
-35
@@ -295,49 +295,67 @@ function Util.is_list_or_nil(val, t)
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a debounced function that delays execution of `fn` until after `delay` milliseconds have
|
||||
--- elapsed since the last time it was invoked.
|
||||
---@param fn fun(...) Function to be debounced
|
||||
---@param delay integer Debounce delay in milliseconds
|
||||
---@return fun(...) function Debounced function
|
||||
function Util.debounce(fn, delay)
|
||||
---@type uv.uv_timer_t?
|
||||
local timer = nil
|
||||
local NIL_KEY = {}
|
||||
|
||||
return function(...)
|
||||
---@class ow.Util.Debouncer
|
||||
---@field private _fn fun(id: any, ...)
|
||||
---@field private _delay integer
|
||||
---@field private _timers table<any, uv.uv_timer_t>
|
||||
local Debouncer = {}
|
||||
Debouncer.__index = Debouncer
|
||||
|
||||
---@param fn fun(id: any, ...)
|
||||
---@param delay integer
|
||||
---@return ow.Util.Debouncer
|
||||
function Debouncer.new(fn, delay)
|
||||
return setmetatable({ _fn = fn, _delay = delay, _timers = {} }, Debouncer)
|
||||
end
|
||||
|
||||
---@param id? any
|
||||
---@param ... any
|
||||
function Debouncer:call(id, ...)
|
||||
local key = id == nil and NIL_KEY or id
|
||||
local args = vim.F.pack_len(...)
|
||||
if timer then
|
||||
timer:stop()
|
||||
timer = nil
|
||||
end
|
||||
self:cancel(id)
|
||||
self._timers[key] = vim.defer_fn(function()
|
||||
self._timers[key] = nil
|
||||
self._fn(id, vim.F.unpack_len(args))
|
||||
end, self._delay)
|
||||
end
|
||||
|
||||
timer = vim.defer_fn(function()
|
||||
timer = nil
|
||||
fn(vim.F.unpack_len(args))
|
||||
end, delay)
|
||||
---@param timer uv.uv_timer_t
|
||||
local function dispose(timer)
|
||||
timer:stop()
|
||||
timer:close()
|
||||
end
|
||||
|
||||
---@param id? any
|
||||
function Debouncer:cancel(id)
|
||||
local key = id == nil and NIL_KEY or id
|
||||
local timer = self._timers[key]
|
||||
if timer then
|
||||
dispose(timer)
|
||||
self._timers[key] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function Debouncer:cancel_all()
|
||||
for _, t in pairs(self._timers) do
|
||||
dispose(t)
|
||||
end
|
||||
self._timers = {}
|
||||
end
|
||||
|
||||
Util.Debouncer = Debouncer
|
||||
|
||||
--- Creates a debounced function that delays execution of `fn` until after `delay` milliseconds have
|
||||
--- elapsed since the last time it was invoked with the same unique identifier.
|
||||
---@param fn fun(...) Function to be debounced
|
||||
--- elapsed since the last time it was invoked. Use `d:call(id, ...)` to debounce per-id, or
|
||||
--- `d:call(...)` for a single shared slot.
|
||||
---@param fn fun(id: any, ...) Function to be debounced
|
||||
---@param delay integer Debounce delay in milliseconds
|
||||
---@return fun(id: any, ...) function Debounced function, where `id` is a unique identifier
|
||||
function Util.debounce_with_id(fn, delay)
|
||||
local map = {}
|
||||
|
||||
return function(id, ...)
|
||||
local args = vim.F.pack_len(...)
|
||||
if map[id] then
|
||||
map[id]:stop()
|
||||
map[id] = nil
|
||||
end
|
||||
|
||||
map[id] = vim.defer_fn(function()
|
||||
map[id] = nil
|
||||
fn(vim.F.unpack_len(args))
|
||||
end, delay)
|
||||
end
|
||||
---@return ow.Util.Debouncer
|
||||
function Util.debounce(fn, delay)
|
||||
return Debouncer.new(fn, delay)
|
||||
end
|
||||
|
||||
function Util.get_hl_source(name)
|
||||
|
||||
Reference in New Issue
Block a user