From 1f5bcc7c4ed7a68ae4e23933aee04c50b4df8bb5 Mon Sep 17 00:00:00 2001 From: glepnir Date: Fri, 23 Aug 2024 03:42:27 +0800 Subject: [PATCH] feat(lsp): completion opts support custom item conversion (#30060) Problem: Some items of completion results include function signatures that can cause the pum to be very long when a function has many params, because pum scales with the longest word/abbr. Solution: add custom covert function that can customise abbr to remove params. --- runtime/doc/lsp.txt | 3 +++ runtime/doc/news.txt | 4 +++- runtime/lua/vim/lsp/completion.lua | 16 ++++++++++---- .../functional/plugin/lsp/completion_spec.lua | 21 ++++++++++++++++++- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 32d414e9a7..05734c3ac1 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1630,6 +1630,9 @@ Lua module: vim.lsp.completion *lsp-completion* Fields: ~ • {autotrigger}? (`boolean`) Whether to trigger completion automatically. Default: false + • {convert}? (`fun(item: lsp.CompletionItem): table`) An optional + function used to customize the transformation of an + LSP CompletionItem to |complete-items|. *vim.lsp.completion.enable()* diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 7c842f42dd..1d1e87fd0b 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -65,7 +65,9 @@ EVENTS LSP -• TODO +• Add convert field in |vim.lsp.completion.BufferOpts| of + |vim.lsp.completion.enable()| an optional function used to customize the + transformation of an Lsp CompletionItem to |complete-items|. LUA diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 022edf5fab..89d9a0e9b1 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -23,6 +23,7 @@ local ns_to_ms = 0.000001 --- @class vim.lsp.completion.BufHandle --- @field clients table --- @field triggers table +--- @field convert? fun(item: lsp.CompletionItem): table --- @type table local buf_handles = {} @@ -250,6 +251,8 @@ function M._lsp_to_complete_items(result, prefix, client_id) end local candidates = {} + local bufnr = api.nvim_get_current_buf() + local user_convert = vim.tbl_get(buf_handles, bufnr, 'convert') for _, item in ipairs(items) do if matches(item) then local word = get_completion_word(item) @@ -260,7 +263,7 @@ function M._lsp_to_complete_items(result, prefix, client_id) then hl_group = 'DiagnosticDeprecated' end - table.insert(candidates, { + local completion_item = { word = word, abbr = item.label, kind = protocol.CompletionItemKind[item.kind] or 'Unknown', @@ -278,7 +281,11 @@ function M._lsp_to_complete_items(result, prefix, client_id) }, }, }, - }) + } + if user_convert then + completion_item = vim.tbl_extend('keep', user_convert(item), completion_item) + end + table.insert(candidates, completion_item) end end ---@diagnostic disable-next-line: no-unknown @@ -590,14 +597,15 @@ end --- @class vim.lsp.completion.BufferOpts --- @field autotrigger? boolean Whether to trigger completion automatically. Default: false +--- @field convert? fun(item: lsp.CompletionItem): table An optional function used to customize the transformation of an LSP CompletionItem to |complete-items|. ---- @param client_id integer +---@param client_id integer ---@param bufnr integer ---@param opts vim.lsp.completion.BufferOpts local function enable_completions(client_id, bufnr, opts) local buf_handle = buf_handles[bufnr] if not buf_handle then - buf_handle = { clients = {}, triggers = {} } + buf_handle = { clients = {}, triggers = {}, convert = opts.convert } buf_handles[bufnr] = buf_handle -- Attach to buffer events. diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index aad7e350ee..766dd16541 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -495,7 +495,9 @@ describe('vim.lsp.completion: protocol', function() bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) return vim.lsp.start({ name = 'dummy', cmd = server.cmd, on_attach = function(client, bufnr) - vim.lsp.completion.enable(true, client.id, bufnr) + vim.lsp.completion.enable(true, client.id, bufnr, { convert = function(item) + return { abbr = item.label:gsub('%b()', '')} + end}) end}) ]], completion_result @@ -700,4 +702,21 @@ describe('vim.lsp.completion: protocol', function() eq(true, exec_lua('return _G.called')) end) end) + + it('custom word/abbar format', function() + create_server({ + isIncomplete = false, + items = { + { + label = 'foo(bar)', + }, + }, + }) + + feed('ifo') + trigger_at_pos({ 1, 1 }) + assert_matches(function(matches) + eq('foo', matches[1].abbr) + end) + end) end)