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
|
local lclient = require 'lclient'()
local furi = require 'file-uri'
local ws = require 'workspace'
local files = require 'files'
local diag = require 'provider.diagnostic'
local util = require 'utility'
local jsonb = require 'json-beautify'
local lang = require 'language'
local define = require 'proto.define'
local protoDiag = require 'proto.diagnostic'
local config = require 'config.config'
local fs = require 'bee.filesystem'
local provider = require 'provider'
local await = require 'await'
require 'plugin'
require 'vm'
lang(LOCALE)
local numThreads = tonumber(NUM_THREADS or 1)
local threadId = tonumber(THREAD_ID or 1)
if type(CHECK_WORKER) ~= 'string' then
print(lang.script('CLI_CHECK_ERROR_TYPE', type(CHECK_WORKER)))
return
end
local rootPath = fs.absolute(fs.path(CHECK_WORKER)):string()
local rootUri = furi.encode(rootPath)
if not rootUri then
print(lang.script('CLI_CHECK_ERROR_URI', rootPath))
return
end
rootUri = rootUri:gsub("/$", "")
if CHECKLEVEL then
if not define.DiagnosticSeverity[CHECKLEVEL] then
print(lang.script('CLI_CHECK_ERROR_LEVEL', 'Error, Warning, Information, Hint'))
return
end
end
local checkLevel = define.DiagnosticSeverity[CHECKLEVEL] or define.DiagnosticSeverity.Warning
util.enableCloseFunction()
-- Hash function used to distribute work.
local function hashString(str)
local hash = 0
for i = 1, #str do
hash = (hash * 37 & 0xFFFFFFFF) + str:byte(i, i)
end
return hash
end
local lastClock = os.clock()
local results = {}
local function errorhandler(err)
print(err)
print(debug.traceback())
end
---@async
xpcall(lclient.start, errorhandler, lclient, function (client)
await.disable()
client:registerFakers()
client:initialize {
rootUri = rootUri,
}
client:register('textDocument/publishDiagnostics', function (params)
results[params.uri] = params.diagnostics
end)
if not QUIET then
io.write(lang.script('CLI_CHECK_INITING'))
end
provider.updateConfig(rootUri)
ws.awaitReady(rootUri)
local disables = util.arrayToHash(config.get(rootUri, 'Lua.diagnostics.disable'))
for name, serverity in pairs(define.DiagnosticDefaultSeverity) do
serverity = config.get(rootUri, 'Lua.diagnostics.severity')[name] or serverity
if serverity:sub(-1) == '!' then
serverity = serverity:sub(1, -2)
end
if define.DiagnosticSeverity[serverity] > checkLevel then
disables[name] = true
end
end
config.set(rootUri, 'Lua.diagnostics.disable', util.getTableKeys(disables, true))
-- Downgrade file opened status to Opened for everything to avoid reporting during compilation on files that do not belong to this thread
local diagStatus = config.get(rootUri, 'Lua.diagnostics.neededFileStatus')
for diag, status in pairs(diagStatus) do
if status == 'Any' or status == 'Any!' then
diagStatus[diag] = 'Opened!'
end
end
for diag, status in pairs(protoDiag.getDefaultStatus()) do
if status == 'Any' or status == 'Any!' then
diagStatus[diag] = 'Opened!'
end
end
config.set(rootUri, 'Lua.diagnostics.neededFileStatus', diagStatus)
local uris = files.getChildFiles(rootUri)
local max = #uris
for i, uri in ipairs(uris) do
local hash = hashString(uri) % numThreads + 1
if hash == threadId then
files.open(uri)
diag.doDiagnostic(uri, true)
-- Print regularly but always print the last entry to ensure that logs written to files don't look incomplete.
if (os.clock() - lastClock > 0.2 or i == #uris) and not QUIET then
lastClock = os.clock()
client:update()
local output = '\x0D'
.. ('>'):rep(math.ceil(i / max * 20))
.. ('='):rep(20 - math.ceil(i / max * 20))
.. ' '
.. ('0'):rep(#tostring(max) - #tostring(i))
.. tostring(i) .. '/' .. tostring(max)
io.write(output)
local filesWithErrors = 0
local errors = 0
for _, diags in pairs(results) do
filesWithErrors = filesWithErrors + 1
errors = errors + #diags
end
if errors > 0 then
local errorDetails = ' [' .. lang.script('CLI_CHECK_PROGRESS', errors, filesWithErrors) .. ']'
io.write(errorDetails)
end
io.flush()
end
end
end
if not QUIET then
io.write('\x0D')
end
end)
local count = 0
for uri, result in pairs(results) do
count = count + #result
if #result == 0 then
results[uri] = nil
end
end
local outpath = CHECK_OUT_PATH
if outpath == nil then
outpath = LOGPATH .. '/check.json'
end
-- Always write result, even if it's empty to make sure no one accidentally looks at an old output after a successful run.
util.saveFile(outpath, jsonb.beautify(results))
if not QUIET then
if count == 0 then
print(lang.script('CLI_CHECK_SUCCESS'))
else
print(lang.script('CLI_CHECK_RESULTS', count, outpath))
end
end
|