From e2ed8053bf722d4d111fac7dcdb07179fdea8752 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Tue, 18 Feb 2020 17:41:29 +0900 Subject: lua: move test helper function, map and filter, to vim.shared module --- runtime/lua/vim/shared.lua | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 6eb7a970e4..498992aa2e 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -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 -- cgit From 4ac376740c85ee337fc10627a793452300801ce0 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Tue, 18 Feb 2020 13:38:52 +0900 Subject: lsp: fix textDocument/completion handling fix: #11826 Some lanuguage servers return complementary candidates whose prefixes do not match are also returned. So we exclude completion candidates whose prefix does not match. ex) Microsoft python-language-server, rust-analyzer --- runtime/lua/vim/lsp.lua | 4 +++- runtime/lua/vim/lsp/callbacks.lua | 3 ++- runtime/lua/vim/lsp/util.lua | 17 ++++++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 94f0d62d8d..bc0da25ae5 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -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) diff --git a/runtime/lua/vim/lsp/callbacks.lua b/runtime/lua/vim/lsp/callbacks.lua index 794140ee2e..e76e07ca96 100644 --- a/runtime/lua/vim/lsp/callbacks.lua +++ b/runtime/lua/vim/lsp/callbacks.lua @@ -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 diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 428874f2b7..620037d24d 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -129,6 +129,19 @@ function M.extract_completion_items(result) 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. +function M.remove_unmatch_completion_items(items, prefix) + local matched_items = {} + for _, item in ipairs(items) do + local word = item.insertText or item.label + if vim.startswith(word, prefix) then + table.insert(matched_items, item) + end + end + return matched_items +end + --- Apply the TextDocumentEdit response. -- @params TextDocumentEdit [table] see https://microsoft.github.io/language-server-protocol/specification function M.apply_text_document_edit(text_document_edit) @@ -151,12 +164,14 @@ 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 = M.remove_unmatch_completion_items(items, prefix) + local matches = {} for _, completion_item in ipairs(items) do -- cgit From c1bfc8093f4fb4487a2293f09558f46c7de49315 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Tue, 18 Feb 2020 13:40:24 +0900 Subject: lsp: respect the sort order if there is sortText --- runtime/lua/vim/lsp/util.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 620037d24d..0a24444328 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -129,6 +129,15 @@ function M.extract_completion_items(result) end end +-- Sort by CompletionItem.sortText +-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion +function M.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. function M.remove_unmatch_completion_items(items, prefix) @@ -171,6 +180,7 @@ function M.text_document_completion_list_to_complete_items(result, prefix) end items = M.remove_unmatch_completion_items(items, prefix) + M.sort_completion_items(items) local matches = {} -- cgit From f3d4ddd0f8b654d58fb4653d88ac7f652e3ad364 Mon Sep 17 00:00:00 2001 From: Hirokazu Hata Date: Wed, 19 Feb 2020 07:39:56 +0900 Subject: lsp: make functions private and use filter function --- runtime/lua/vim/lsp/util.lua | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 0a24444328..6b12b37ec2 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -129,28 +129,6 @@ function M.extract_completion_items(result) end end --- Sort by CompletionItem.sortText --- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion -function M.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. -function M.remove_unmatch_completion_items(items, prefix) - local matched_items = {} - for _, item in ipairs(items) do - local word = item.insertText or item.label - if vim.startswith(word, prefix) then - table.insert(matched_items, item) - end - end - return matched_items -end - --- Apply the TextDocumentEdit response. -- @params TextDocumentEdit [table] see https://microsoft.github.io/language-server-protocol/specification function M.apply_text_document_edit(text_document_edit) @@ -170,6 +148,24 @@ 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 } @@ -179,8 +175,8 @@ function M.text_document_completion_list_to_complete_items(result, prefix) return {} end - items = M.remove_unmatch_completion_items(items, prefix) - M.sort_completion_items(items) + items = remove_unmatch_completion_items(items, prefix) + sort_completion_items(items) local matches = {} -- cgit