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
|
local core = require 'core'
local parser = require 'parser'
local function posToRange(lines, start, finish)
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,
character = finish_col,
},
}
end
local function fastCompletion(lsp, params, lines)
local uri = params.textDocument.uri
local text, oldText = lsp:getText(uri)
-- lua是从1开始的,因此都要+1
local position = lines:positionAsChar(params.position.line + 1, params.position.character)
local vm = lsp:getVM(uri)
if not vm then
vm = lsp:loadVM(uri)
if not vm then
return nil
end
end
local items = core.completion(vm, text, position, oldText)
if not items or #items == 0 then
vm = lsp:loadVM(uri)
if not vm then
return nil
end
items = core.completion(vm, text, position)
if not items or #items == 0 then
return nil
end
end
return items, position
end
local function finishCompletion(lsp, params, lines)
local uri = params.textDocument.uri
local text = lsp:getText(uri)
-- lua是从1开始的,因此都要+1
local position = lines:positionAsChar(params.position.line + 1, params.position.character)
local vm = lsp:loadVM(uri)
if not vm then
return nil
end
local items = core.completion(vm, text, position)
if not items or #items == 0 then
return nil
end
return items
end
local function cuterFactory(lines, text, position)
local start = position
local head = ''
for i = position, position - 100, -1 do
if not text:sub(i, i):match '[%w_]' then
start = i + 1
head = text:sub(start, position)
break
end
end
return function (insertText)
return {
newText = insertText,
range = posToRange(lines, start, position)
}
end
end
--- @param lsp LSP
--- @param params table
--- @return table
return function (lsp, params)
local uri = params.textDocument.uri
local text, oldText = lsp:getText(uri)
if not text then
return nil
end
local lines = parser:lines(text, 'utf8')
local items, position = fastCompletion(lsp, params, lines)
--local items = finishCompletion(lsp, params, lines)
if not items then
return nil
end
-- TODO 在协议阶段将 `insertText` 转化为 `textEdit` ,
-- 以避免不同客户端对 `insertText` 实现的不一致。
-- 重构后直接在 core 中使用 `textEdit` 。
local cuter = cuterFactory(lines, text, position)
for i, item in ipairs(items) do
item.sortText = ('%04d'):format(i)
item.insertTextFormat = 2
if item.textEdit then
item.textEdit.range = posToRange(lines, item.textEdit.start, item.textEdit.finish)
item.textEdit.start = nil
item.textEdit.finish = nil
else
item.textEdit = cuter(item.insertText or item.label)
end
if item.additionalTextEdits then
for _, textEdit in ipairs(item.additionalTextEdits) do
textEdit.range = posToRange(lines, textEdit.start, textEdit.finish)
textEdit.start = nil
textEdit.finish = nil
end
end
end
local response = {
isIncomplete = true,
items = items,
}
return response
end
|