mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-24 05:40:05 +08:00
69 lines
2.3 KiB
Lua
69 lines
2.3 KiB
Lua
|
---This timer matches the semantics of setInterval and clearInterval of
|
||
|
---Javascript. It provides a more reliable alternative to vim.loop.timer_start
|
||
|
---with a callback wrapped into a vim.schedule call by addressing two problems:
|
||
|
---1. Scheduled callbacks are invoked less frequently than a libuv timer with a
|
||
|
--- small interval (1-5ms). This causes those callbacks to fill up the queue
|
||
|
--- in the event loop, and so the callback function may get invoked multiple
|
||
|
--- times on one event loop tick. In contrast, Javascript's setInterval
|
||
|
--- guarantees that the callback is not invoked more frequently than the
|
||
|
--- interval.
|
||
|
---2. When a libuv timer is stopped with vim.loop.timer_stop, it doesn't affect
|
||
|
--- the callbacks that have already been scheduled. So timer_stop will not
|
||
|
--- immediately stop the timer, the actual callback function will run one
|
||
|
--- more time until it is finally stopped. This implementation ensures that
|
||
|
--- timer_stop prevents any subsequent invocations of the callback.
|
||
|
---
|
||
|
---@class cmp_buffer.Timer
|
||
|
---@field public handle any
|
||
|
---@field private callback_wrapper_instance fun()|nil
|
||
|
local timer = {}
|
||
|
|
||
|
function timer.new()
|
||
|
local self = setmetatable({}, { __index = timer })
|
||
|
self.handle = vim.loop.new_timer()
|
||
|
self.callback_wrapper_instance = nil
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
---@param timeout_ms number
|
||
|
---@param repeat_ms number
|
||
|
---@param callback fun()
|
||
|
function timer:start(timeout_ms, repeat_ms, callback)
|
||
|
-- This is the flag that fixes problem 1.
|
||
|
local scheduled = false
|
||
|
-- Creating a function on every call to timer_start ensures that we can always
|
||
|
-- detect when a different callback is set by calling timer_start and prevent
|
||
|
-- the old one from being invoked.
|
||
|
local function callback_wrapper()
|
||
|
if scheduled then
|
||
|
return
|
||
|
end
|
||
|
scheduled = true
|
||
|
vim.schedule(function()
|
||
|
scheduled = false
|
||
|
-- Either a different callback was set, or the timer has been stopped.
|
||
|
if self.callback_wrapper_instance ~= callback_wrapper then
|
||
|
return
|
||
|
end
|
||
|
callback()
|
||
|
end)
|
||
|
end
|
||
|
self.handle:start(timeout_ms, repeat_ms, callback_wrapper)
|
||
|
self.callback_wrapper_instance = callback_wrapper
|
||
|
end
|
||
|
|
||
|
function timer:stop()
|
||
|
self.handle:stop()
|
||
|
self.callback_wrapper_instance = nil
|
||
|
end
|
||
|
|
||
|
function timer:is_active()
|
||
|
return self.handle:is_active()
|
||
|
end
|
||
|
|
||
|
function timer:close()
|
||
|
self.handle:close()
|
||
|
end
|
||
|
|
||
|
return timer
|