LSP 3.17 (#1306)
* 3.17 * PositionEncodingKind * Implement PositionEncodingKind * Remove luarc.json
This commit is contained in:
@@ -6,7 +6,16 @@ let s:sources = {}
|
|||||||
"
|
"
|
||||||
function! cmp#register_source(name, source) abort
|
function! cmp#register_source(name, source) abort
|
||||||
let l:methods = []
|
let l:methods = []
|
||||||
for l:method in ['is_available', 'get_debug_name', 'get_trigger_characters', 'get_keyword_pattern', 'complete', 'execute', 'resolve']
|
for l:method in [
|
||||||
|
\ 'is_available',
|
||||||
|
\ 'get_debug_name',
|
||||||
|
\ 'get_position_encoding_kind',
|
||||||
|
\ 'get_trigger_characters',
|
||||||
|
\ 'get_keyword_pattern',
|
||||||
|
\ 'complete',
|
||||||
|
\ 'execute',
|
||||||
|
\ 'resolve'
|
||||||
|
\ ]
|
||||||
if has_key(a:source, l:method) && type(a:source[l:method]) == v:t_func
|
if has_key(a:source, l:method) && type(a:source[l:method]) == v:t_func
|
||||||
call add(l:methods, l:method)
|
call add(l:methods, l:method)
|
||||||
endif
|
endif
|
||||||
@@ -39,6 +48,8 @@ function! cmp#_method(bridge_id, method, args) abort
|
|||||||
return l:source[a:method]()
|
return l:source[a:method]()
|
||||||
elseif a:method ==# 'get_debug_name'
|
elseif a:method ==# 'get_debug_name'
|
||||||
return l:source[a:method]()
|
return l:source[a:method]()
|
||||||
|
elseif a:method ==# 'get_position_encoding_kind'
|
||||||
|
return l:source[a:method](a:args[0])
|
||||||
elseif a:method ==# 'get_keyword_pattern'
|
elseif a:method ==# 'get_keyword_pattern'
|
||||||
return l:source[a:method](a:args[0])
|
return l:source[a:method](a:args[0])
|
||||||
elseif a:method ==# 'get_trigger_characters'
|
elseif a:method ==# 'get_trigger_characters'
|
||||||
|
|||||||
@@ -735,6 +735,13 @@ Here is an example on how to create a custom source:
|
|||||||
return 'debug name'
|
return 'debug name'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Return LSP's PositionEncodingKind.
|
||||||
|
---@NOTE: If this method is ommited, the default value will be `utf-16`.
|
||||||
|
---@return lsp.PositionEncodingKind
|
||||||
|
function source:get_position_encoding_kind()
|
||||||
|
return 'utf-16'
|
||||||
|
end
|
||||||
|
|
||||||
---Return the keyword pattern for triggering completion (optional).
|
---Return the keyword pattern for triggering completion (optional).
|
||||||
---If this is ommited, nvim-cmp will use a default keyword pattern. See |cmp-config.completion.keyword_pattern|.
|
---If this is ommited, nvim-cmp will use a default keyword pattern. See |cmp-config.completion.keyword_pattern|.
|
||||||
---@return string
|
---@return string
|
||||||
|
|||||||
@@ -344,7 +344,10 @@ end, config.get().performance.throttle)
|
|||||||
---@param callback function
|
---@param callback function
|
||||||
core.confirm = function(self, e, option, callback)
|
core.confirm = function(self, e, option, callback)
|
||||||
if not (e and not e.confirmed) then
|
if not (e and not e.confirmed) then
|
||||||
return callback()
|
if callback then
|
||||||
|
callback()
|
||||||
|
end
|
||||||
|
return
|
||||||
end
|
end
|
||||||
e.confirmed = true
|
e.confirmed = true
|
||||||
|
|
||||||
@@ -357,9 +360,10 @@ core.confirm = function(self, e, option, callback)
|
|||||||
|
|
||||||
feedkeys.call(keymap.indentkeys(), 'n')
|
feedkeys.call(keymap.indentkeys(), 'n')
|
||||||
feedkeys.call('', 'n', function()
|
feedkeys.call('', 'n', function()
|
||||||
|
-- Emulate `<C-y>` behavior to save `.` register.
|
||||||
local ctx = context.new()
|
local ctx = context.new()
|
||||||
local keys = {}
|
local keys = {}
|
||||||
table.insert(keys, keymap.backspace(ctx.cursor.character - misc.to_utfindex(ctx.cursor_line, e:get_offset())))
|
table.insert(keys, keymap.backspace(ctx.cursor_before_line:sub(e:get_offset())))
|
||||||
table.insert(keys, e:get_word())
|
table.insert(keys, e:get_word())
|
||||||
table.insert(keys, keymap.undobreak())
|
table.insert(keys, keymap.undobreak())
|
||||||
feedkeys.call(table.concat(keys, ''), 'in')
|
feedkeys.call(table.concat(keys, ''), 'in')
|
||||||
@@ -368,7 +372,7 @@ core.confirm = function(self, e, option, callback)
|
|||||||
local ctx = context.new()
|
local ctx = context.new()
|
||||||
if api.is_cmdline_mode() then
|
if api.is_cmdline_mode() then
|
||||||
local keys = {}
|
local keys = {}
|
||||||
table.insert(keys, keymap.backspace(ctx.cursor.character - misc.to_utfindex(ctx.cursor_line, e:get_offset())))
|
table.insert(keys, keymap.backspace(ctx.cursor_before_line:sub(e:get_offset())))
|
||||||
table.insert(keys, string.sub(e.context.cursor_before_line, e:get_offset()))
|
table.insert(keys, string.sub(e.context.cursor_before_line, e:get_offset()))
|
||||||
feedkeys.call(table.concat(keys, ''), 'in')
|
feedkeys.call(table.concat(keys, ''), 'in')
|
||||||
else
|
else
|
||||||
@@ -405,11 +409,15 @@ core.confirm = function(self, e, option, callback)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
vim.cmd([[silent! undojoin]])
|
vim.cmd([[silent! undojoin]])
|
||||||
vim.lsp.util.apply_text_edits(text_edits, ctx.bufnr, 'utf-16')
|
vim.lsp.util.apply_text_edits(text_edits, ctx.bufnr, e.source:get_position_encoding_kind())
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
vim.cmd([[silent! undojoin]])
|
vim.cmd([[silent! undojoin]])
|
||||||
vim.lsp.util.apply_text_edits(e:get_completion_item().additionalTextEdits, ctx.bufnr, 'utf-16')
|
vim.lsp.util.apply_text_edits(
|
||||||
|
e:get_completion_item().additionalTextEdits,
|
||||||
|
ctx.bufnr,
|
||||||
|
e.source:get_position_encoding_kind()
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
feedkeys.call('', 'n', function()
|
feedkeys.call('', 'n', function()
|
||||||
@@ -426,30 +434,33 @@ core.confirm = function(self, e, option, callback)
|
|||||||
completion_item.textEdit.range = e:get_insert_range()
|
completion_item.textEdit.range = e:get_insert_range()
|
||||||
end
|
end
|
||||||
|
|
||||||
local diff_before = math.max(0, e.context.cursor.character - completion_item.textEdit.range.start.character)
|
local diff_before = math.max(0, e.context.cursor.col - (completion_item.textEdit.range.start.character + 1))
|
||||||
local diff_after = math.max(0, completion_item.textEdit.range['end'].character - e.context.cursor.character)
|
local diff_after = math.max(0, (completion_item.textEdit.range['end'].character + 1) - e.context.cursor.col)
|
||||||
local new_text = completion_item.textEdit.newText
|
local new_text = completion_item.textEdit.newText
|
||||||
|
|
||||||
if api.is_insert_mode() then
|
if api.is_insert_mode() then
|
||||||
local is_snippet = completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet
|
|
||||||
completion_item.textEdit.range.start.line = ctx.cursor.line
|
completion_item.textEdit.range.start.line = ctx.cursor.line
|
||||||
completion_item.textEdit.range.start.character = ctx.cursor.character - diff_before
|
completion_item.textEdit.range.start.character = (e.context.cursor.col - 1) - diff_before
|
||||||
completion_item.textEdit.range['end'].line = ctx.cursor.line
|
completion_item.textEdit.range['end'].line = ctx.cursor.line
|
||||||
completion_item.textEdit.range['end'].character = ctx.cursor.character + diff_after
|
completion_item.textEdit.range['end'].character = (ctx.cursor.col - 1) + diff_after
|
||||||
|
|
||||||
|
local is_snippet = completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet
|
||||||
if is_snippet then
|
if is_snippet then
|
||||||
completion_item.textEdit.newText = ''
|
completion_item.textEdit.newText = ''
|
||||||
end
|
end
|
||||||
vim.lsp.util.apply_text_edits({ completion_item.textEdit }, ctx.bufnr, 'utf-16')
|
vim.lsp.util.apply_text_edits({ completion_item.textEdit }, ctx.bufnr, 'utf-8')
|
||||||
|
|
||||||
local texts = vim.split(completion_item.textEdit.newText, '\n')
|
local texts = vim.split(completion_item.textEdit.newText, '\n')
|
||||||
local position = completion_item.textEdit.range.start
|
vim.api.nvim_win_set_cursor(0, {
|
||||||
position.line = position.line + (#texts - 1)
|
completion_item.textEdit.range.start.line + #texts,
|
||||||
if #texts == 1 then
|
(
|
||||||
position.character = position.character + misc.to_utfindex(texts[1])
|
#texts == 1 and (
|
||||||
else
|
completion_item.textEdit.range.start.character + #texts[1]
|
||||||
position.character = misc.to_utfindex(texts[#texts])
|
) or (
|
||||||
end
|
#texts[#texts]
|
||||||
local pos = types.lsp.Position.to_vim(0, position)
|
)
|
||||||
vim.api.nvim_win_set_cursor(0, { pos.row, pos.col - 1 })
|
)
|
||||||
|
})
|
||||||
if is_snippet then
|
if is_snippet then
|
||||||
config.get().snippet.expand({
|
config.get().snippet.expand({
|
||||||
body = new_text,
|
body = new_text,
|
||||||
@@ -458,8 +469,8 @@ core.confirm = function(self, e, option, callback)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
local keys = {}
|
local keys = {}
|
||||||
table.insert(keys, string.rep(keymap.t('<BS>'), diff_before))
|
table.insert(keys, keymap.backspace(ctx.cursor_line:sub(completion_item.textEdit.range.start.character + 1, ctx.cursor.col - 1)))
|
||||||
table.insert(keys, string.rep(keymap.t('<Del>'), diff_after))
|
table.insert(keys, keymap.delete(ctx.cursor_line:sub(ctx.cursor.col, completion_item.textEdit.range['end'].character)))
|
||||||
table.insert(keys, new_text)
|
table.insert(keys, new_text)
|
||||||
feedkeys.call(table.concat(keys, ''), 'in')
|
feedkeys.call(table.concat(keys, ''), 'in')
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,9 +8,19 @@ local api = require('cmp.utils.api')
|
|||||||
|
|
||||||
describe('cmp.core', function()
|
describe('cmp.core', function()
|
||||||
describe('confirm', function()
|
describe('confirm', function()
|
||||||
local confirm = function(request, filter, completion_item)
|
---@param request string
|
||||||
|
---@param filter string
|
||||||
|
---@param completion_item lsp.CompletionItem
|
||||||
|
---@param option? { position_encoding_kind: lsp.PositionEncodingKind }
|
||||||
|
---@return table
|
||||||
|
local confirm = function(request, filter, completion_item, option)
|
||||||
|
option = option or {}
|
||||||
|
|
||||||
local c = core.new()
|
local c = core.new()
|
||||||
local s = source.new('spec', {
|
local s = source.new('spec', {
|
||||||
|
get_position_encoding_kind = function()
|
||||||
|
return option.position_encoding_kind or types.lsp.PositionEncodingKind.UTF16
|
||||||
|
end,
|
||||||
complete = function(_, _, callback)
|
complete = function(_, _, callback)
|
||||||
callback({ completion_item })
|
callback({ completion_item })
|
||||||
end,
|
end,
|
||||||
@@ -23,7 +33,8 @@ describe('cmp.core', function()
|
|||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
feedkeys.call(filter, 'n', function()
|
feedkeys.call(filter, 'n', function()
|
||||||
c:confirm(c.sources[s.id].entries[1], {})
|
c:confirm(c.sources[s.id].entries[1], {}, function()
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
local state = {}
|
local state = {}
|
||||||
feedkeys.call('', 'x', function()
|
feedkeys.call('', 'x', function()
|
||||||
@@ -111,6 +122,46 @@ describe('cmp.core', function()
|
|||||||
assert.are.same(state.buffer, { '***foo', 'bar', 'baz***' })
|
assert.are.same(state.buffer, { '***foo', 'bar', 'baz***' })
|
||||||
assert.are.same(state.cursor, { 2, 2 })
|
assert.are.same(state.cursor, { 2, 2 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
local char = '🗿'
|
||||||
|
for _, case in ipairs({
|
||||||
|
{
|
||||||
|
encoding = types.lsp.PositionEncodingKind.UTF8,
|
||||||
|
char_size = #char
|
||||||
|
},
|
||||||
|
{
|
||||||
|
encoding = types.lsp.PositionEncodingKind.UTF16,
|
||||||
|
char_size = select(2, vim.str_utfindex(char))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
encoding = types.lsp.PositionEncodingKind.UTF32,
|
||||||
|
char_size = select(1, vim.str_utfindex(char))
|
||||||
|
},
|
||||||
|
}) do
|
||||||
|
it('textEdit & multibyte: ' .. case.encoding , function()
|
||||||
|
local state = confirm(keymap.t('i%s:%s%s:%s<Left><Left><Left>'):format(char, char, char, char), char, {
|
||||||
|
label = char .. char .. char,
|
||||||
|
textEdit = {
|
||||||
|
range = {
|
||||||
|
start = {
|
||||||
|
line = 0,
|
||||||
|
character = case.char_size + #':'
|
||||||
|
},
|
||||||
|
['end'] = {
|
||||||
|
line = 0,
|
||||||
|
character = case.char_size + #':' + case.char_size + case.char_size
|
||||||
|
},
|
||||||
|
},
|
||||||
|
newText = char .. char .. char .. char .. char,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
position_encoding_kind = case.encoding
|
||||||
|
})
|
||||||
|
vim.pretty_print({ state = state, case = case })
|
||||||
|
assert.are.same(state.buffer, { ('%s:%s%s%s%s%s:%s'):format(char, char, char, char, char, char, char) })
|
||||||
|
assert.are.same(state.cursor, { 1, #('%s:%s%s%s%s%s'):format(char, char, char, char, char, char) })
|
||||||
|
end)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('cmdline-mode', function()
|
describe('cmdline-mode', function()
|
||||||
|
|||||||
@@ -29,8 +29,9 @@ local entry = {}
|
|||||||
---@param ctx cmp.Context
|
---@param ctx cmp.Context
|
||||||
---@param source cmp.Source
|
---@param source cmp.Source
|
||||||
---@param completion_item lsp.CompletionItem
|
---@param completion_item lsp.CompletionItem
|
||||||
|
---@param item_defaults? lsp.internal.CompletionItemDefaults
|
||||||
---@return cmp.Entry
|
---@return cmp.Entry
|
||||||
entry.new = function(ctx, source, completion_item)
|
entry.new = function(ctx, source, completion_item, item_defaults)
|
||||||
local self = setmetatable({}, { __index = entry })
|
local self = setmetatable({}, { __index = entry })
|
||||||
self.id = misc.id('entry.new')
|
self.id = misc.id('entry.new')
|
||||||
self.cache = cache.new()
|
self.cache = cache.new()
|
||||||
@@ -43,7 +44,7 @@ entry.new = function(ctx, source, completion_item)
|
|||||||
self.source_offset = source.request_offset
|
self.source_offset = source.request_offset
|
||||||
self.source_insert_range = source:get_default_insert_range()
|
self.source_insert_range = source:get_default_insert_range()
|
||||||
self.source_replace_range = source:get_default_replace_range()
|
self.source_replace_range = source:get_default_replace_range()
|
||||||
self.completion_item = completion_item
|
self.completion_item = self:fill_defaults(completion_item, item_defaults)
|
||||||
self.resolved_completion_item = nil
|
self.resolved_completion_item = nil
|
||||||
self.resolved_callbacks = {}
|
self.resolved_callbacks = {}
|
||||||
self.resolving = false
|
self.resolving = false
|
||||||
@@ -57,11 +58,10 @@ entry.get_offset = function(self)
|
|||||||
return self.cache:ensure('get_offset', function()
|
return self.cache:ensure('get_offset', function()
|
||||||
local offset = self.source_offset
|
local offset = self.source_offset
|
||||||
if misc.safe(self:get_completion_item().textEdit) then
|
if misc.safe(self:get_completion_item().textEdit) then
|
||||||
local range = misc.safe(self:get_completion_item().textEdit.insert) or misc.safe(self:get_completion_item().textEdit.range)
|
local range = self:get_insert_range()
|
||||||
if range then
|
if range then
|
||||||
offset = self.context.cache:ensure({ 'entry', 'get_offset', range.start.character }, function()
|
offset = self.context.cache:ensure({ 'entry', 'get_offset', tostring(range.start.character) }, function()
|
||||||
local c = misc.to_vimindex(self.context.cursor_line, range.start.character)
|
for idx = range.start.character + 1, self.source_offset do
|
||||||
for idx = c, self.source_offset do
|
|
||||||
if not char.is_white(string.byte(self.context.cursor_line, idx)) then
|
if not char.is_white(string.byte(self.context.cursor_line, idx)) then
|
||||||
return idx
|
return idx
|
||||||
end
|
end
|
||||||
@@ -128,7 +128,7 @@ entry.get_word = function(self)
|
|||||||
word = str.trim(self:get_completion_item().label)
|
word = str.trim(self:get_completion_item().label)
|
||||||
end
|
end
|
||||||
return str.oneline(word)
|
return str.oneline(word)
|
||||||
end)
|
end) --[[@as string]]
|
||||||
end
|
end
|
||||||
|
|
||||||
---Get overwrite information
|
---Get overwrite information
|
||||||
@@ -136,15 +136,17 @@ end
|
|||||||
entry.get_overwrite = function(self)
|
entry.get_overwrite = function(self)
|
||||||
return self.cache:ensure('get_overwrite', function()
|
return self.cache:ensure('get_overwrite', function()
|
||||||
if misc.safe(self:get_completion_item().textEdit) then
|
if misc.safe(self:get_completion_item().textEdit) then
|
||||||
local range = misc.safe(self:get_completion_item().textEdit.insert) or misc.safe(self:get_completion_item().textEdit.range)
|
local range = self:get_insert_range()
|
||||||
if range then
|
if range then
|
||||||
return self.context.cache:ensure({ 'entry', 'get_overwrite', range.start.character, range['end'].character }, function()
|
return self.context.cache:ensure({ 'entry', 'get_overwrite', tostring(range.start.character),
|
||||||
local s = misc.to_vimindex(self.context.cursor_line, range.start.character)
|
tostring(range['end'].character) },
|
||||||
local e = misc.to_vimindex(self.context.cursor_line, range['end'].character)
|
function()
|
||||||
local before = self.context.cursor.col - s
|
local vim_start = range.start.character + 1
|
||||||
local after = e - self.context.cursor.col
|
local vim_end = range['end'].character + 1
|
||||||
return { before, after }
|
local before = self.context.cursor.col - vim_start
|
||||||
end)
|
local after = vim_end - self.context.cursor.col
|
||||||
|
return { before, after }
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return { 0, 0 }
|
return { 0, 0 }
|
||||||
@@ -190,7 +192,8 @@ end
|
|||||||
---Return the item is deprecated or not.
|
---Return the item is deprecated or not.
|
||||||
---@return boolean
|
---@return boolean
|
||||||
entry.is_deprecated = function(self)
|
entry.is_deprecated = function(self)
|
||||||
return self:get_completion_item().deprecated or vim.tbl_contains(self:get_completion_item().tags or {}, types.lsp.CompletionItemTag.Deprecated)
|
return self:get_completion_item().deprecated or
|
||||||
|
vim.tbl_contains(self:get_completion_item().tags or {}, types.lsp.CompletionItemTag.Deprecated)
|
||||||
end
|
end
|
||||||
|
|
||||||
---Return view information.
|
---Return view information.
|
||||||
@@ -199,7 +202,7 @@ end
|
|||||||
---@return { abbr: { text: string, bytes: integer, width: integer, hl_group: string }, kind: { text: string, bytes: integer, width: integer, hl_group: string }, menu: { text: string, bytes: integer, width: integer, hl_group: string } }
|
---@return { abbr: { text: string, bytes: integer, width: integer, hl_group: string }, kind: { text: string, bytes: integer, width: integer, hl_group: string }, menu: { text: string, bytes: integer, width: integer, hl_group: string } }
|
||||||
entry.get_view = function(self, suggest_offset, entries_buf)
|
entry.get_view = function(self, suggest_offset, entries_buf)
|
||||||
local item = self:get_vim_item(suggest_offset)
|
local item = self:get_vim_item(suggest_offset)
|
||||||
return self.cache:ensure({ 'get_view', entries_buf }, function()
|
return self.cache:ensure({ 'get_view', tostring(entries_buf) }, function()
|
||||||
local view = {}
|
local view = {}
|
||||||
-- The result of vim.fn.strdisplaywidth depends on which buffer it was
|
-- The result of vim.fn.strdisplaywidth depends on which buffer it was
|
||||||
-- called in because it reads the values of the option 'tabstop' when
|
-- called in because it reads the values of the option 'tabstop' when
|
||||||
@@ -214,7 +217,9 @@ entry.get_view = function(self, suggest_offset, entries_buf)
|
|||||||
view.kind.text = item.kind or ''
|
view.kind.text = item.kind or ''
|
||||||
view.kind.bytes = #view.kind.text
|
view.kind.bytes = #view.kind.text
|
||||||
view.kind.width = vim.fn.strdisplaywidth(view.kind.text)
|
view.kind.width = vim.fn.strdisplaywidth(view.kind.text)
|
||||||
view.kind.hl_group = item.kind_hl_group or ('CmpItemKind' .. (types.lsp.CompletionItemKind[self:get_kind()] or ''))
|
view.kind.hl_group = item.kind_hl_group or
|
||||||
|
('CmpItemKind' .. (types.lsp.CompletionItemKind[self:get_kind()] or '')
|
||||||
|
)
|
||||||
view.menu = {}
|
view.menu = {}
|
||||||
view.menu.text = item.menu or ''
|
view.menu.text = item.menu or ''
|
||||||
view.menu.bytes = #view.menu.text
|
view.menu.bytes = #view.menu.text
|
||||||
@@ -230,7 +235,7 @@ end
|
|||||||
---@param suggest_offset integer
|
---@param suggest_offset integer
|
||||||
---@return vim.CompletedItem
|
---@return vim.CompletedItem
|
||||||
entry.get_vim_item = function(self, suggest_offset)
|
entry.get_vim_item = function(self, suggest_offset)
|
||||||
return self.cache:ensure({ 'get_vim_item', suggest_offset }, function()
|
return self.cache:ensure({ 'get_vim_item', tostring(suggest_offset) }, function()
|
||||||
local completion_item = self:get_completion_item()
|
local completion_item = self:get_completion_item()
|
||||||
local word = self:get_word()
|
local word = self:get_word()
|
||||||
local abbr = str.oneline(completion_item.label)
|
local abbr = str.oneline(completion_item.label)
|
||||||
@@ -314,13 +319,17 @@ entry.get_insert_range = function(self)
|
|||||||
if misc.safe(self:get_completion_item().textEdit.insert) then
|
if misc.safe(self:get_completion_item().textEdit.insert) then
|
||||||
insert_range = self:get_completion_item().textEdit.insert
|
insert_range = self:get_completion_item().textEdit.insert
|
||||||
else
|
else
|
||||||
insert_range = self:get_completion_item().textEdit.range
|
insert_range = self:get_completion_item().textEdit.range --[[@as lsp.Range]]
|
||||||
end
|
end
|
||||||
|
insert_range = {
|
||||||
|
start = self:convert_position_encoding(insert_range.start),
|
||||||
|
['end'] = self:convert_position_encoding(insert_range['end']),
|
||||||
|
}
|
||||||
else
|
else
|
||||||
insert_range = {
|
insert_range = {
|
||||||
start = {
|
start = {
|
||||||
line = self.context.cursor.row - 1,
|
line = self.context.cursor.row - 1,
|
||||||
character = math.min(misc.to_utfindex(self.context.cursor_line, self:get_offset()), self.source_insert_range.start.character),
|
character = self:get_offset() - 1,
|
||||||
},
|
},
|
||||||
['end'] = self.source_insert_range['end'],
|
['end'] = self.source_insert_range['end'],
|
||||||
}
|
}
|
||||||
@@ -337,15 +346,19 @@ entry.get_replace_range = function(self)
|
|||||||
if misc.safe(self:get_completion_item().textEdit.replace) then
|
if misc.safe(self:get_completion_item().textEdit.replace) then
|
||||||
replace_range = self:get_completion_item().textEdit.replace
|
replace_range = self:get_completion_item().textEdit.replace
|
||||||
else
|
else
|
||||||
replace_range = self:get_completion_item().textEdit.range
|
replace_range = self:get_completion_item().textEdit.range --[[@as lsp.Range]]
|
||||||
end
|
end
|
||||||
|
replace_range = {
|
||||||
|
start = self:convert_position_encoding(replace_range.start),
|
||||||
|
['end'] = self:convert_position_encoding(replace_range['end']),
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
if not replace_range or (self.context.cursor.character == replace_range['end'].character) then
|
if not replace_range or ((self.context.cursor.col - 1) == replace_range['end'].character) then
|
||||||
replace_range = {
|
replace_range = {
|
||||||
start = {
|
start = {
|
||||||
line = self.source_replace_range.start.line,
|
line = self.source_replace_range.start.line,
|
||||||
character = math.min(misc.to_utfindex(self.context.cursor_line, self:get_offset()), self.source_replace_range.start.character),
|
character = self:get_offset() - 1
|
||||||
},
|
},
|
||||||
['end'] = self.source_replace_range['end'],
|
['end'] = self.source_replace_range['end'],
|
||||||
}
|
}
|
||||||
@@ -361,10 +374,10 @@ end
|
|||||||
entry.match = function(self, input, matching_config)
|
entry.match = function(self, input, matching_config)
|
||||||
return self.match_cache:ensure({
|
return self.match_cache:ensure({
|
||||||
input,
|
input,
|
||||||
self.resolved_completion_item and 1 or 0,
|
self.resolved_completion_item and '1' or '0',
|
||||||
matching_config.disallow_fuzzy_matching and 1 or 0,
|
matching_config.disallow_fuzzy_matching and '1' or '0',
|
||||||
matching_config.disallow_partial_matching and 1 or 0,
|
matching_config.disallow_partial_matching and '1' or '0',
|
||||||
matching_config.disallow_prefix_unmatching and 1 or 0,
|
matching_config.disallow_prefix_unmatching and '1' or '0',
|
||||||
}, function()
|
}, function()
|
||||||
local option = {
|
local option = {
|
||||||
disallow_fuzzy_matching = matching_config.disallow_fuzzy_matching,
|
disallow_fuzzy_matching = matching_config.disallow_fuzzy_matching,
|
||||||
@@ -492,4 +505,60 @@ entry.resolve = function(self, callback)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param completion_item lsp.CompletionItem
|
||||||
|
---@param defaults? lsp.internal.CompletionItemDefaults
|
||||||
|
---@return lsp.CompletionItem
|
||||||
|
entry.fill_defaults = function(_, completion_item, defaults)
|
||||||
|
defaults = defaults or {}
|
||||||
|
|
||||||
|
if defaults.data then
|
||||||
|
completion_item.data = completion_item.data or defaults.data
|
||||||
|
end
|
||||||
|
|
||||||
|
if defaults.commitCharacters then
|
||||||
|
completion_item.commitCharacters = completion_item.commitCharacters or defaults.commitCharacters
|
||||||
|
end
|
||||||
|
|
||||||
|
if defaults.insertTextFormat then
|
||||||
|
completion_item.insertTextFormat = completion_item.insertTextFormat or defaults.insertTextFormat
|
||||||
|
end
|
||||||
|
|
||||||
|
if defaults.insertTextMode then
|
||||||
|
completion_item.insertTextMode = completion_item.insertTextMode or defaults.insertTextMode
|
||||||
|
end
|
||||||
|
|
||||||
|
if defaults.editRange then
|
||||||
|
if not completion_item.textEdit then
|
||||||
|
if defaults.editRange.insert then
|
||||||
|
completion_item.textEdit = {
|
||||||
|
insert = defaults.editRange.insert,
|
||||||
|
replace = defaults.editRange.replace,
|
||||||
|
newText = completion_item.textEditText or completion_item.label,
|
||||||
|
}
|
||||||
|
else
|
||||||
|
completion_item.textEdit = {
|
||||||
|
range = defaults.editRange --[[@as lsp.Range]] ,
|
||||||
|
newText = completion_item.textEditText or completion_item.label,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return completion_item
|
||||||
|
end
|
||||||
|
|
||||||
|
---Convert the oneline range encoding.
|
||||||
|
entry.convert_position_encoding = function(self, position)
|
||||||
|
local from_encoding = self.source:get_position_encoding_kind()
|
||||||
|
return self.context.cache:ensure('entry.convert_position_encoding.' .. position.character .. '.' .. from_encoding,
|
||||||
|
function()
|
||||||
|
return types.lsp.Position.to_utf8(
|
||||||
|
self.context.cursor_line,
|
||||||
|
position,
|
||||||
|
from_encoding
|
||||||
|
)
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
return entry
|
return entry
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ source.new = function(name, s)
|
|||||||
end
|
end
|
||||||
|
|
||||||
---Reset current completion state
|
---Reset current completion state
|
||||||
---@return boolean
|
|
||||||
source.reset = function(self)
|
source.reset = function(self)
|
||||||
self.cache:clear()
|
self.cache:clear()
|
||||||
self.revision = self.revision + 1
|
self.revision = self.revision + 1
|
||||||
@@ -124,7 +123,7 @@ source.get_entries = function(self, ctx)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.cache:set({ 'get_entries', self.revision, ctx.cursor_before_line }, entries)
|
self.cache:set({ 'get_entries', tostring(self.revision), ctx.cursor_before_line }, entries)
|
||||||
|
|
||||||
local max_item_count = self:get_source_config().max_item_count or 200
|
local max_item_count = self:get_source_config().max_item_count or 200
|
||||||
local limited_entries = {}
|
local limited_entries = {}
|
||||||
@@ -137,44 +136,44 @@ source.get_entries = function(self, ctx)
|
|||||||
return limited_entries
|
return limited_entries
|
||||||
end
|
end
|
||||||
|
|
||||||
---Get default insert range
|
---Get default insert range (UTF8 byte index).
|
||||||
---@return lsp.Range
|
---@return lsp.Range
|
||||||
source.get_default_insert_range = function(self)
|
source.get_default_insert_range = function(self)
|
||||||
if not self.context then
|
if not self.context then
|
||||||
error('context is not initialized yet.')
|
error('context is not initialized yet.')
|
||||||
end
|
end
|
||||||
|
|
||||||
return self.cache:ensure({ 'get_default_insert_range', self.revision }, function()
|
return self.cache:ensure({ 'get_default_insert_range', tostring(self.revision) }, function()
|
||||||
return {
|
return {
|
||||||
start = {
|
start = {
|
||||||
line = self.context.cursor.row - 1,
|
line = self.context.cursor.row - 1,
|
||||||
character = misc.to_utfindex(self.context.cursor_line, self.offset),
|
character = self.offset - 1,
|
||||||
},
|
},
|
||||||
['end'] = {
|
['end'] = {
|
||||||
line = self.context.cursor.row - 1,
|
line = self.context.cursor.row - 1,
|
||||||
character = misc.to_utfindex(self.context.cursor_line, self.context.cursor.col),
|
character = self.context.cursor.col - 1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
---Get default replace range
|
---Get default replace range (UTF8 byte index).
|
||||||
---@return lsp.Range
|
---@return lsp.Range
|
||||||
source.get_default_replace_range = function(self)
|
source.get_default_replace_range = function(self)
|
||||||
if not self.context then
|
if not self.context then
|
||||||
error('context is not initialized yet.')
|
error('context is not initialized yet.')
|
||||||
end
|
end
|
||||||
|
|
||||||
return self.cache:ensure({ 'get_default_replace_range', self.revision }, function()
|
return self.cache:ensure({ 'get_default_replace_range', tostring(self.revision) }, function()
|
||||||
local _, e = pattern.offset('^' .. '\\%(' .. self:get_keyword_pattern() .. '\\)', string.sub(self.context.cursor_line, self.offset))
|
local _, e = pattern.offset('^' .. '\\%(' .. self:get_keyword_pattern() .. '\\)', string.sub(self.context.cursor_line, self.offset))
|
||||||
return {
|
return {
|
||||||
start = {
|
start = {
|
||||||
line = self.context.cursor.row - 1,
|
line = self.context.cursor.row - 1,
|
||||||
character = misc.to_utfindex(self.context.cursor_line, self.offset),
|
character = self.offset,
|
||||||
},
|
},
|
||||||
['end'] = {
|
['end'] = {
|
||||||
line = self.context.cursor.row - 1,
|
line = self.context.cursor.row - 1,
|
||||||
character = misc.to_utfindex(self.context.cursor_line, e and self.offset + e - 1 or self.context.cursor.col),
|
character = (e and self.offset + e - 2 or self.context.cursor.col - 1),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
@@ -223,7 +222,10 @@ source.get_keyword_pattern = function(self)
|
|||||||
return c.keyword_pattern
|
return c.keyword_pattern
|
||||||
end
|
end
|
||||||
if self.source.get_keyword_pattern then
|
if self.source.get_keyword_pattern then
|
||||||
return self.source:get_keyword_pattern(misc.copy(c))
|
local keyword_pattern = self.source:get_keyword_pattern(misc.copy(c))
|
||||||
|
if keyword_pattern then
|
||||||
|
return keyword_pattern
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return config.get().completion.keyword_pattern
|
return config.get().completion.keyword_pattern
|
||||||
end
|
end
|
||||||
@@ -239,21 +241,30 @@ source.get_keyword_length = function(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
---Get filter
|
---Get filter
|
||||||
--@return function
|
--@return fun(entry: cmp.Entry, context: cmp.Context): boolean
|
||||||
source.get_entry_filter = function(self)
|
source.get_entry_filter = function(self)
|
||||||
local c = self:get_source_config()
|
local c = self:get_source_config()
|
||||||
if c.entry_filter then
|
if c.entry_filter then
|
||||||
return c.entry_filter
|
return c.entry_filter --[[@as fun(entry: cmp.Entry, context: cmp.Context): boolean]]
|
||||||
end
|
end
|
||||||
return function(_, _)
|
return function(_, _)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Get lsp.PositionEncodingKind
|
||||||
|
---@return lsp.PositionEncodingKind
|
||||||
|
source.get_position_encoding_kind = function(self)
|
||||||
|
if self.source.get_position_encoding_kind then
|
||||||
|
return self.source:get_position_encoding_kind()
|
||||||
|
end
|
||||||
|
return types.lsp.PositionEncodingKind.UTF16
|
||||||
|
end
|
||||||
|
|
||||||
---Invoke completion
|
---Invoke completion
|
||||||
---@param ctx cmp.Context
|
---@param ctx cmp.Context
|
||||||
---@param callback function
|
---@param callback function
|
||||||
---@return boolean Return true if not trigger completion.
|
---@return boolean? Return true if not trigger completion.
|
||||||
source.complete = function(self, ctx, callback)
|
source.complete = function(self, ctx, callback)
|
||||||
local offset = ctx:get_offset(self:get_keyword_pattern())
|
local offset = ctx:get_offset(self:get_keyword_pattern())
|
||||||
|
|
||||||
@@ -318,6 +329,7 @@ source.complete = function(self, ctx, callback)
|
|||||||
completion_context = completion_context,
|
completion_context = completion_context,
|
||||||
}),
|
}),
|
||||||
self.complete_dedup(vim.schedule_wrap(function(response)
|
self.complete_dedup(vim.schedule_wrap(function(response)
|
||||||
|
---@type lsp.CompletionResponse
|
||||||
response = response or {}
|
response = response or {}
|
||||||
|
|
||||||
self.incomplete = response.isIncomplete or false
|
self.incomplete = response.isIncomplete or false
|
||||||
@@ -331,7 +343,7 @@ source.complete = function(self, ctx, callback)
|
|||||||
self.entries = {}
|
self.entries = {}
|
||||||
for i, item in ipairs(response.items or response) do
|
for i, item in ipairs(response.items or response) do
|
||||||
if (misc.safe(item) or {}).label then
|
if (misc.safe(item) or {}).label then
|
||||||
local e = entry.new(ctx, self, item)
|
local e = entry.new(ctx, self, item, response.itemDefaults)
|
||||||
self.entries[i] = e
|
self.entries[i] = e
|
||||||
self.offset = math.min(self.offset, e:get_offset())
|
self.offset = math.min(self.offset, e:get_offset())
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,10 +4,18 @@ local misc = require('cmp.utils.misc')
|
|||||||
---@class lsp
|
---@class lsp
|
||||||
local lsp = {}
|
local lsp = {}
|
||||||
|
|
||||||
|
---@enum lsp.PositionEncodingKind
|
||||||
|
lsp.PositionEncodingKind = {
|
||||||
|
UTF8 = 'utf-8',
|
||||||
|
UTF16 = 'utf-16',
|
||||||
|
UTF32 = 'utf-32',
|
||||||
|
}
|
||||||
|
|
||||||
lsp.Position = {
|
lsp.Position = {
|
||||||
---Convert lsp.Position to vim.Position
|
---Convert lsp.Position to vim.Position
|
||||||
---@param buf integer
|
---@param buf integer
|
||||||
---@param position lsp.Position
|
---@param position lsp.Position
|
||||||
|
--
|
||||||
---@return vim.Position
|
---@return vim.Position
|
||||||
to_vim = function(buf, position)
|
to_vim = function(buf, position)
|
||||||
if not vim.api.nvim_buf_is_loaded(buf) then
|
if not vim.api.nvim_buf_is_loaded(buf) then
|
||||||
@@ -45,11 +53,77 @@ lsp.Position = {
|
|||||||
character = position.col - 1,
|
character = position.col - 1,
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
---Convert position to utf8 from specified encoding.
|
||||||
|
---@param text string
|
||||||
|
---@param position lsp.Position
|
||||||
|
---@param from_encoding? lsp.PositionEncodingKind
|
||||||
|
---@return lsp.Position
|
||||||
|
to_utf8 = function(text, position, from_encoding)
|
||||||
|
from_encoding = from_encoding or lsp.PositionEncodingKind.UTF16
|
||||||
|
if from_encoding == lsp.PositionEncodingKind.UTF8 then
|
||||||
|
return position
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, byteindex = pcall(function()
|
||||||
|
return vim.str_byteindex(text, position.character, from_encoding == lsp.PositionEncodingKind.UTF16)
|
||||||
|
end)
|
||||||
|
if not ok then
|
||||||
|
return position
|
||||||
|
end
|
||||||
|
return { line = position.line, character = byteindex }
|
||||||
|
end,
|
||||||
|
|
||||||
|
---Convert position to utf16 from specified encoding.
|
||||||
|
---@param text string
|
||||||
|
---@param position lsp.Position
|
||||||
|
---@param from_encoding? lsp.PositionEncodingKind
|
||||||
|
---@return lsp.Position
|
||||||
|
to_utf16 = function(text, position, from_encoding)
|
||||||
|
from_encoding = from_encoding or lsp.PositionEncodingKind.UTF16
|
||||||
|
if from_encoding == lsp.PositionEncodingKind.UTF16 then
|
||||||
|
return position
|
||||||
|
end
|
||||||
|
|
||||||
|
local utf8 = lsp.Position.to_utf8(text, position, from_encoding)
|
||||||
|
for index = utf8.character, 0, -1 do
|
||||||
|
local ok, utf16index = pcall(function()
|
||||||
|
return select(2, vim.str_utfindex(text, index))
|
||||||
|
end)
|
||||||
|
if ok then
|
||||||
|
return { line = utf8.line, character = utf16index }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return position
|
||||||
|
end,
|
||||||
|
|
||||||
|
---Convert position to utf32 from specified encoding.
|
||||||
|
---@param text string
|
||||||
|
---@param position lsp.Position
|
||||||
|
---@param from_encoding? lsp.PositionEncodingKind
|
||||||
|
---@return lsp.Position
|
||||||
|
to_utf32 = function(text, position, from_encoding)
|
||||||
|
from_encoding = from_encoding or lsp.PositionEncodingKind.UTF16
|
||||||
|
if from_encoding == lsp.PositionEncodingKind.UTF32 then
|
||||||
|
return position
|
||||||
|
end
|
||||||
|
|
||||||
|
local utf8 = lsp.Position.to_utf8(text, position, from_encoding)
|
||||||
|
for index = utf8.character, 0, -1 do
|
||||||
|
local ok, utf32index = pcall(function()
|
||||||
|
return select(1, vim.str_utfindex(text, index))
|
||||||
|
end)
|
||||||
|
if ok then
|
||||||
|
return { line = utf8.line, character = utf32index }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return position
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
lsp.Range = {
|
lsp.Range = {
|
||||||
---Convert lsp.Range to vim.Range
|
---Convert lsp.Range to vim.Range
|
||||||
---@param buf integer|string
|
---@param buf integer
|
||||||
---@param range lsp.Range
|
---@param range lsp.Range
|
||||||
---@return vim.Range
|
---@return vim.Range
|
||||||
to_vim = function(buf, range)
|
to_vim = function(buf, range)
|
||||||
@@ -60,7 +134,7 @@ lsp.Range = {
|
|||||||
end,
|
end,
|
||||||
|
|
||||||
---Convert vim.Range to lsp.Range
|
---Convert vim.Range to lsp.Range
|
||||||
---@param buf integer|string
|
---@param buf integer
|
||||||
---@param range vim.Range
|
---@param range vim.Range
|
||||||
---@return lsp.Range
|
---@return lsp.Range
|
||||||
to_lsp = function(buf, range)
|
to_lsp = function(buf, range)
|
||||||
@@ -130,15 +204,23 @@ lsp.CompletionItemKind = {
|
|||||||
}
|
}
|
||||||
lsp.CompletionItemKind = vim.tbl_add_reverse_lookup(lsp.CompletionItemKind)
|
lsp.CompletionItemKind = vim.tbl_add_reverse_lookup(lsp.CompletionItemKind)
|
||||||
|
|
||||||
|
---@class lsp.internal.CompletionItemDefaults
|
||||||
|
---@field public commitCharacters? string[]
|
||||||
|
---@field public editRange? lsp.Range | { insert: lsp.Range, replace: lsp.Range }
|
||||||
|
---@field public insertTextFormat? lsp.InsertTextFormat
|
||||||
|
---@field public insertTextMode? lsp.InsertTextMode
|
||||||
|
---@field public data? any
|
||||||
|
|
||||||
---@class lsp.CompletionContext
|
---@class lsp.CompletionContext
|
||||||
---@field public triggerKind lsp.CompletionTriggerKind
|
---@field public triggerKind lsp.CompletionTriggerKind
|
||||||
---@field public triggerCharacter string|nil
|
---@field public triggerCharacter string|nil
|
||||||
|
|
||||||
---@class lsp.CompletionList
|
---@class lsp.CompletionList
|
||||||
---@field public isIncomplete boolean
|
---@field public isIncomplete boolean
|
||||||
|
---@field public itemDefaults? lsp.internal.CompletionItemDefaults
|
||||||
---@field public items lsp.CompletionItem[]
|
---@field public items lsp.CompletionItem[]
|
||||||
|
|
||||||
---@alias lsp.CompletionResponse lsp.CompletionList|lsp.CompletionItem[]|nil
|
---@alias lsp.CompletionResponse lsp.CompletionList|lsp.CompletionItem[]
|
||||||
|
|
||||||
---@class lsp.MarkupContent
|
---@class lsp.MarkupContent
|
||||||
---@field public kind lsp.MarkupKind
|
---@field public kind lsp.MarkupKind
|
||||||
@@ -168,37 +250,38 @@ lsp.CompletionItemKind = vim.tbl_add_reverse_lookup(lsp.CompletionItemKind)
|
|||||||
---@field public newText string
|
---@field public newText string
|
||||||
|
|
||||||
---@class lsp.internal.ReplaceTextEdit
|
---@class lsp.internal.ReplaceTextEdit
|
||||||
---@field public insert lsp.Range
|
---@field public replace lsp.Range
|
||||||
---@field public newText string
|
---@field public newText string
|
||||||
|
|
||||||
---@class lsp.CompletionItemLabelDetails
|
---@class lsp.CompletionItemLabelDetails
|
||||||
---@field public detail string|nil
|
---@field public detail? string
|
||||||
---@field public description string|nil
|
---@field public description? string
|
||||||
|
|
||||||
---@class lsp.Cmp
|
---@class lsp.internal.CmpCompletionExtension
|
||||||
---@field public kind_text string
|
---@field public kind_text string
|
||||||
---@field public kind_hl_group string
|
---@field public kind_hl_group string
|
||||||
|
|
||||||
---@class lsp.CompletionItem
|
---@class lsp.CompletionItem
|
||||||
---@field public label string
|
---@field public label string
|
||||||
---@field public labelDetails lsp.CompletionItemLabelDetails|nil
|
---@field public labelDetails? lsp.CompletionItemLabelDetails
|
||||||
---@field public kind lsp.CompletionItemKind|nil
|
---@field public kind? lsp.CompletionItemKind
|
||||||
---@field public tags lsp.CompletionItemTag[]|nil
|
---@field public tags? lsp.CompletionItemTag[]
|
||||||
---@field public detail string|nil
|
---@field public detail? string
|
||||||
---@field public documentation lsp.MarkupContent|string|nil
|
---@field public documentation? lsp.MarkupContent|string
|
||||||
---@field public deprecated boolean|nil
|
---@field public deprecated? boolean
|
||||||
---@field public preselect boolean|nil
|
---@field public preselect? boolean
|
||||||
---@field public sortText string|nil
|
---@field public sortText? string
|
||||||
---@field public filterText string|nil
|
---@field public filterText? string
|
||||||
---@field public insertText string|nil
|
---@field public insertText? string
|
||||||
---@field public insertTextFormat lsp.InsertTextFormat
|
---@field public insertTextFormat? lsp.InsertTextFormat
|
||||||
---@field public insertTextMode lsp.InsertTextMode
|
---@field public insertTextMode? lsp.InsertTextMode
|
||||||
---@field public textEdit lsp.TextEdit|lsp.InsertReplaceTextEdit|nil
|
---@field public textEdit? lsp.TextEdit|lsp.InsertReplaceTextEdit
|
||||||
---@field public additionalTextEdits lsp.TextEdit[]
|
---@field public textEditText? string
|
||||||
---@field public commitCharacters string[]|nil
|
---@field public additionalTextEdits? lsp.TextEdit[]
|
||||||
---@field public command lsp.Command|nil
|
---@field public commitCharacters? string[]
|
||||||
---@field public data any|nil
|
---@field public command? lsp.Command
|
||||||
---@field public cmp lsp.Cmp|nil
|
---@field public data? any
|
||||||
|
---@field public cmp? lsp.internal.CmpCompletionExtension
|
||||||
---
|
---
|
||||||
---TODO: Should send the issue for upstream?
|
---TODO: Should send the issue for upstream?
|
||||||
---@field public word string|nil
|
---@field public word string|nil
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
---@field public kind_hl_group string|nil
|
---@field public kind_hl_group string|nil
|
||||||
---@field public menu_hl_group string|nil
|
---@field public menu_hl_group string|nil
|
||||||
|
|
||||||
---@class vim.Position
|
---@class vim.Position 1-based index
|
||||||
---@field public row integer
|
---@field public row integer
|
||||||
---@field public col integer
|
---@field public col integer
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,21 @@ keymap.backspace = function(count)
|
|||||||
return table.concat(keys, '')
|
return table.concat(keys, '')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Create delete keys.
|
||||||
|
---@param count string|integer
|
||||||
|
---@return string
|
||||||
|
keymap.delete = function(count)
|
||||||
|
if type(count) == 'string' then
|
||||||
|
count = vim.fn.strchars(count, true)
|
||||||
|
end
|
||||||
|
if count <= 0 then
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
local keys = {}
|
||||||
|
table.insert(keys, keymap.t(string.rep('<Del>', count)))
|
||||||
|
return table.concat(keys, '')
|
||||||
|
end
|
||||||
|
|
||||||
---Update indentkeys.
|
---Update indentkeys.
|
||||||
---@param expr? string
|
---@param expr? string
|
||||||
---@return string
|
---@return string
|
||||||
|
|||||||
Reference in New Issue
Block a user