Skip to content

Commit 9a1c947

Browse files
committed
性能优化, easycomplete#util#GetVimCompletionItems 用 lua 重写了 for #383
1 parent e7f8936 commit 9a1c947

File tree

3 files changed

+190
-8
lines changed

3 files changed

+190
-8
lines changed

autoload/easycomplete/action/completion.vim

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
" 参考 vim-lsp 完全重构了,无须再安装外部依赖,这里的 LSP
44
" 工具函数主要是给 easycomplete 的插件用的通用方法,内部使用方便
55
" ----------------------------------------------------------------------
6+
let s:util_toolkit = has('nvim') ? v:lua.require("easycomplete.util") : v:null
67

78
function! easycomplete#action#completion#do(opt, ctx)
89
if empty(easycomplete#installer#GetCommand(a:opt['name']))
@@ -68,7 +69,11 @@ function! s:GetLspCompletionResult(server_name, data, plugin_name, word) abort
6869
" 这里包含了 info document 和 matches
6970
let g:xx = reltime()
7071
" 192 个元素,55 ms
71-
let l:completion_result = easycomplete#util#GetVimCompletionItems(l:response, a:plugin_name, a:word)
72+
if g:env_is_nvim
73+
let l:completion_result = s:util_toolkit.get_vim_complete_items(l:response, a:plugin_name, a:word)
74+
else
75+
let l:completion_result = easycomplete#util#GetVimCompletionItems(l:response, a:plugin_name, a:word)
76+
endif
7277
" call s:console('<--', 'TODOTODOTODO', reltimestr(reltime(g:xx)), len(l:completion_result['items']))
7378
return {'matches': l:completion_result['items'], 'incomplete': l:completion_result['incomplete'] }
7479
endfunction

autoload/easycomplete/util.vim

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,18 @@ endfunction " }}}
16971697
" {{{ BadBoy
16981698
" 对 lsp response 的过滤,这个过滤本来应该 lsp 给做掉,但实际 lsp
16991699
" 偷懒都给过来了, 导致渲染很慢, v:true === isBad
1700+
function! easycomplete#util#BadBoy_Nim(item, typing_word)
1701+
return s:BadBoy.Nim(a:item, a:typing_word)
1702+
endfunction
1703+
1704+
function! easycomplete#util#BadBoy_Vim(item, typing_word)
1705+
return s:BadBoy.Vim(a:item, a:typing_word)
1706+
endfunction
1707+
1708+
function! easycomplete#util#BadBoy_Dart(item, typing_word)
1709+
return s:BadBoy.Dart(a:item, a:typing_word)
1710+
endfunction
1711+
17001712
let s:BadBoy = {}
17011713
function! s:BadBoy.Nim(item, typing_word)
17021714
if &filetype != "nim" | return v:false | endif
@@ -1825,6 +1837,10 @@ function! s:NormalizeFunctionalSnip(insertText)
18251837
return ret_str
18261838
endfunction
18271839

1840+
function! easycomplete#util#NormalizeFunctionalSnip(insertText)
1841+
return s:NormalizeFunctionalSnip(a:insertText)
1842+
endfunction
1843+
18281844
" GetVimCompletionItems {{{
18291845
function! easycomplete#util#GetVimCompletionItems(response, plugin_name, word)
18301846
let l:result = a:response['result']
@@ -1865,13 +1881,6 @@ function! easycomplete#util#GetVimCompletionItems(response, plugin_name, word)
18651881
\ 'lsp_item' : l:completion_item
18661882
\ }
18671883

1868-
" 如果 label 中包含括号 且过长
1869-
" if l:completion_item['label'] =~ "(.\\+)" && strlen(l:completion_item['label']) > 40
1870-
" if easycomplete#util#contains(l:completion_item['label'], ",") >= 2
1871-
" let l:completion_item['label'] = substitute(l:completion_item['label'], "(.\\+)", "(...)", "g")
1872-
" endif
1873-
" endif
1874-
18751884
if has_key(l:completion_item, 'textEdit') && type(l:completion_item['textEdit']) == type({})
18761885
if has_key(l:completion_item['textEdit'], 'nextText')
18771886
let l:vim_complete_item['word'] = l:completion_item['textEdit']['nextText']
@@ -1973,6 +1982,7 @@ function! easycomplete#util#GetVimCompletionItems(response, plugin_name, word)
19731982
if get(l:vim_complete_item, "word", "") != ""
19741983
let l:vim_complete_items += [l:vim_complete_item]
19751984
endif
1985+
"----------------------------------
19761986
endfor
19771987
return { 'items': l:vim_complete_items, 'incomplete': l:incomplete }
19781988
endfunction

lua/easycomplete/util.lua

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,173 @@ function util.complete_menu_filter(matching_res, word)
142142
return filtered_menu
143143
end
144144

145+
-- easycomplete#util#GetVimCompletionItems 的 lua 实现
146+
function util.get_vim_complete_items(response, plugin_name, word)
147+
local l_result = response["result"]
148+
local l_items = {}
149+
local l_incomplete = 0
150+
if type(l_result) == type({}) and l_result["items"] == nil then
151+
l_items = l_result
152+
l_incomplete = 0
153+
elseif type(l_result) == type({}) and l_result["items"] ~= nil then
154+
l_items = l_result["items"]
155+
if l_result["isIncomplete"] ~= nil then
156+
l_incomplete = l_result["isIncomplete"]
157+
else
158+
l_incomplete = 0
159+
end
160+
else
161+
l_items = {}
162+
l_incomplete = 0
163+
end
164+
165+
local l_vim_complete_items = {}
166+
local l_items_length = #l_items
167+
local typing_word = word
168+
169+
for _, l_completion_item in ipairs(l_items) do
170+
if vim.o.filetype == "nim" and vim.fn['easycomplete#util#BadBoy_Nim'](l_completion_item, typing_word) then
171+
goto continue
172+
end
173+
if vim.o.filetype == "vim" and vim.fn['easycomplete#util#BadBoy_Vim'](l_completion_item, typing_word) then
174+
goto continue
175+
end
176+
if vim.o.filetype == 'dart' and vim.fn['easycomplete#util#BadBoy_Dart'](l_completion_item, typing_word) then
177+
goto continue
178+
end
179+
180+
local l_expandable = false
181+
if l_completion_item["insertTextFormat"] == 2 then
182+
l_expandable = true
183+
end
184+
185+
local l_lsp_type_obj = {}
186+
local l_kind = 0
187+
if l_completion_item["kind"] ~= nil then
188+
l_lsp_type_obj = vim.fn["easycomplete#util#LspType"](l_completion_item["kind"])
189+
l_kind = l_completion_item["kind"]
190+
else
191+
l_lsp_type_obj = vim.fn["easycomplete#util#LspType"](0)
192+
l_kind = 0
193+
end
194+
195+
local l_menu_str = ""
196+
if vim.g.easycomplete_menu_abbr == 1 then
197+
l_menu_str = "[" .. string.upper(plugin_name) .. "]"
198+
else
199+
l_menu_str = l_lsp_type_obj["fullname"]
200+
end
201+
local l_vim_complete_item = {
202+
kind = l_lsp_type_obj["symble"],
203+
dup = 1,
204+
kind_number = l_kind,
205+
menu = l_menu_str,
206+
empty = 1,
207+
icase = 1,
208+
lsp_item = l_completion_item
209+
}
210+
if l_completion_item["textEdit"] ~= nil and type(l_completion_item['textEdit']) == type({}) then
211+
if l_completion_item['textEdit']['nextText'] ~= nil then
212+
l_vim_complete_item["word"] = l_completion_item['textEdit']['nextText']
213+
end
214+
if l_completion_item['textEdit']['newText'] ~= nil then
215+
l_vim_complete_item["word"] = l_completion_item['textEdit']['newText']
216+
end
217+
elseif l_completion_item["insertText"] ~= nil and l_completion_item['insertText'] ~= "" then
218+
l_vim_complete_item["word"] = l_completion_item['insertText']
219+
else
220+
l_vim_complete_item["word"] = l_completion_item['label']
221+
end
222+
if plugin_name == "cpp" and string.find(l_completion_item['label'], "^[•%s]") then
223+
l_vim_complete_item["word"] = string.gsub(l_completion_item['label'], "^[•%s]", "")
224+
l_completion_item["label"] = l_vim_complete_item["word"]
225+
end
226+
227+
if l_expandable == true then
228+
local l_origin_word = l_vim_complete_item['word']
229+
local l_placeholder_regex = [[\$[0-9]\+\|\${\%(\\.\|[^}]\)\+}]]
230+
l_vim_complete_item['word'] = vim.fn['easycomplete#lsp#utils#make_valid_word'](
231+
vim.fn.substitute(l_vim_complete_item['word'], l_placeholder_regex, "", "g"))
232+
local l_placeholder_position = vim.fn.match(l_origin_word, l_placeholder_regex)
233+
local l_cursor_backing_steps = string.len(string.sub(l_vim_complete_item['word'], l_placeholder_position + 1))
234+
l_vim_complete_item['abbr'] = l_completion_item['label'] .. '~'
235+
if string.len(l_origin_word) > string.len(l_vim_complete_item['word']) then
236+
local l_user_data_json = {
237+
expandable = 1,
238+
placeholder_position = l_placeholder_position,
239+
cursor_backing_steps = l_cursor_backing_steps
240+
}
241+
l_vim_complete_item['user_data'] = vim.fn.json_encode(l_user_data_json)
242+
l_vim_complete_item['user_data_json'] = l_user_data_json
243+
end
244+
local l_user_data_json_l = vim.fn.extend(vim.fn["easycomplete#util#GetUserData"](l_vim_complete_item), {
245+
expandable = 1
246+
})
247+
l_vim_complete_item['user_data'] = vim.fn.json_encode(l_user_data_json_l)
248+
l_vim_complete_item['user_data_json'] = l_user_data_json_l
249+
elseif string.find(l_completion_item['label'], ".+%(.*%)") then
250+
l_vim_complete_item['abbr'] = l_completion_item['label']
251+
if vim.fn['easycomplete#SnipExpandSupport']() then
252+
l_vim_complete_item['word'] = l_completion_item['label']
253+
else
254+
-- 如果不支持snipexpand,则只做简易展开
255+
l_vim_complete_item['word'] = string.gsub(l_completion_item['label'], "%(.*%)","") .. "()"
256+
end
257+
l_vim_complete_item['user_data_json'] = {
258+
expandable = 1,
259+
placeholder_position = string.len(l_vim_complete_item['word']) - 1,
260+
cursor_backing_steps = 1
261+
}
262+
if vim.fn['easycomplete#SnipExpandSupport']() then
263+
if string.find(l_completion_item["insertText"], "%${%d") then
264+
-- 原本就是 snippet 形式
265+
-- Do nothing
266+
elseif string.find(l_completion_item["insertText"], ".+%(.*%)$") then
267+
l_completion_item["insertText"] = vim.fn["easycomplete#util#NormalizeFunctionalSnip"](l_completion_item["insertText"])
268+
elseif string.find(l_vim_complete_item["word"], ".+%(.*%)$") then
269+
l_completion_item["insertText"] = vim.fn["easycomplete#util#NormalizeFunctionalSnip"](l_vim_complete_item["word"])
270+
else
271+
-- 不是函数形式,do nogthing
272+
end
273+
else
274+
l_vim_complete_item['user_data_json']["custom_expand"] = 1
275+
end
276+
l_vim_complete_item["user_data"] = vim.fn.json_encode(l_vim_complete_item['user_data_json'])
277+
else
278+
l_vim_complete_item['abbr'] = l_completion_item['label']
279+
end
280+
local l_t_info = {}
281+
if l_completion_item["documentation"] ~= nil then
282+
l_t_info = vim.fn['easycomplete#util#NormalizeLspInfo'](l_completion_item["documentation"])
283+
else
284+
l_t_info = {}
285+
end
286+
if l_completion_item["detail"] == nil or l_completion_item["detail"] == "" then
287+
l_vim_complete_item['info'] = l_t_info
288+
else
289+
l_vim_complete_item['info'] = {l_completion_item["detail"]}
290+
for _, v in ipairs(l_t_info) do table.insert(l_vim_complete_item['info'], v) end
291+
end
292+
293+
local sha256_str_o = vim.fn['easycomplete#util#Sha256'](l_vim_complete_item['word'] .. tostring(l_vim_complete_item['info']))
294+
local sha256_str = string.sub(sha256_str_o, 1, 16)
295+
local user_data_json = vim.fn.extend(vim.fn['easycomplete#util#GetUserData'](l_vim_complete_item), {
296+
plugin_name = plugin_name,
297+
sha256 = sha256_str,
298+
lsp_item = l_completion_item
299+
})
300+
l_vim_complete_item['user_data'] = vim.fn.json_encode(user_data_json)
301+
l_vim_complete_item["user_data_json"] = user_data_json
302+
303+
if l_vim_complete_item["word"] ~= "" then
304+
table.insert(l_vim_complete_items, l_vim_complete_item)
305+
end
306+
307+
::continue::
308+
end -- endfor
309+
return { items = l_vim_complete_items, incomplete = l_incomplete }
310+
end -- endfunction
311+
145312
-- TODO 需要再测试一下这个函数
146313
function util.get(a, ...)
147314
local args = {...}

0 commit comments

Comments
 (0)