fix eat of typing char after completion done (#1468)

When using typescript-language-server, in content `Math.ab|`, if you type
`<C-X><C-o>` for omni completion, it will be completed with `s`. Then, the
content will become `Math.abs|`. If you continue typing `(`, the `(` will
be removed. Also, if type `<CR>`, a new line will be added, resulting in
`Math.abs|s\nMath.ab`. This patch attempts to fix this issue.
This commit is contained in:
Colin Cheng
2023-04-27 22:21:05 +08:00
committed by GitHub
parent 80644e108b
commit 507565f281
3 changed files with 23 additions and 21 deletions

View File

@@ -311,44 +311,43 @@ function! lsp#omni#get_vim_completion_items(options) abort
\ 'icase': 1, \ 'icase': 1,
\ } \ }
let l:range = lsp#utils#text_edit#get_range(get(l:completion_item, 'textEdit', {})) let l:range = lsp#utils#text_edit#get_range(get(l:completion_item, 'textEdit', {}))
let l:complete_word = ''
if has_key(l:completion_item, 'textEdit') && type(l:completion_item['textEdit']) == s:t_dict && !empty(l:range) && has_key(l:completion_item['textEdit'], 'newText') if has_key(l:completion_item, 'textEdit') && type(l:completion_item['textEdit']) == s:t_dict && !empty(l:range) && has_key(l:completion_item['textEdit'], 'newText')
let l:text_edit_new_text = l:completion_item['textEdit']['newText'] let l:text_edit_new_text = l:completion_item['textEdit']['newText']
if has_key(l:completion_item, 'filterText') && !empty(l:completion_item['filterText']) && matchstr(l:text_edit_new_text, '^' . l:refresh_pattern) ==# '' if has_key(l:completion_item, 'filterText') && !empty(l:completion_item['filterText']) && matchstr(l:text_edit_new_text, '^' . l:refresh_pattern) ==# ''
" Use filterText as word. " Use filterText as word.
let l:vim_complete_item['word'] = l:completion_item['filterText'] let l:complete_word = l:completion_item['filterText']
else else
" Use textEdit.newText as word. " Use textEdit.newText as word.
let l:vim_complete_item['word'] = l:text_edit_new_text let l:complete_word = l:text_edit_new_text
endif endif
" Fix overlapped text if needed.
let l:item_start_character = l:range['start']['character'] let l:item_start_character = l:range['start']['character']
if l:item_start_character < l:default_start_character
" Add already typed word. The typescript-language-server returns `[Symbol]` item for the line of `Hoo.|`. So we should add `.` (`.[Symbol]`) .
let l:overlap_text = strcharpart(l:current_line, l:item_start_character, l:default_start_character - l:item_start_character)
if stridx(l:vim_complete_item['word'], l:overlap_text) != 0
let l:vim_complete_item['word'] = l:overlap_text . l:vim_complete_item['word']
endif
endif
let l:start_character = min([l:item_start_character, l:start_character]) let l:start_character = min([l:item_start_character, l:start_character])
let l:start_characters += [l:item_start_character] let l:start_characters += [l:item_start_character]
elseif has_key(l:completion_item, 'insertText') && !empty(l:completion_item['insertText']) elseif has_key(l:completion_item, 'insertText') && !empty(l:completion_item['insertText'])
let l:vim_complete_item['word'] = l:completion_item['insertText'] let l:complete_word = l:completion_item['insertText']
let l:start_characters += [l:default_start_character] let l:start_characters += [l:default_start_character]
else else
let l:vim_complete_item['word'] = l:completion_item['label'] let l:complete_word = l:completion_item['label']
let l:start_characters += [l:default_start_character] let l:start_characters += [l:default_start_character]
endif endif
if l:expandable if l:expandable
let l:vim_complete_item['word'] = lsp#utils#make_valid_word(substitute(l:vim_complete_item['word'], '\$[0-9]\+\|\${\%(\\.\|[^}]\)\+}', '', 'g')) let l:vim_complete_item['word'] = lsp#utils#make_valid_word(substitute(l:complete_word, '\$[0-9]\+\|\${\%(\\.\|[^}]\)\+}', '', 'g'))
let l:vim_complete_item['abbr'] = l:completion_item['label'] . '~' let l:vim_complete_item['abbr'] = l:completion_item['label'] . '~'
else else
let l:vim_complete_item['word'] = l:complete_word
let l:vim_complete_item['abbr'] = l:completion_item['label'] let l:vim_complete_item['abbr'] = l:completion_item['label']
endif endif
if s:is_user_data_support if s:is_user_data_support
let l:vim_complete_item['user_data'] = s:create_user_data(l:completion_item, l:server_name, l:complete_position, l:start_characters[len(l:start_characters) - 1]) let l:vim_complete_item['user_data'] = s:create_user_data(
\ l:completion_item,
\ l:server_name,
\ l:complete_position,
\ l:start_characters[-1],
\ l:complete_word)
endif endif
let l:vim_complete_items += [l:vim_complete_item] let l:vim_complete_items += [l:vim_complete_item]
@@ -382,13 +381,14 @@ endfunction
" "
" create item's user_data. " create item's user_data.
" "
function! s:create_user_data(completion_item, server_name, complete_position, start_character) abort function! s:create_user_data(completion_item, server_name, complete_position, start_character, complete_word) abort
let l:user_data_key = s:create_user_data_key(s:managed_user_data_key_base) let l:user_data_key = s:create_user_data_key(s:managed_user_data_key_base)
let s:managed_user_data_map[l:user_data_key] = { let s:managed_user_data_map[l:user_data_key] = {
\ 'complete_position': a:complete_position, \ 'complete_position': a:complete_position,
\ 'server_name': a:server_name, \ 'server_name': a:server_name,
\ 'completion_item': a:completion_item, \ 'completion_item': a:completion_item,
\ 'start_character': a:start_character, \ 'start_character': a:start_character,
\ 'complete_word': a:complete_word,
\ } \ }
let s:managed_user_data_key_base += 1 let s:managed_user_data_key_base += 1
return l:user_data_key return l:user_data_key

View File

@@ -50,12 +50,12 @@ function! s:on_complete_done() abort
let s:context['done_line'] = getline('.') let s:context['done_line'] = getline('.')
let s:context['done_line_nr'] = line('.') let s:context['done_line_nr'] = line('.')
let s:context['completed_item'] = copy(v:completed_item)
let s:context['done_position'] = lsp#utils#position#vim_to_lsp('%', getpos('.')[1 : 2]) let s:context['done_position'] = lsp#utils#position#vim_to_lsp('%', getpos('.')[1 : 2])
let s:context['complete_position'] = l:managed_user_data['complete_position'] let s:context['complete_position'] = l:managed_user_data['complete_position']
let s:context['server_name'] = l:managed_user_data['server_name'] let s:context['server_name'] = l:managed_user_data['server_name']
let s:context['completion_item'] = l:managed_user_data['completion_item'] let s:context['completion_item'] = l:managed_user_data['completion_item']
let s:context['start_character'] = l:managed_user_data['start_character'] let s:context['start_character'] = l:managed_user_data['start_character']
let s:context['complete_word'] = l:managed_user_data['complete_word']
call feedkeys(printf("\<C-r>=<SNR>%d_on_complete_done_after()\<CR>", s:SID()), 'n') call feedkeys(printf("\<C-r>=<SNR>%d_on_complete_done_after()\<CR>", s:SID()), 'n')
endfunction endfunction
@@ -73,12 +73,12 @@ function! s:on_complete_done_after() abort
let l:done_line = s:context['done_line'] let l:done_line = s:context['done_line']
let l:done_line_nr = s:context['done_line_nr'] let l:done_line_nr = s:context['done_line_nr']
let l:completed_item = s:context['completed_item']
let l:done_position = s:context['done_position'] let l:done_position = s:context['done_position']
let l:complete_position = s:context['complete_position'] let l:complete_position = s:context['complete_position']
let l:server_name = s:context['server_name'] let l:server_name = s:context['server_name']
let l:completion_item = s:context['completion_item'] let l:completion_item = s:context['completion_item']
let l:start_character = s:context['start_character'] let l:start_character = s:context['start_character']
let l:complete_word = s:context['complete_word']
" check the commit characters are <BS> or <C-w>. " check the commit characters are <BS> or <C-w>.
if line('.') ==# l:done_line_nr && strlen(getline('.')) < strlen(l:done_line) if line('.') ==# l:done_line_nr && strlen(getline('.')) < strlen(l:done_line)
@@ -95,7 +95,7 @@ function! s:on_complete_done_after() abort
let l:completion_item = s:resolve_completion_item(l:completion_item, l:server_name) let l:completion_item = s:resolve_completion_item(l:completion_item, l:server_name)
" clear completed string if need. " clear completed string if need.
let l:is_expandable = s:is_expandable(l:done_line, l:done_position, l:complete_position, l:completion_item, l:completed_item) let l:is_expandable = s:is_expandable(l:done_line, l:done_position, l:complete_position, l:completion_item, l:complete_word)
if l:is_expandable if l:is_expandable
call s:clear_auto_inserted_text(l:done_line, l:done_position, l:complete_position) call s:clear_auto_inserted_text(l:done_line, l:done_position, l:complete_position)
endif endif
@@ -162,7 +162,7 @@ endfunction
" "
" is_expandable " is_expandable
" "
function! s:is_expandable(done_line, done_position, complete_position, completion_item, completed_item) abort function! s:is_expandable(done_line, done_position, complete_position, completion_item, complete_word) abort
if get(a:completion_item, 'textEdit', v:null) isnot# v:null if get(a:completion_item, 'textEdit', v:null) isnot# v:null
let l:range = lsp#utils#text_edit#get_range(a:completion_item['textEdit']) let l:range = lsp#utils#text_edit#get_range(a:completion_item['textEdit'])
if l:range['start']['line'] != l:range['end']['line'] if l:range['start']['line'] != l:range['end']['line']
@@ -177,7 +177,7 @@ function! s:is_expandable(done_line, done_position, complete_position, completio
let l:text_edit_after = strcharpart(l:completed_line, l:range['end']['character'], strchars(l:completed_line) - l:range['end']['character']) let l:text_edit_after = strcharpart(l:completed_line, l:range['end']['character'], strchars(l:completed_line) - l:range['end']['character'])
return a:done_line !=# l:text_edit_before . s:trim_unmeaning_tabstop(a:completion_item['textEdit']['newText']) . l:text_edit_after return a:done_line !=# l:text_edit_before . s:trim_unmeaning_tabstop(a:completion_item['textEdit']['newText']) . l:text_edit_after
endif endif
return s:get_completion_text(a:completion_item) !=# s:trim_unmeaning_tabstop(a:completed_item['word']) return s:get_completion_text(a:completion_item) !=# s:trim_unmeaning_tabstop(a:complete_word)
endfunction endfunction
" "
@@ -246,7 +246,7 @@ endfunction
function! s:clear_auto_inserted_text(done_line, done_position, complete_position) abort function! s:clear_auto_inserted_text(done_line, done_position, complete_position) abort
let l:before = strcharpart(a:done_line, 0, a:complete_position['character']) let l:before = strcharpart(a:done_line, 0, a:complete_position['character'])
let l:after = strcharpart(a:done_line, a:done_position['character'], (strchars(a:done_line) - a:done_position['character'])) let l:after = strcharpart(a:done_line, a:done_position['character'], (strchars(a:done_line) - a:done_position['character']))
call setline('.', l:before . l:after) call setline(a:done_position['line'] + 1, l:before . l:after)
call cursor([a:done_position['line'] + 1, strlen(l:before) + 1]) call cursor([a:done_position['line'] + 1, strlen(l:before) + 1])
endfunction endfunction

View File

@@ -84,6 +84,7 @@ Describe lsp#omni
\ 'completion_item': item, \ 'completion_item': item,
\ 'complete_position': { 'line': 1, 'character': 1 }, \ 'complete_position': { 'line': 1, 'character': 1 },
\ 'start_character': 0, \ 'start_character': 0,
\ 'complete_word': 'yyy',
\ }) \ })
End End
@@ -187,6 +188,7 @@ Describe lsp#omni
\ 'completion_item': item, \ 'completion_item': item,
\ 'complete_position': { 'line': 1, 'character': 1 }, \ 'complete_position': { 'line': 1, 'character': 1 },
\ 'start_character': 0, \ 'start_character': 0,
\ 'complete_word': 'System.out.println(${0});',
\ }) \ })
End End