1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 05:30:07 +08:00
SpaceVim/bundle/telescope.nvim/lua/telescope/debounce.lua
2022-05-16 22:20:10 +08:00

180 lines
4.7 KiB
Lua
Vendored

-- Credit: https://gist.github.com/runiq/31aa5c4bf00f8e0843cd267880117201
--
local M = {}
---Validates args for `throttle()` and `debounce()`.
local function td_validate(fn, ms)
vim.validate {
fn = { fn, "f" },
ms = {
ms,
function(v)
return type(v) == "number" and v > 0
end,
"number > 0",
},
}
end
--- Throttles a function on the leading edge. Automatically `schedule_wrap()`s.
---
--@param fn (function) Function to throttle
--@param timeout (number) Timeout in ms
--@returns (function, timer) throttled function and timer. Remember to call
---`timer:close()` at the end or you will leak memory!
function M.throttle_leading(fn, ms)
td_validate(fn, ms)
local timer = vim.loop.new_timer()
local running = false
local function wrapped_fn(...)
if not running then
timer:start(ms, 0, function()
running = false
end)
running = true
pcall(vim.schedule_wrap(fn), select(1, ...))
end
end
return wrapped_fn, timer
end
--- Throttles a function on the trailing edge. Automatically
--- `schedule_wrap()`s.
---
--@param fn (function) Function to throttle
--@param timeout (number) Timeout in ms
--@param last (boolean, optional) Whether to use the arguments of the last
---call to `fn` within the timeframe. Default: Use arguments of the first call.
--@returns (function, timer) Throttled function and timer. Remember to call
---`timer:close()` at the end or you will leak memory!
function M.throttle_trailing(fn, ms, last)
td_validate(fn, ms)
local timer = vim.loop.new_timer()
local running = false
local wrapped_fn
if not last then
function wrapped_fn(...)
if not running then
local argv = { ... }
local argc = select("#", ...)
timer:start(ms, 0, function()
running = false
pcall(vim.schedule_wrap(fn), unpack(argv, 1, argc))
end)
running = true
end
end
else
local argv, argc
function wrapped_fn(...)
argv = { ... }
argc = select("#", ...)
if not running then
timer:start(ms, 0, function()
running = false
pcall(vim.schedule_wrap(fn), unpack(argv, 1, argc))
end)
running = true
end
end
end
return wrapped_fn, timer
end
--- Debounces a function on the leading edge. Automatically `schedule_wrap()`s.
---
--@param fn (function) Function to debounce
--@param timeout (number) Timeout in ms
--@returns (function, timer) Debounced function and timer. Remember to call
---`timer:close()` at the end or you will leak memory!
function M.debounce_leading(fn, ms)
td_validate(fn, ms)
local timer = vim.loop.new_timer()
local running = false
local function wrapped_fn(...)
timer:start(ms, 0, function()
running = false
end)
if not running then
running = true
pcall(vim.schedule_wrap(fn), select(1, ...))
end
end
return wrapped_fn, timer
end
--- Debounces a function on the trailing edge. Automatically
--- `schedule_wrap()`s.
---
--@param fn (function) Function to debounce
--@param timeout (number) Timeout in ms
--@param first (boolean, optional) Whether to use the arguments of the first
---call to `fn` within the timeframe. Default: Use arguments of the last call.
--@returns (function, timer) Debounced function and timer. Remember to call
---`timer:close()` at the end or you will leak memory!
function M.debounce_trailing(fn, ms, first)
td_validate(fn, ms)
local timer = vim.loop.new_timer()
local wrapped_fn
if not first then
function wrapped_fn(...)
local argv = { ... }
local argc = select("#", ...)
timer:start(ms, 0, function()
pcall(vim.schedule_wrap(fn), unpack(argv, 1, argc))
end)
end
else
local argv, argc
function wrapped_fn(...)
argv = argv or { ... }
argc = argc or select("#", ...)
timer:start(ms, 0, function()
pcall(vim.schedule_wrap(fn), unpack(argv, 1, argc))
end)
end
end
return wrapped_fn, timer
end
--- Test deferment methods (`{throttle,debounce}_{leading,trailing}()`).
---
--@param bouncer (string) Bouncer function to test
--@param ms (number, optional) Timeout in ms, default 2000.
--@param firstlast (bool, optional) Whether to use the 'other' fn call
---strategy.
function M.test_defer(bouncer, ms, firstlast)
local bouncers = {
tl = M.throttle_leading,
tt = M.throttle_trailing,
dl = M.debounce_leading,
dt = M.debounce_trailing,
}
local timeout = ms or 2000
local bounced = bouncers[bouncer](function(i)
vim.cmd('echom "' .. bouncer .. ": " .. i .. '"')
end, timeout, firstlast)
for i, _ in ipairs { 1, 2, 3, 4, 5 } do
bounced(i)
vim.schedule(function()
vim.cmd("echom " .. i)
end)
vim.fn.call("wait", { 1000, "v:false" })
end
end
return M