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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
local proto = require 'proto.proto'
local util = require 'utility'
local timer = require "timer"
local nextToken = util.counter()
local m = {}
m.map = {}
---@class progress
local mt = {}
mt.__index = mt
mt._token = nil
mt._title = nil
mt._message = nil
mt._removed = false
mt._clock = 0.0
mt._delay = 0.0
mt._percentage = 0.0
mt._showed = false
mt._dirty = true
mt._updated = 0.0
mt._onCancel = nil
---移除进度条
function mt:remove()
if self._removed then
return
end
self._removed = true
local token = self._token
m.map[token] = nil
if self._showed then
self._showed = false
proto.notify('$/progress', {
token = token,
value = {
kind = 'end',
}
})
log.info('Remove progress:', token, self._title)
end
end
---设置描述
---@param message string # 描述
function mt:setMessage(message)
if self._message == message then
return
end
self._message = message
self._dirty = true
self:_update()
end
---设置百分比
---@param per number # 百分比(1-100)
function mt:setPercentage(per)
if self._percentage == per then
return
end
self._percentage = math.floor(per)
self._dirty = true
self:_update()
end
---取消事件
function mt:onCancel(callback)
self._onCancel = callback
self:_update()
end
function mt:_update()
if self._removed then
return
end
if not self._dirty then
return
end
if not self._showed
and self._clock + self._delay <= os.clock() then
self._showed = true
self._updated = os.clock()
proto.request('window/workDoneProgress/create', {
token = self._token,
})
proto.notify('$/progress', {
token = self._token,
value = {
kind = 'begin',
title = self._title,
cancellable = self._onCancel ~= nil,
message = self._message,
percentage = self._percentage,
}
})
log.info('Create progress:', self._token, self._title)
self._dirty = false
return
end
if not self._showed then
return
end
if os.clock() - self._updated < 0.05 then
return
end
self._dirty = false
self._updated = os.clock()
proto.notify('$/progress', {
token = self._token,
value = {
kind = 'report',
message = self._message,
percentage = self._percentage,
}
})
log.info('Report progress:', self._token, self._title, self._message, self._percentage)
end
function mt:__close()
log.info('Close progress:', self._token, self._message)
self:remove()
end
function m.update()
---@param prog progress
for _, prog in pairs(m.map) do
if prog._removed then
goto CONTINUE
end
prog:_update()
::CONTINUE::
end
end
---创建一个进度条
---@param title string # 标题
---@param delay number # 至少经过这么久之后才会显示出来
function m.create(title, delay)
local prog = setmetatable({
_token = nextToken(),
_title = title,
_clock = os.clock(),
_delay = delay,
}, mt)
m.map[prog._token] = prog
return prog
end
---取消一个进度条
function m.cancel(token)
local prog = m.map[token]
if not prog then
return
end
xpcall(prog._onCancel, log.error, prog)
prog:remove()
end
timer.loop(0.1, m.update)
return m
|