mirror of
https://github.com/neovim/neovim.git
synced 2026-07-21 00:21:38 +00:00
Merge #11895 'lsp: fix textDocument/completion handling'
This commit is contained in:
@@ -945,12 +945,14 @@ function lsp.omnifunc(findstart, base)
|
||||
|
||||
-- Get the start position of the current keyword
|
||||
local textMatch = vim.fn.match(line_to_cursor, '\\k*$')
|
||||
local prefix = line_to_cursor:sub(textMatch+1)
|
||||
|
||||
local params = util.make_position_params()
|
||||
|
||||
local items = {}
|
||||
lsp.buf_request(bufnr, 'textDocument/completion', params, function(err, _, result)
|
||||
if err or not result then return end
|
||||
local matches = util.text_document_completion_list_to_complete_items(result)
|
||||
local matches = util.text_document_completion_list_to_complete_items(result, prefix)
|
||||
-- TODO(ashkan): is this the best way to do this?
|
||||
vim.list_extend(items, matches)
|
||||
vim.fn.complete(textMatch+1, items)
|
||||
|
||||
@@ -63,8 +63,9 @@ M['textDocument/completion'] = function(_, _, result)
|
||||
local line = assert(api.nvim_buf_get_lines(0, row-1, row, false)[1])
|
||||
local line_to_cursor = line:sub(col+1)
|
||||
local textMatch = vim.fn.match(line_to_cursor, '\\k*$')
|
||||
local prefix = line_to_cursor:sub(textMatch+1)
|
||||
|
||||
local matches = util.text_document_completion_list_to_complete_items(result)
|
||||
local matches = util.text_document_completion_list_to_complete_items(result, prefix)
|
||||
vim.fn.complete(textMatch+1, matches)
|
||||
end
|
||||
|
||||
|
||||
@@ -148,15 +148,36 @@ function M.get_current_line_to_cursor()
|
||||
return line:sub(pos[2]+1)
|
||||
end
|
||||
|
||||
-- Sort by CompletionItem.sortText
|
||||
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
|
||||
local function sort_completion_items(items)
|
||||
if items[1] and items[1].sortText then
|
||||
table.sort(items, function(a, b) return a.sortText < b.sortText
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Some lanuguage servers return complementary candidates whose prefixes do not match are also returned.
|
||||
-- So we exclude completion candidates whose prefix does not match.
|
||||
local function remove_unmatch_completion_items(items, prefix)
|
||||
return vim.tbl_filter(function(item)
|
||||
local word = item.insertText or item.label
|
||||
return vim.startswith(word, prefix)
|
||||
end, items)
|
||||
end
|
||||
|
||||
--- Getting vim complete-items with incomplete flag.
|
||||
-- @params CompletionItem[], CompletionList or nil (https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
|
||||
-- @return { matches = complete-items table, incomplete = boolean }
|
||||
function M.text_document_completion_list_to_complete_items(result)
|
||||
function M.text_document_completion_list_to_complete_items(result, prefix)
|
||||
local items = M.extract_completion_items(result)
|
||||
if vim.tbl_isempty(items) then
|
||||
return {}
|
||||
end
|
||||
|
||||
items = remove_unmatch_completion_items(items, prefix)
|
||||
sort_completion_items(items)
|
||||
|
||||
local matches = {}
|
||||
|
||||
for _, completion_item in ipairs(items) do
|
||||
|
||||
@@ -135,6 +135,36 @@ function vim.tbl_values(t)
|
||||
return values
|
||||
end
|
||||
|
||||
--- Apply a function to all values of a table.
|
||||
---
|
||||
--@param func function or callable table
|
||||
--@param t table
|
||||
function vim.tbl_map(func, t)
|
||||
vim.validate{func={func,'c'},t={t,'t'}}
|
||||
|
||||
local rettab = {}
|
||||
for k, v in pairs(t) do
|
||||
rettab[k] = func(v)
|
||||
end
|
||||
return rettab
|
||||
end
|
||||
|
||||
--- Filter a table using a predicate function
|
||||
---
|
||||
--@param func function or callable table
|
||||
--@param t table
|
||||
function vim.tbl_filter(func, t)
|
||||
vim.validate{func={func,'c'},t={t,'t'}}
|
||||
|
||||
local rettab = {}
|
||||
for _, entry in pairs(t) do
|
||||
if func(entry) then
|
||||
table.insert(rettab, entry)
|
||||
end
|
||||
end
|
||||
return rettab
|
||||
end
|
||||
|
||||
--- Checks if a list-like (vector) table contains `value`.
|
||||
---
|
||||
--@param t Table to check
|
||||
|
||||
@@ -6,7 +6,7 @@ local command = helpers.command
|
||||
local eq = helpers.eq
|
||||
local eval = helpers.eval
|
||||
local feed = helpers.feed
|
||||
local map = helpers.map
|
||||
local map = helpers.tbl_map
|
||||
local nvim = helpers.nvim
|
||||
local parse_context = helpers.parse_context
|
||||
local redir_exec = helpers.redir_exec
|
||||
|
||||
@@ -15,9 +15,9 @@ local check_cores = global_helpers.check_cores
|
||||
local check_logs = global_helpers.check_logs
|
||||
local dedent = global_helpers.dedent
|
||||
local eq = global_helpers.eq
|
||||
local filter = global_helpers.filter
|
||||
local filter = global_helpers.tbl_filter
|
||||
local is_os = global_helpers.is_os
|
||||
local map = global_helpers.map
|
||||
local map = global_helpers.tbl_map
|
||||
local ok = global_helpers.ok
|
||||
local sleep = global_helpers.sleep
|
||||
local tbl_contains = global_helpers.tbl_contains
|
||||
|
||||
@@ -384,6 +384,30 @@ describe('lua stdlib', function()
|
||||
end
|
||||
end)
|
||||
|
||||
it('vim.tbl_map', function()
|
||||
eq({}, exec_lua([[
|
||||
return vim.tbl_map(function(v) return v * 2 end, {})
|
||||
]]))
|
||||
eq({2, 4, 6}, exec_lua([[
|
||||
return vim.tbl_map(function(v) return v * 2 end, {1, 2, 3})
|
||||
]]))
|
||||
eq({{i=2}, {i=4}, {i=6}}, exec_lua([[
|
||||
return vim.tbl_map(function(v) return { i = v.i * 2 } end, {{i=1}, {i=2}, {i=3}})
|
||||
]]))
|
||||
end)
|
||||
|
||||
it('vim.tbl_filter', function()
|
||||
eq({}, exec_lua([[
|
||||
return vim.tbl_filter(function(v) return (v % 2) == 0 end, {})
|
||||
]]))
|
||||
eq({2}, exec_lua([[
|
||||
return vim.tbl_filter(function(v) return (v % 2) == 0 end, {1, 2, 3})
|
||||
]]))
|
||||
eq({{i=2}}, exec_lua([[
|
||||
return vim.tbl_filter(function(v) return (v.i % 2) == 0 end, {{i=1}, {i=2}, {i=3}})
|
||||
]]))
|
||||
end)
|
||||
|
||||
it('vim.tbl_islist', function()
|
||||
eq(true, exec_lua("return vim.tbl_islist({})"))
|
||||
eq(false, exec_lua("return vim.tbl_islist(vim.empty_dict())"))
|
||||
|
||||
@@ -6,8 +6,8 @@ local insert = helpers.insert
|
||||
local feed = helpers.feed
|
||||
local expect = helpers.expect
|
||||
local eq = helpers.eq
|
||||
local map = helpers.map
|
||||
local filter = helpers.filter
|
||||
local map = helpers.tbl_map
|
||||
local filter = helpers.tbl_filter
|
||||
local feed_command = helpers.feed_command
|
||||
local curbuf_contents = helpers.curbuf_contents
|
||||
local funcs = helpers.funcs
|
||||
|
||||
@@ -290,24 +290,6 @@ module.tmpname = (function()
|
||||
end)
|
||||
end)()
|
||||
|
||||
function module.map(func, tab)
|
||||
local rettab = {}
|
||||
for k, v in pairs(tab) do
|
||||
rettab[k] = func(v)
|
||||
end
|
||||
return rettab
|
||||
end
|
||||
|
||||
function module.filter(filter_func, tab)
|
||||
local rettab = {}
|
||||
for _, entry in pairs(tab) do
|
||||
if filter_func(entry) then
|
||||
table.insert(rettab, entry)
|
||||
end
|
||||
end
|
||||
return rettab
|
||||
end
|
||||
|
||||
function module.hasenv(name)
|
||||
local env = os.getenv(name)
|
||||
if env and env ~= '' then
|
||||
|
||||
@@ -14,7 +14,7 @@ local cimport = helpers.cimport
|
||||
local to_cstr = helpers.to_cstr
|
||||
local alloc_log_new = helpers.alloc_log_new
|
||||
local concat_tables = helpers.concat_tables
|
||||
local map = helpers.map
|
||||
local map = helpers.tbl_map
|
||||
|
||||
local a = eval_helpers.alloc_logging_helpers
|
||||
local int = eval_helpers.int
|
||||
|
||||
@@ -13,7 +13,7 @@ local syscall = nil
|
||||
local check_cores = global_helpers.check_cores
|
||||
local dedent = global_helpers.dedent
|
||||
local neq = global_helpers.neq
|
||||
local map = global_helpers.map
|
||||
local map = global_helpers.tbl_map
|
||||
local eq = global_helpers.eq
|
||||
local trim = global_helpers.trim
|
||||
|
||||
|
||||
Reference in New Issue
Block a user