Skip to content

Commit 6038748

Browse files
Improve completion perf (#1038)
* improve completion perf * improve completion popup perf * fix tests * remove old s:get_vim_completion_item
1 parent 3bca7e8 commit 6038748

File tree

4 files changed

+58
-137
lines changed

4 files changed

+58
-137
lines changed

autoload/lsp/omni.vim

Lines changed: 38 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
" vint: -ProhibitUnusedVariable
22

33
" constants {{{
4+
let s:t_dict = type({})
45

56
let s:default_completion_item_kinds = {
67
\ '1': 'text',
@@ -232,14 +233,14 @@ function! s:send_completion_request(info) abort
232233
let l:server_name = a:info['server_names'][0]
233234
" TODO: support multiple servers
234235
call lsp#send_request(l:server_name, {
235-
\ 'method': 'textDocument/completion',
236-
\ 'params': {
237-
\ 'textDocument': lsp#get_text_document_identifier(),
238-
\ 'position': lsp#get_position(),
239-
\ 'context': { 'triggerKind': 1 },
240-
\ },
241-
\ 'on_notification': function('s:handle_omnicompletion', [l:server_name, s:completion['counter'], a:info]),
242-
\ })
236+
\ 'method': 'textDocument/completion',
237+
\ 'params': {
238+
\ 'textDocument': lsp#get_text_document_identifier(),
239+
\ 'position': lsp#get_position(),
240+
\ 'context': { 'triggerKind': 1 },
241+
\ },
242+
\ 'on_notification': function('s:handle_omnicompletion', [l:server_name, s:completion['counter'], a:info]),
243+
\ })
243244
endfunction
244245

245246
function! s:get_completion_result(server_name, data) abort
@@ -256,82 +257,6 @@ function! s:get_completion_result(server_name, data) abort
256257
return {'matches': l:completion_result['items'], 'incomplete': l:completion_result['incomplete'] }
257258
endfunction
258259

259-
function! s:get_vim_completion_item(item, options) abort
260-
let l:server_name = a:options['server']['name']
261-
let l:complete_position = a:options['position']
262-
let l:kind_text_mappings = a:options['kind_text_mappings']
263-
264-
let l:word = ''
265-
let l:expandable = v:false
266-
if get(a:item, 'insertTextFormat', -1) == 2 && !empty(get(a:item, 'insertText', ''))
267-
" if candidate is snippet, use insertText. But it may include
268-
" placeholder.
269-
let l:word = lsp#utils#make_valid_word(a:item['insertText'])
270-
let l:expandable = l:word !=# a:item['insertText']
271-
elseif !empty(get(a:item, 'insertText', ''))
272-
" if plain-text insertText, use it.
273-
let l:word = a:item['insertText']
274-
elseif has_key(a:item, 'textEdit') && type(a:item['textEdit']) ==# v:t_dict
275-
let l:word = lsp#utils#make_valid_word(a:item['label'])
276-
let l:expandable = l:word !=# get(a:item['textEdit'], 'newText', '')
277-
endif
278-
if !empty(l:word)
279-
let l:word = split(l:word, '\n')[0]
280-
endif
281-
if empty(l:word)
282-
let l:word = a:item['label']
283-
endif
284-
let l:abbr = a:item['label']
285-
286-
if has_key(a:item, 'insertTextFormat') && a:item['insertTextFormat'] == 2
287-
let l:word = substitute(l:word, '\$[0-9]\+\|\${\%(\\.\|[^}]\)\+}', '', 'g')
288-
endif
289-
290-
let l:word = lsp#utils#_trim(l:word)
291-
let l:kind = has_key(a:item, 'kind') ? get(l:kind_text_mappings, a:item['kind'], '') : ''
292-
293-
let l:completion = {
294-
\ 'word': l:word,
295-
\ 'abbr': l:abbr . (l:expandable ? '~' : ''),
296-
\ 'menu': '',
297-
\ 'info': '',
298-
\ 'icase': 1,
299-
\ 'dup': 1,
300-
\ 'empty': 1,
301-
\ 'kind': l:kind,
302-
\ }
303-
304-
" check support user_data.
305-
" if not support but g:lsp_text_edit_enabled enabled,
306-
" then print information to user and add information to log file.
307-
if !s:is_user_data_support && g:lsp_text_edit_enabled
308-
let l:no_support_error_message = 'textEdit support on omni complete requires Vim 8.0 patch 1493 or later(please check g:lsp_text_edit_enabled)'
309-
call lsp#utils#error(l:no_support_error_message)
310-
call lsp#log(l:no_support_error_message)
311-
endif
312-
313-
" Add user_data.
314-
if s:is_user_data_support
315-
let l:completion['user_data'] = s:create_user_data(a:item, l:server_name, l:complete_position)
316-
endif
317-
318-
if has_key(a:item, 'detail') && !empty(a:item['detail'])
319-
let l:completion['menu'] = substitute(a:item['detail'], '[ \t\n\r]\+', ' ', 'g')
320-
endif
321-
322-
if has_key(a:item, 'documentation')
323-
if type(a:item['documentation']) == type('') " field is string
324-
let l:completion['info'] .= a:item['documentation']
325-
elseif type(a:item['documentation']) == type({}) &&
326-
\ has_key(a:item['documentation'], 'value')
327-
" field is MarkupContent (hopefully 'plaintext')
328-
let l:completion['info'] .= substitute(a:item['documentation']['value'], '\r', '', 'g')
329-
endif
330-
endif
331-
332-
return l:completion
333-
endfunction
334-
335260
" options = {
336261
" server: {}, " needs to be server_info and not server_name
337262
" position: lsp#get_position(),
@@ -340,6 +265,8 @@ endfunction
340265
" }
341266
function! lsp#omni#get_vim_completion_items(options) abort
342267
let l:server = a:options['server']
268+
let l:server_name = l:server['name']
269+
let l:kind_text_mappings = s:get_kind_text_mappings(l:server)
343270
let l:complete_position = a:options['position']
344271

345272
let l:result = a:options['response']['result']
@@ -355,14 +282,33 @@ function! lsp#omni#get_vim_completion_items(options) abort
355282
endif
356283

357284
let l:vim_complete_items = []
358-
let l:server_name = l:server['name']
359-
let l:item_options = {
360-
\ 'server': l:server,
361-
\ 'position': l:complete_position,
362-
\ 'kind_text_mappings': s:get_kind_text_mappings(l:server),
363-
\ }
364-
for l:item in l:items
365-
call add(l:vim_complete_items, s:get_vim_completion_item(l:item, l:item_options))
285+
for l:completion_item in l:items
286+
let l:expandable = get(l:completion_item, 'insertTextFormat', 1) == 2
287+
let l:vim_complete_item = {
288+
\ 'kind': get(l:kind_text_mappings, get(l:completion_item, 'kind', '') , ''),
289+
\ 'dup': 1,
290+
\ 'empty': 1,
291+
\ 'icase': 1,
292+
\ }
293+
if has_key(l:completion_item, 'textEdit') && type(l:completion_item['textEdit']) == type(s:t_dict) && has_key(l:completion_item['textEdit'], 'nextText')
294+
let l:vim_complete_item['word'] = l:completion_item['textEdit']['nextText']
295+
elseif has_key(l:completion_item, 'insertText') && !empty(l:completion_item['insertText'])
296+
let l:vim_complete_item['word'] = l:completion_item['insertText']
297+
else
298+
let l:vim_complete_item['word'] = l:completion_item['label']
299+
endif
300+
301+
if l:expandable
302+
let l:vim_complete_item['abbr'] = l:completion_item['label'] . '~'
303+
else
304+
let l:vim_complete_item['abbr'] = l:completion_item['label']
305+
endif
306+
307+
if s:is_user_data_support
308+
let l:vim_complete_item['user_data'] = s:create_user_data(l:completion_item, l:server_name, l:complete_position)
309+
endif
310+
311+
let l:vim_complete_items += [l:vim_complete_item]
366312
endfor
367313

368314
return { 'items': l:vim_complete_items, 'incomplete': l:incomplete }
@@ -428,5 +374,4 @@ endfunction
428374
function! s:create_user_data_key(base) abort
429375
return '{"vim-lsp/key":"' . a:base . '"}'
430376
endfunction
431-
432377
" }}}

autoload/lsp/ui/vim/documentation.vim

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,29 @@ endfunction
1818
function! s:show_documentation(event) abort
1919
call s:close_popup()
2020

21-
if !has_key(a:event['completed_item'], 'info') || empty(a:event['completed_item']['info'])
21+
let l:managed_data = lsp#omni#get_managed_user_data_from_completed_item(a:event['completed_item'])
22+
if empty(l:managed_data)
2223
return
2324
endif
2425

26+
let l:completion_item = l:managed_data['completion_item']
27+
if !has_key(l:completion_item, 'documentation')
28+
return
29+
endif
30+
31+
if type(l:completion_item['documentation']) == type('')
32+
let l:documentation = l:completion_item['documentation']
33+
elseif type(l:completion_item['documentation']) == type({}) && has_key(l:completion_item['documentation'], 'value')
34+
" field is MarkupContent (hopefully plaintext)
35+
let l:documentation = substitute(l:completion_item['documentation']['value'], '\r', '', 'g')
36+
endif
2537

2638
" TODO: Support markdown
27-
let l:data = split(a:event['completed_item']['info'], '\n')
39+
let l:data = split(l:documentation, '\n')
2840
let l:lines = []
2941
let l:syntax_lines = []
3042
let l:ft = lsp#ui#vim#output#append(l:data, l:lines, l:syntax_lines)
3143

32-
3344
" Neovim
3445
if s:use_nvim_float
3546
let l:event = a:event

autoload/lsp/utils.vim

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
let s:has_lua = has('nvim-0.4.0') || (has('lua') && has('patch-8.2.0775'))
2+
function! lsp#utils#has_lua() abort
3+
return s:has_lua
4+
endfunction
5+
16
let s:has_virtual_text = exists('*nvim_buf_set_virtual_text') && exists('*nvim_create_namespace')
27
function! lsp#utils#_has_virtual_text() abort
38
return s:has_virtual_text

test/lsp/omni.vimspec

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@ Describe lsp#omni
2525
\ 'items': [{
2626
\ 'word': 'my-label',
2727
\ 'abbr': 'my-label',
28-
\ 'info': 'my documentation.',
2928
\ 'icase': 1,
3029
\ 'dup': 1,
3130
\ 'empty': 1,
3231
\ 'kind': 'function',
33-
\ 'menu': 'my-detail',
3432
\ 'user_data': '{"vim-lsp/key":"0"}',
3533
\ }],
3634
\ 'incomplete': 0,
@@ -67,13 +65,11 @@ Describe lsp#omni
6765
let want = {
6866
\ 'items': [{
6967
\ 'word': 'my-label',
70-
\ 'abbr': 'my-label~',
71-
\ 'info': 'my documentation.',
68+
\ 'abbr': 'my-label',
7269
\ 'icase': 1,
7370
\ 'dup': 1,
7471
\ 'empty': 1,
7572
\ 'kind': 'function',
76-
\ 'menu': 'my-detail',
7773
\ 'user_data': '{"vim-lsp/key":"0"}',
7874
\ }],
7975
\ 'incomplete': 0,
@@ -88,38 +84,6 @@ Describe lsp#omni
8884
\ })
8985
End
9086

91-
It should return item with newlines in 'menu' replaced
92-
let item = {
93-
\ 'label': 'my-label',
94-
\ 'documentation': 'my documentation.',
95-
\ 'detail': "my-detail\nmore-detail",
96-
\ 'kind': '3'
97-
\}
98-
99-
let options = {
100-
\ 'server': { 'name': 'dummy-server' },
101-
\ 'position': lsp#get_position(),
102-
\ 'response': { 'result': [item] },
103-
\}
104-
105-
let want = {
106-
\ 'items': [{
107-
\ 'word': 'my-label',
108-
\ 'abbr': 'my-label',
109-
\ 'info': 'my documentation.',
110-
\ 'icase': 1,
111-
\ 'dup': 1,
112-
\ 'empty': 1,
113-
\ 'kind': 'function',
114-
\ 'menu': 'my-detail more-detail',
115-
\ 'user_data': '{"vim-lsp/key":"0"}',
116-
\ }],
117-
\ 'incomplete': 0,
118-
\}
119-
120-
Assert Equals(lsp#omni#get_vim_completion_items(options), want)
121-
End
122-
12387
It should not raise errors
12488
let item = {
12589
\ 'label': 'my-label',
@@ -136,12 +100,10 @@ Describe lsp#omni
136100
\ 'items': [{
137101
\ 'word': 'my-label',
138102
\ 'abbr': 'my-label',
139-
\ 'info': '',
140103
\ 'icase': 1,
141104
\ 'dup': 1,
142105
\ 'empty': 1,
143106
\ 'kind': '',
144-
\ 'menu': '',
145107
\ 'user_data': '{"vim-lsp/key":"0"}',
146108
\ }],
147109
\ 'incomplete': 0,
@@ -166,12 +128,10 @@ Describe lsp#omni
166128
\ 'items': [{
167129
\ 'word': 'my-label',
168130
\ 'abbr': 'my-label',
169-
\ 'info': '',
170131
\ 'icase': 1,
171132
\ 'dup': 1,
172133
\ 'empty': 1,
173134
\ 'kind': '',
174-
\ 'menu': '',
175135
\ 'user_data': '{"vim-lsp/key":"1"}',
176136
\ }],
177137
\ 'incomplete': 0,

0 commit comments

Comments
 (0)