refactor(util): unify debounce helpers into Debouncer class

This commit is contained in:
2026-04-13 21:09:07 +02:00
parent 8c3f7b8d77
commit fa01343730
3 changed files with 103 additions and 110 deletions
+55 -37
View File
@@ -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(...)
local args = vim.F.pack_len(...)
if timer then
timer:stop()
timer = nil
end
---@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
timer = vim.defer_fn(function()
timer = nil
fn(vim.F.unpack_len(args))
end, delay)
---@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(...)
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
---@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
--- 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
---@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)
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. 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 ow.Util.Debouncer
function Util.debounce(fn, delay)
return Debouncer.new(fn, delay)
end
function Util.get_hl_source(name)