-
Notifications
You must be signed in to change notification settings - Fork 21
/
timer.lua
101 lines (86 loc) · 2.7 KB
/
timer.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
local core = require "core"
local Object = require "core.object"
---Timer class
---@class lsp.timer : core.object
---@field public interval integer
---@field public single_shot boolean
---@field private started boolean
---@field private last_run integer
local Timer = Object:extend()
---Constructor
---@param interval integer The interval in milliseconds
---@param single_shot boolean Indicates if timer should only run once
function Timer:new(interval, single_shot)
Timer.super.new(self)
self.single_shot = single_shot or false
self.started = false
self.cancel_thread_marker = { cancel = true }
self.last_run = 0
self:set_interval(interval or 1000)
end
---Starts a non running timer.
function Timer:start()
if self.started then return end
self.started = true
self.cancel_thread_marker = { cancel = false }
local this = self
-- Save marker so that we keep this one and not an "updated" one
local marker = self.cancel_thread_marker
core.add_thread(function()
while true do
if marker.cancel == true then return end
this:reset()
local now = system.get_time()
local remaining = (this.last_run + this.interval) - now
if remaining > 0 then
repeat
if not this.started or marker.cancel then return end
coroutine.yield(remaining)
now = system.get_time()
remaining = (this.last_run + this.interval) - now
until remaining <= 0
end
if not this.started or marker.cancel then return end
this:on_timer()
if this.single_shot then break end
end
this.started = false
end)
end
---Stops a running timer.
function Timer:stop()
self.started = false
end
---Resets the timer countdown for execution.
function Timer:reset()
self.last_run = system.get_time()
end
---Restarts the timer countdown for execution.
function Timer:restart()
self:reset()
if not self.started then
self:start()
end
end
---Check if the timer is running.
---@return boolean
function Timer:running()
return self.started
end
---Appropriately set the timer interval by converting milliseconds to seconds.
---@param interval integer The interval in milliseconds
function Timer:set_interval(interval)
local new_interval = interval / 1000
-- As this new interval might be shorter than the currently running one, and
-- because we might already be sleeping waiting for the old interval, we
-- mark the already running coroutine as cancelled, and create a new one.
if self.started and self.interval > new_interval then
self.cancel_thread_marker.cancel = true
self:stop()
self:start()
end
self.interval = new_interval
end
---To be overwritten by the instantiated timer objects
function Timer:on_timer() end
return Timer