mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
fix(lsp): use filterText as word if textEdit/label doesn't match
Problem: With language servers like lemminx, completing xml tags like `<mo` first shows the right candidates (`modules`) but after typing `d` the candidates disappear. This is because the server returns: [...] filterText = "<module", label = "module", textEdit = { newText = "<module>$1</module>$0", Which resulted in `module` being used as `word`, and `module` doesn't match the prefix `<mo`. Typing `d` causes the `complete()` filtering mechanism to kick in and remove the entry. Solution: Use `<module` from the `filterText` as `word` if the textEdit/label heuristic doesn't match.
This commit is contained in:
parent
3530182ba4
commit
b9e6fa7ec8
@ -127,8 +127,10 @@ end
|
|||||||
--- See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
|
--- See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
|
||||||
---
|
---
|
||||||
--- @param item lsp.CompletionItem
|
--- @param item lsp.CompletionItem
|
||||||
|
--- @param prefix string
|
||||||
|
--- @param match fun(text: string, prefix: string):boolean
|
||||||
--- @return string
|
--- @return string
|
||||||
local function get_completion_word(item)
|
local function get_completion_word(item, prefix, match)
|
||||||
if item.insertTextFormat == protocol.InsertTextFormat.Snippet then
|
if item.insertTextFormat == protocol.InsertTextFormat.Snippet then
|
||||||
if item.textEdit then
|
if item.textEdit then
|
||||||
-- Use label instead of text if text has different starting characters.
|
-- Use label instead of text if text has different starting characters.
|
||||||
@ -146,7 +148,12 @@ local function get_completion_word(item)
|
|||||||
--
|
--
|
||||||
-- Typing `i` would remove the candidate because newText starts with `t`.
|
-- Typing `i` would remove the candidate because newText starts with `t`.
|
||||||
local text = parse_snippet(item.insertText or item.textEdit.newText)
|
local text = parse_snippet(item.insertText or item.textEdit.newText)
|
||||||
return #text < #item.label and vim.fn.matchstr(text, '\\k*') or item.label
|
local word = #text < #item.label and vim.fn.matchstr(text, '\\k*') or item.label
|
||||||
|
if item.filterText and not match(word, prefix) then
|
||||||
|
return item.filterText
|
||||||
|
else
|
||||||
|
return word
|
||||||
|
end
|
||||||
elseif item.insertText and item.insertText ~= '' then
|
elseif item.insertText and item.insertText ~= '' then
|
||||||
return parse_snippet(item.insertText)
|
return parse_snippet(item.insertText)
|
||||||
else
|
else
|
||||||
@ -276,7 +283,7 @@ function M._lsp_to_complete_items(result, prefix, client_id)
|
|||||||
local user_convert = vim.tbl_get(buf_handles, bufnr, 'convert')
|
local user_convert = vim.tbl_get(buf_handles, bufnr, 'convert')
|
||||||
for _, item in ipairs(items) do
|
for _, item in ipairs(items) do
|
||||||
if matches(item) then
|
if matches(item) then
|
||||||
local word = get_completion_word(item)
|
local word = get_completion_word(item, prefix, match_item_by_value)
|
||||||
local hl_group = ''
|
local hl_group = ''
|
||||||
if
|
if
|
||||||
item.deprecated
|
item.deprecated
|
||||||
|
@ -216,6 +216,38 @@ describe('vim.lsp.completion: item conversion', function()
|
|||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('uses filterText as word if label/newText would not match', function()
|
||||||
|
local items = {
|
||||||
|
{
|
||||||
|
filterText = '<module',
|
||||||
|
insertTextFormat = 2,
|
||||||
|
kind = 10,
|
||||||
|
label = 'module',
|
||||||
|
sortText = 'module',
|
||||||
|
textEdit = {
|
||||||
|
newText = '<module>$1</module>$0',
|
||||||
|
range = {
|
||||||
|
start = {
|
||||||
|
character = 0,
|
||||||
|
line = 0,
|
||||||
|
},
|
||||||
|
['end'] = {
|
||||||
|
character = 0,
|
||||||
|
line = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
local expected = {
|
||||||
|
{
|
||||||
|
abbr = 'module',
|
||||||
|
word = '<module',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert_completion_matches('<mo', items, expected)
|
||||||
|
end)
|
||||||
|
|
||||||
it('fuzzy matches on label when filterText is missing', function()
|
it('fuzzy matches on label when filterText is missing', function()
|
||||||
assert_completion_matches('fo', {
|
assert_completion_matches('fo', {
|
||||||
{ label = 'foo' },
|
{ label = 'foo' },
|
||||||
|
Loading…
Reference in New Issue
Block a user