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
|
local core = require 'core'
local lang = require 'language'
local DiagnosticSeverity = {
Error = 1,
Warning = 2,
Information = 3,
Hint = 4,
}
--[[
/**
* Represents a related message and source code location for a diagnostic. This should be
* used to point to code locations that cause or related to a diagnostics, e.g when duplicating
* a symbol in a scope.
*/
export interface DiagnosticRelatedInformation {
/**
* The location of this related diagnostic information.
*/
location: Location;
/**
* The message of this related diagnostic information.
*/
message: string;
}
]]--
local function getRange(start, finish, lines)
local start_row, start_col = lines:rowcol(start)
local finish_row, finish_col = lines:rowcol(finish)
return {
start = {
line = start_row - 1,
character = start_col - 1,
},
['end'] = {
line = finish_row - 1,
-- 这里不用-1,因为前端期待的是匹配完成后的位置
character = finish_col,
},
}
end
local function createInfo(lsp, data, lines)
local diagnostic = {
source = lang.script.DIAG_DIAGNOSTICS,
range = getRange(data.start, data.finish, lines),
severity = data.level,
message = data.message,
code = data.code,
}
if data.related then
local related = {}
for i, info in ipairs(data.related) do
local _, lines = lsp:getVM(info.uri)
local message = info.message
if not message then
local start_line = lines:rowcol(info.start)
local finish_line = lines:rowcol(info.finish)
local chars = {}
for n = start_line, finish_line do
chars[#chars+1] = lines:line(n)
end
message = table.concat(chars, '\n')
end
related[i] = {
message = message,
location = {
uri = info.uri,
range = getRange(info.start, info.finish, lines),
}
}
end
diagnostic.relatedInformation = related
end
return diagnostic
end
local function buildError(err, lines, uri)
local diagnostic = {
source = lang.script.DIAG_SYNTAX_CHECK,
message = lang.script('PARSER_'..err.type, err.info)
}
if err.version then
if type(err.version) == 'table' then
diagnostic.message = ('%s(%s)'):format(diagnostic.message, lang.script('DIAG_NEED_VERSION', table.concat(err.version, '/')))
else
diagnostic.message = ('%s(%s)'):format(diagnostic.message, lang.script('DIAG_NEED_VERSION', err.version))
end
end
if err.level == 'error' then
diagnostic.severity = DiagnosticSeverity.Error
else
diagnostic.severity = DiagnosticSeverity.Warning
end
local startrow, startcol = lines:rowcol(err.start)
local endrow, endcol = lines:rowcol(err.finish)
if err.type == 'UNKNOWN' then
local _, max = lines:range(endrow)
endcol = max
end
local range = {
start = {
line = startrow - 1,
character = startcol - 1,
},
['end'] = {
line = endrow - 1,
character = endcol,
},
}
diagnostic.range = range
local related = err.info and err.info.related
if related then
local start_line = lines:rowcol(related[1])
local finish_line = lines:rowcol(related[2])
local chars = {}
for n = start_line, finish_line do
chars[#chars+1] = lines:line(n)
end
local message = table.concat(chars, '\n')
diagnostic.relatedInformation = {
{
message = message,
location = {
uri = uri,
range = getRange(related[1], related[2], lines),
}
}
}
end
return diagnostic
end
return function (lsp, params)
local vm = params.vm
local lines = params.lines
local uri = params.uri
local errs = lsp:getAstErrors(uri)
local diagnostics = {}
if vm then
local datas = core.diagnostics(vm, lines, uri)
for _, data in ipairs(datas) do
diagnostics[#diagnostics+1] = createInfo(lsp, data, lines)
end
end
if errs then
for _, err in ipairs(errs) do
diagnostics[#diagnostics+1] = buildError(err, lines, uri)
end
end
return diagnostics
end
|