From 3ffe29d679b2a4aee5a2f6fd9eee4845c4fef0e5 Mon Sep 17 00:00:00 2001 From: glepnir Date: Mon, 18 May 2026 17:25:41 +0800 Subject: [PATCH] fix(lsp): preserve trigger chars on completion #39850 Problem: After 767fbd8, typing trigger chars would open completion but the chars were removed. Solution: Use filterText fallback so selected item respects typed trigger chars. --- runtime/lua/vim/lsp/completion.lua | 23 ++++++++----------- .../functional/plugin/lsp/completion_spec.lua | 8 +++++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 4f6c9022ea..a096d778b4 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -168,6 +168,13 @@ local function apply_snippet(item) end end +local function fallback_filtertext(item, word, prefix, match) + if item.filterText and not match(word, prefix) and match(item.filterText, prefix) then + return item.filterText + end + return word +end + --- Returns text that should be inserted when a selecting completion item. The --- precedence is as follows: textEdit.newText > insertText > label --- @@ -200,11 +207,7 @@ local function get_completion_word(item, prefix, match) item.filterText and vim.fn.match(item.label, '^\\k') == -1 and item.filterText or item.label ) - if item.filterText and not match(word, prefix) then - return item.filterText - else - return word - end + return fallback_filtertext(item, word, prefix, match) else return item.label end @@ -212,15 +215,9 @@ local function get_completion_word(item, prefix, match) local word = item.textEdit.newText word = string.gsub(word, '\r\n?', '\n') word = word:match('([^\n]*)') or word - if item.filterText and not match(word, prefix) then - return item.filterText - end - return word + return fallback_filtertext(item, word, prefix, match) 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 fallback_filtertext(item, item.insertText, prefix, match) end return item.label end diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 00ef82327c..2e74c5677d 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -457,10 +457,14 @@ describe('vim.lsp.completion: item conversion', function() it('works on non word prefix', function() local completion_list = { - { label = ' foo', insertText = '->foo' }, + { label = ' foo', insertText = '->foo', sortText = '1' }, + { label = ' bar', insertText = '->bar', filterText = 'bar', sortText = '2' }, } local result = complete('wp.|', completion_list, 0, 2) - eq({ { abbr = ' foo', word = '->foo' } }, extract_word_abbr(result.items)) + eq({ + { abbr = ' foo', word = '->foo' }, + { abbr = ' bar', word = '->bar' }, + }, extract_word_abbr(result.items)) end) it('trims trailing newline or tab from textEdit', function()