mirror of
https://github.com/neovim/neovim.git
synced 2026-05-26 14:58:28 +00:00
fix(lsp): fallback to filterText for non-matching PlainText items #39695
Problem: PlainText completion items used `textEdit.newText` or `insertText` as the completion word even when they did not match the typed prefix. This could break popup completion behavior like 'completeopt+=longest'. Solution: Fall back to `filterText` when `newText` or `insertText` does not match the typed prefix.
This commit is contained in:
@@ -211,8 +211,15 @@ local function get_completion_word(item, prefix, match)
|
|||||||
elseif item.textEdit then
|
elseif item.textEdit then
|
||||||
local word = item.textEdit.newText
|
local word = item.textEdit.newText
|
||||||
word = string.gsub(word, '\r\n?', '\n')
|
word = string.gsub(word, '\r\n?', '\n')
|
||||||
return word:match('([^\n]*)') or word
|
word = word:match('([^\n]*)') or word
|
||||||
|
if item.filterText and not match(word, prefix) then
|
||||||
|
return item.filterText
|
||||||
|
end
|
||||||
|
return word
|
||||||
elseif item.insertText and item.insertText ~= '' then
|
elseif item.insertText and item.insertText ~= '' then
|
||||||
|
if item.filterText and not match(item.insertText, prefix) then
|
||||||
|
return item.filterText
|
||||||
|
end
|
||||||
return item.insertText
|
return item.insertText
|
||||||
end
|
end
|
||||||
return item.label
|
return item.label
|
||||||
|
|||||||
@@ -222,6 +222,59 @@ describe('vim.lsp.completion: item conversion', function()
|
|||||||
eq(expected, got)
|
eq(expected, got)
|
||||||
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 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filterText = 'atto',
|
||||||
|
insertTextFormat = 1,
|
||||||
|
kind = 7,
|
||||||
|
label = '•std::atto',
|
||||||
|
sortText = 'atto',
|
||||||
|
textEdit = {
|
||||||
|
newText = 'std::atto',
|
||||||
|
range = {
|
||||||
|
start = { character = 0, line = 0 },
|
||||||
|
['end'] = { character = 0, line = 0 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filterText = 'adopt_lock_t',
|
||||||
|
insertTextFormat = 1,
|
||||||
|
kind = 7,
|
||||||
|
label = '•std::adopt_lock_t',
|
||||||
|
sortText = 'adopt_lock_t',
|
||||||
|
insertText = 'std::adopt_lock_t',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert_completion_matches('<mo', items, {
|
||||||
|
{ abbr = 'module', word = '<module' },
|
||||||
|
})
|
||||||
|
assert_completion_matches('a', items, {
|
||||||
|
{ abbr = '•std::atto', word = 'atto' },
|
||||||
|
{ abbr = '•std::adopt_lock_t', word = 'adopt_lock_t' },
|
||||||
|
})
|
||||||
|
assert_completion_matches('', items, {
|
||||||
|
{ abbr = 'module', word = 'module' },
|
||||||
|
{ abbr = '•std::atto', word = 'std::atto' },
|
||||||
|
{ abbr = '•std::adopt_lock_t', word = 'std::adopt_lock_t' },
|
||||||
|
})
|
||||||
|
end)
|
||||||
|
|
||||||
describe('when completeopt has fuzzy matching enabled', function()
|
describe('when completeopt has fuzzy matching enabled', function()
|
||||||
before_each(function()
|
before_each(function()
|
||||||
exec_lua(function()
|
exec_lua(function()
|
||||||
@@ -245,31 +298,6 @@ 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 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert_completion_matches('<mo', items, {
|
|
||||||
{ abbr = 'module', word = '<module' },
|
|
||||||
})
|
|
||||||
assert_completion_matches('', items, {
|
|
||||||
{ abbr = 'module', word = 'module' },
|
|
||||||
})
|
|
||||||
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' },
|
||||||
|
|||||||
Reference in New Issue
Block a user