Remove VS.LSP.CompletionItem

This commit is contained in:
hrsh7th
2021-08-06 21:14:58 +09:00
parent 48cbe3022f
commit ef27b622a7
6 changed files with 46 additions and 231 deletions

View File

@@ -1,6 +1,4 @@
let s:Position = vital#cmp#import('VS.LSP.Position')
let s:TextEdit = vital#cmp#import('VS.LSP.TextEdit')
let s:CompletionItem = vital#cmp#import('VS.LSP.CompletionItem')
"
" cmp#apply_text_edits
@@ -9,24 +7,3 @@ function! cmp#apply_text_edits(bufnr, text_edits) abort
call s:TextEdit.apply(a:bufnr, a:text_edits)
endfunction
"
" cmp#confirm
"
function! cmp#confirm(args) abort
call s:CompletionItem.confirm({
\ 'suggest_position': s:Position.vim_to_lsp('%', [line('.'), a:args.suggest_offset]),
\ 'request_position': s:Position.vim_to_lsp('%', [line('.'), a:args.request_offset]),
\ 'current_position': s:Position.vim_to_lsp('%', [line('.'), col('.')]),
\ 'current_line': getline('.'),
\ 'completion_item': a:args.completion_item,
\ 'expand_snippet': s:get_expand_snippet(),
\ })
endfunction
"
" get_expand_snippet
"
function! s:get_expand_snippet() abort
return { args -> luaeval('require"cmp"._expand_snippet(_A)', args) }
endfunction

View File

@@ -1,178 +0,0 @@
" ___vital___
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
" Do not modify the code nor insert new lines before '" ___vital___'
function! s:_SID() abort
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
endfunction
execute join(['function! vital#_cmp#VS#LSP#CompletionItem#import() abort', printf("return map({'_vital_depends': '', 'confirm': '', '_vital_loaded': ''}, \"vital#_cmp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
delfunction s:_SID
" ___vital___
"
" _vital_loaded
"
function! s:_vital_loaded(V) abort
let s:Position = a:V.import('VS.LSP.Position')
let s:TextEdit = a:V.import('VS.LSP.TextEdit')
let s:Text = a:V.import('VS.LSP.Text')
endfunction
"
" _vital_depends
"
function! s:_vital_depends() abort
return ['VS.LSP.Position', 'VS.LSP.TextEdit', 'VS.LSP.Text']
endfunction
"
" confirm
"
" @param {LSP.Position} args.suggest_position
" @param {LSP.Position} args.request_position
" @param {LSP.Position} args.current_position
" @param {string} args.current_line
" @param {LSP.CompletionItem} args.completion_item
" @param {(args: { body: string; insert_text_mode: number; }) => void?} args.expand_snippet
"
" # Pre-condition
"
" - You must pass `current_position` that represents the position when `CompleteDone` was fired.
" - You must pass `current_line` that represents the line when `CompleteDone` was fired.
" - You must call this function after the commit characters has been inserted.
"
" # The positoins
"
" 0. The example case
"
" call getbufl|<C-x><C-o><C-n><C-y> -> call getbufline|
"
" 1. suggest_position
"
" call |getbufline
"
" 2. request_position
"
" call getbufl|ine
"
" 3. current_position
"
" call getbufline|
"
"
function! s:confirm(args) abort
let l:suggest_position = a:args.suggest_position
let l:request_position = a:args.request_position
let l:current_position = a:args.current_position
let l:current_line = a:args.current_line
let l:completion_item = a:args.completion_item
let l:ExpandSnippet = get(a:args, 'expand_snippet', v:null)
" 1. Prepare for alignment to VSCode behavior.
let l:expansion = s:_get_expansion({
\ 'suggest_position': l:suggest_position,
\ 'request_position': l:request_position,
\ 'current_position': l:current_position,
\ 'current_line': l:current_line,
\ 'completion_item': l:completion_item,
\ })
if !empty(l:expansion)
" Remove commit characters if expansion is needed.
if getline('.') !=# l:current_line
call setline(l:current_position.line + 1, l:current_line)
call cursor(s:Position.lsp_to_vim('%', l:current_position))
endif
" Restore state of the timing when `textDocument/completion` was sent.
call s:TextEdit.apply('%', [{
\ 'range': { 'start': l:request_position, 'end': l:current_position },
\ 'newText': ''
\ }])
endif
" 2. Apply additionalTextEdits
if type(get(l:completion_item, 'additionalTextEdits', v:null)) == type([])
call s:TextEdit.apply('%', l:completion_item.additionalTextEdits)
endif
" 3. Apply expansion
if !empty(l:expansion)
let l:current_position = s:Position.cursor() " Update current_position to after additionalTextEdits.
let l:range = {
\ 'start': extend({
\ 'character': l:current_position.character - l:expansion.overflow_before,
\ }, l:current_position, 'keep'),
\ 'end': extend({
\ 'character': l:current_position.character + l:expansion.overflow_after,
\ }, l:current_position, 'keep')
\ }
" Snippet.
if l:expansion.is_snippet && !empty(l:ExpandSnippet)
call s:TextEdit.apply('%', [{ 'range': l:range, 'newText': '' }])
call cursor(s:Position.lsp_to_vim('%', l:range.start))
call l:ExpandSnippet({ 'body': l:expansion.new_text, 'insert_text_mode': get(l:completion_item, 'insertTextMode', 2) })
" TextEdit.
else
call s:TextEdit.apply('%', [{ 'range': l:range, 'newText': l:expansion.new_text }])
" Move cursor position to end of new_text like as snippet.
let l:lines = s:Text.split_by_eol(l:expansion.new_text)
let l:cursor = copy(l:range.start)
let l:cursor.line += len(l:lines) - 1
let l:cursor.character = strchars(l:lines[-1]) + (len(l:lines) == 1 ? l:cursor.character : 0)
call cursor(s:Position.lsp_to_vim('%', l:cursor))
endif
endif
endfunction
"
" _get_expansion
"
function! s:_get_expansion(args) abort
let l:current_line = a:args.current_line
let l:suggest_position = a:args.suggest_position
let l:request_position = a:args.request_position
let l:current_position = a:args.current_position
let l:completion_item = a:args.completion_item
let l:is_snippet = get(l:completion_item, 'insertTextFormat', 1) == 2
if type(get(l:completion_item, 'textEdit', v:null)) == type({})
let l:inserted_text = strcharpart(l:current_line, l:request_position.character, l:current_position.character - l:request_position.character)
let l:overflow_before = l:request_position.character - l:completion_item.textEdit.range.start.character
let l:overflow_after = l:completion_item.textEdit.range.end.character - l:request_position.character
let l:inserted = ''
\ . strcharpart(l:current_line, l:request_position.character - l:overflow_before, l:overflow_before)
\ . strcharpart(l:current_line, l:request_position.character, strchars(l:inserted_text) + l:overflow_after)
let l:new_text = l:completion_item.textEdit.newText
if s:_trim_tabstop(l:new_text) !=# l:inserted
" The LSP spec says `textEdit range must contain the request position.`
return {
\ 'overflow_before': max([0, l:overflow_before]),
\ 'overflow_after': max([0, l:overflow_after]),
\ 'new_text': l:new_text,
\ 'is_snippet': l:is_snippet,
\ }
endif
else
let l:inserted = strcharpart(l:current_line, l:suggest_position.character, l:current_position.character - l:suggest_position.character)
let l:new_text = get(l:completion_item, 'insertText', v:null)
let l:new_text = !empty(l:new_text) ? l:new_text : l:completion_item.label
if s:_trim_tabstop(l:new_text) !=# l:inserted
return {
\ 'overflow_before': l:request_position.character - l:suggest_position.character,
\ 'overflow_after': 0,
\ 'new_text': l:new_text,
\ 'is_snippet': l:is_snippet,
\ }
endif
endif
return {}
endfunction
"
" _trim_tabstop
"
function! s:_trim_tabstop(text) abort
return substitute(a:text, '\%(\$0\|\${0}\)$', '', 'g')
endfunction

View File

@@ -1,5 +1,4 @@
cmp
5828301d6bae0858e9ea21012913544f5ef8e375
2755f0c8fbd3442bcb7f567832e4d1455b57f9a2
VS.LSP.CompletionItem
VS.LSP.Position
VS.LSP.TextEdit

View File

@@ -205,9 +205,9 @@ core.confirm = vim.schedule_wrap(function(e, option, callback)
local has_cursor_line_text_edit = (function()
local minrow = math.min(pre.cursor.row, new.cursor.row)
local maxrow = math.max(pre.cursor.row, new.cursor.row)
for _, text_edit in ipairs(text_edits) do
local srow = text_edit.range.start.line + 1
local erow = text_edit.range['end'].line + 1
for _, te in ipairs(text_edits) do
local srow = te.range.start.line + 1
local erow = te.range['end'].line + 1
if srow <= minrow and maxrow <= erow then
return true
end
@@ -235,30 +235,48 @@ core.confirm = vim.schedule_wrap(function(e, option, callback)
completion_item.textEdit.range = e:get_insert_range()
end
-- First, emulates vim's `<C-y>` behavior and then confirms LSP functionalities.
if #(misc.safe(e:get_completion_item().additionalTextEdits) or {}) > 0 then
vim.fn['cmp#apply_text_edits'](pre.bufnr, e:get_completion_item().additionalTextEdits)
end
local range = types.lsp.Range.to_vim(pre.bufnr, e:get_insert_range())
-- First, emulates vim's `<C-y>` behavior and then confirms LSP functionalities.
local range = types.lsp.Range.to_vim(pre.bufnr, completion_item.textEdit.range)
local before_text = string.sub(pre.cursor_line, range.start.col, pre.cursor.col - 1)
local after_text = string.sub(pre.cursor_line, pre.cursor.col, pre.cursor.col + (range['end'].col - e.context.cursor.col) - 1)
local before_len = vim.fn.strchars(before_text)
local after_len = vim.fn.strchars(after_text)
local keys = string.rep('<C-g>U<Right>', after_len) .. string.rep('<BS>', before_len + after_len) .. e:get_word()
local keys = '<C-g>u' .. string.rep('<C-g>U<Right>', after_len) .. string.rep('<BS>', before_len + after_len)
if not completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet then
keys = keys .. completion_item.textEdit.newText
else
keys = keys .. e:get_word()
end
keymap.feedkeys(
keys,
'n',
vim.schedule_wrap(function()
vim.fn['cmp#confirm']({
request_offset = e.context.cursor.col,
suggest_offset = e:get_offset(),
completion_item = completion_item,
})
-- execute
e:execute(function()
if callback then
callback()
end
end)
local execute = function()
e:execute(function()
if callback then
callback()
end
end)
end
if completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet then
keymap.feedkeys(
'<C-g>U' .. string.rep('<BS>', vim.fn.strchars(e:get_word())),
'n',
vim.schedule_wrap(function()
config.get().snippet.expand({
body = completion_item.textEdit.newText,
insert_text_mode = completion_item.insertTextMode,
})
execute()
end)
)
else
execute()
end
end)
)
end)

View File

@@ -190,13 +190,19 @@ end
---@return vim.CompletedItem
entry.get_vim_item = function(self, suggeset_offset)
return self.cache:ensure({ 'get_vim_item', suggeset_offset }, function()
local diff = vim.str_byteindex(self.context.cursor_line, self:get_replace_range()['end'].character)
local item = config.get().formatting.format(self, suggeset_offset)
item.word = str.remove_suffix(item.word, string.sub(self.context.cursor_line, self.context.cursor.col, diff))
item.equal = 1
item.empty = 1
item.dup = self.completion_item.dup or 1
item.user_data = { cmp = self.id }
for i = 1, #item.word - 1 do
if str.has_prefix(self.context.cursor_after_line, string.sub(item.word, i, #item.word)) then
item.word = string.sub(item.word, 1, i - 1)
break
end
end
return item
end)
end

View File

@@ -55,13 +55,6 @@ cmp.close = function()
core.reset()
end
---Internal expand snippet function.
---TODO: It should be removed when we remove `autoload/cmp.vim`.
---@param args cmp.SnippetExpansionParams
cmp._expand_snippet = function(args)
return config.get().snippet.expand(args)
end
---Handle events
autocmd.subscribe('InsertEnter', function()
core.prepare()