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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
local files = require 'files'
local define = require 'proto.define'
local config = require 'config'
local await = require 'await'
local vm = require "vm.vm"
local util = require 'utility'
local diagd = require 'proto.diagnostic'
local sleepRest = 0.0
---@async
local function checkSleep(uri, passed)
local speedRate = config.get(uri, 'Lua.diagnostics.workspaceRate')
if speedRate <= 0 or speedRate >= 100 then
return
end
local sleepTime = passed * (100 - speedRate) / speedRate
if sleepTime + sleepRest < 0.001 then
sleepRest = sleepRest + sleepTime
return
end
sleepRest = sleepTime + sleepRest
sleepTime = sleepRest
if sleepTime > 0.1 then
sleepTime = 0.1
end
local clock = os.clock()
await.sleep(sleepTime)
local sleeped = os.clock() - clock
sleepRest = sleepRest - sleeped
end
---@param uri uri
---@param name string
---@return string
local function getSeverity(uri, name)
local severity = config.get(uri, 'Lua.diagnostics.severity')[name]
or define.DiagnosticDefaultSeverity[name]
if severity:sub(-1) == '!' then
return severity:sub(1, -2)
end
local groupSeverity = config.get(uri, 'Lua.diagnostics.groupSeverity')
local groups = diagd.getGroups(name)
local groupLevel = 999
for _, groupName in ipairs(groups) do
local gseverity = groupSeverity[groupName]
if gseverity and gseverity ~= 'Fallback' then
groupLevel = math.min(groupLevel, define.DiagnosticSeverity[gseverity])
end
end
if groupLevel == 999 then
return severity
end
for severityName, level in pairs(define.DiagnosticSeverity) do
if level == groupLevel then
return severityName
end
end
return severity
end
---@param uri uri
---@param name string
---@return string
local function getStatus(uri, name)
local status = config.get(uri, 'Lua.diagnostics.neededFileStatus')[name]
or define.DiagnosticDefaultNeededFileStatus[name]
if status:sub(-1) == '!' then
return status:sub(1, -2)
end
local groupStatus = config.get(uri, 'Lua.diagnostics.groupFileStatus')
local groups = diagd.getGroups(name)
local groupLevel = 0
for _, groupName in ipairs(groups) do
local gstatus = groupStatus[groupName]
if gstatus and gstatus ~= 'Fallback' then
groupLevel = math.max(groupLevel, define.DiagnosticFileStatus[gstatus])
end
end
if groupLevel == 0 then
return status
end
for statusName, level in pairs(define.DiagnosticFileStatus) do
if level == groupLevel then
return statusName
end
end
return status
end
---@async
---@param uri uri
---@param name string
---@param isScopeDiag boolean
---@param response async fun(result: any)
---@return boolean
local function check(uri, name, isScopeDiag, response)
local disables = config.get(uri, 'Lua.diagnostics.disable')
if util.arrayHas(disables, name) then
return false
end
local severity = getSeverity(uri, name)
local status = getStatus(uri, name)
if status == 'None' then
return false
end
if status == 'Opened' and not files.isOpen(uri) then
return false
end
local level = define.DiagnosticSeverity[severity]
local clock = os.clock()
local mark = {}
---@async
require('core.diagnostics.' .. name)(uri, function (result)
if vm.isDiagDisabledAt(uri, result.start, name) then
return
end
if result.start < 0 then
return
end
if mark[result.start] then
return
end
mark[result.start] = true
result.level = level or result.level
result.code = name
response(result)
end, name)
local passed = os.clock() - clock
if passed >= 0.5 then
log.warn(('Diagnostics [%s] @ [%s] takes [%.3f] sec!'):format(name, uri, passed))
end
if isScopeDiag then
checkSleep(uri, passed)
end
if DIAGTIMES then
DIAGTIMES[name] = (DIAGTIMES[name] or 0) + passed
end
return true
end
local diagList
local diagCosts = {}
local diagCount = {}
local function buildDiagList()
if not diagList then
diagList = {}
for name in pairs(define.DiagnosticDefaultSeverity) do
diagList[#diagList+1] = name
end
end
table.sort(diagList, function (a, b)
local time1 = (diagCosts[a] or 0) / (diagCount[a] or 1)
local time2 = (diagCosts[b] or 0) / (diagCount[b] or 1)
return time1 < time2
end)
return diagList
end
---@async
---@param uri uri
---@param isScopeDiag boolean
---@param response async fun(result: any)
---@param checked? async fun(name: string)
return function (uri, isScopeDiag, response, checked)
local ast = files.getState(uri)
if not ast then
return nil
end
for _, name in ipairs(buildDiagList()) do
await.delay()
local clock = os.clock()
local suc = check(uri, name, isScopeDiag, response)
if suc then
local cost = os.clock() - clock
diagCosts[name] = (diagCosts[name] or 0) + cost
diagCount[name] = (diagCount[name] or 0) + 1
end
if checked then
checked(name)
end
end
end
|