diff options
Diffstat (limited to 'runtime/lua/vim/lsp/buf.lua')
-rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 128 |
1 files changed, 74 insertions, 54 deletions
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 747d761730..eb7ec579f1 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -116,31 +116,30 @@ end --- asks the user to select one. -- ---@returns The client that the user selected or nil -local function select_client(method) - local clients = vim.tbl_values(vim.lsp.buf_get_clients()); - clients = vim.tbl_filter(function (client) +local function select_client(method, on_choice) + validate { + on_choice = { on_choice, 'function', false }, + } + local clients = vim.tbl_values(vim.lsp.buf_get_clients()) + clients = vim.tbl_filter(function(client) return client.supports_method(method) end, clients) -- better UX when choices are always in the same order (between restarts) - table.sort(clients, function (a, b) return a.name < b.name end) + table.sort(clients, function(a, b) + return a.name < b.name + end) if #clients > 1 then - local choices = {} - for k,v in pairs(clients) do - table.insert(choices, string.format("%d %s", k, v.name)) - end - local user_choice = vim.fn.confirm( - "Select a language server:", - table.concat(choices, "\n"), - 0, - "Question" - ) - if user_choice == 0 then return nil end - return clients[user_choice] + vim.ui.select(clients, { + prompt = 'Select a language server:', + format_item = function(client) + return client.name + end, + }, on_choice) elseif #clients < 1 then - return nil + on_choice(nil) else - return clients[1] + on_choice(clients[1]) end end @@ -152,11 +151,15 @@ end -- ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting function M.formatting(options) - local client = select_client("textDocument/formatting") - if client == nil then return end - local params = util.make_formatting_params(options) - return client.request("textDocument/formatting", params, nil, vim.api.nvim_get_current_buf()) + local bufnr = vim.api.nvim_get_current_buf() + select_client('textDocument/formatting', function(client) + if client == nil then + return + end + + return client.request('textDocument/formatting', params, nil, bufnr) + end) end --- Performs |vim.lsp.buf.formatting()| synchronously. @@ -165,23 +168,27 @@ end --- saved. {timeout_ms} is passed on to |vim.lsp.buf_request_sync()|. Example: --- --- <pre> ---- vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()]] +--- autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync() --- </pre> --- ---@param options Table with valid `FormattingOptions` entries ---@param timeout_ms (number) Request timeout ---@see |vim.lsp.buf.formatting_seq_sync| function M.formatting_sync(options, timeout_ms) - local client = select_client("textDocument/formatting") - if client == nil then return end - local params = util.make_formatting_params(options) - local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, vim.api.nvim_get_current_buf()) - if result and result.result then - util.apply_text_edits(result.result) - elseif err then - vim.notify("vim.lsp.buf.formatting_sync: " .. err, vim.log.levels.WARN) - end + local bufnr = vim.api.nvim_get_current_buf() + select_client('textDocument/formatting', function(client) + if client == nil then + return + end + + local result, err = client.request_sync('textDocument/formatting', params, timeout_ms, bufnr) + if result and result.result then + util.apply_text_edits(result.result, bufnr, client.offset_encoding) + elseif err then + vim.notify('vim.lsp.buf.formatting_sync: ' .. err, vim.log.levels.WARN) + end + end) end --- Formats the current buffer by sequentially requesting formatting from attached clients. @@ -202,6 +209,7 @@ end ---the remaining clients in the order as they occur in the `order` list. function M.formatting_seq_sync(options, timeout_ms, order) local clients = vim.tbl_values(vim.lsp.buf_get_clients()); + local bufnr = vim.api.nvim_get_current_buf() -- sort the clients according to `order` for _, client_name in pairs(order or {}) do @@ -220,7 +228,7 @@ function M.formatting_seq_sync(options, timeout_ms, order) local params = util.make_formatting_params(options) local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, vim.api.nvim_get_current_buf()) if result and result.result then - util.apply_text_edits(result.result) + util.apply_text_edits(result.result, bufnr, client.offset_encoding) elseif err then vim.notify(string.format("vim.lsp.buf.formatting_seq_sync: (%s) %s", client.name, err), vim.log.levels.WARN) end @@ -236,12 +244,15 @@ end ---@param end_pos ({number, number}, optional) mark-indexed position. ---Defaults to the end of the last visual selection. function M.range_formatting(options, start_pos, end_pos) - local client = select_client("textDocument/rangeFormatting") - if client == nil then return end - local params = util.make_given_range_params(start_pos, end_pos) params.options = util.make_formatting_params(options).options - return client.request("textDocument/rangeFormatting", params) + select_client('textDocument/rangeFormatting', function(client) + if client == nil then + return + end + + return client.request('textDocument/rangeFormatting', params) + end) end --- Renames all references to the symbol under the cursor. @@ -261,6 +272,7 @@ function M.rename(new_name) request('textDocument/rename', params) end + ---@private local function prepare_rename(err, result) if err == nil and result == nil then vim.notify('nothing to rename', vim.log.levels.INFO) @@ -369,7 +381,7 @@ end function M.list_workspace_folders() local workspace_folders = {} for _, client in pairs(vim.lsp.buf_get_clients()) do - for _, folder in pairs(client.workspaceFolders or {}) do + for _, folder in pairs(client.workspace_folders or {}) do table.insert(workspace_folders, folder.name) end end @@ -389,7 +401,7 @@ function M.add_workspace_folder(workspace_folder) local params = util.make_workspace_params({{uri = vim.uri_from_fname(workspace_folder); name = workspace_folder}}, {{}}) for _, client in pairs(vim.lsp.buf_get_clients()) do local found = false - for _, folder in pairs(client.workspaceFolders or {}) do + for _, folder in pairs(client.workspace_folders or {}) do if folder.name == workspace_folder then found = true print(workspace_folder, "is already part of this workspace") @@ -398,10 +410,10 @@ function M.add_workspace_folder(workspace_folder) end if not found then vim.lsp.buf_notify(0, 'workspace/didChangeWorkspaceFolders', params) - if not client.workspaceFolders then - client.workspaceFolders = {} + if not client.workspace_folders then + client.workspace_folders = {} end - table.insert(client.workspaceFolders, params.event.added[1]) + table.insert(client.workspace_folders, params.event.added[1]) end end end @@ -415,10 +427,10 @@ function M.remove_workspace_folder(workspace_folder) if not (workspace_folder and #workspace_folder > 0) then return end local params = util.make_workspace_params({{}}, {{uri = vim.uri_from_fname(workspace_folder); name = workspace_folder}}) for _, client in pairs(vim.lsp.buf_get_clients()) do - for idx, folder in pairs(client.workspaceFolders) do + for idx, folder in pairs(client.workspace_folders) do if folder.name == workspace_folder then vim.lsp.buf_notify(0, 'workspace/didChangeWorkspaceFolders', params) - client.workspaceFolders[idx] = nil + client.workspace_folders[idx] = nil return end end @@ -435,18 +447,21 @@ end ---@param query (string, optional) function M.workspace_symbol(query) query = query or npcall(vfn.input, "Query: ") + if query == nil then + return + end local params = {query = query} request('workspace/symbol', params) end --- Send request to the server to resolve document highlights for the current --- text document position. This request can be triggered by a key mapping or ---- by events such as `CursorHold`, eg: +--- by events such as `CursorHold`, e.g.: --- --- <pre> ---- vim.api.nvim_command [[autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()]] ---- vim.api.nvim_command [[autocmd CursorHoldI <buffer> lua vim.lsp.buf.document_highlight()]] ---- vim.api.nvim_command [[autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()]] +--- autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight() +--- autocmd CursorHoldI <buffer> lua vim.lsp.buf.document_highlight() +--- autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references() --- </pre> --- --- Note: Usage of |vim.lsp.buf.document_highlight()| requires the following highlight groups @@ -491,7 +506,7 @@ local function on_code_action_results(results, ctx) ---@private local function apply_action(action, client) if action.edit then - util.apply_workspace_edit(action.edit) + util.apply_workspace_edit(action.edit, client.offset_encoding) end if action.command then local command = type(action.command) == 'table' and action.command or action @@ -615,14 +630,19 @@ end --- Executes an LSP server command. --- ----@param command A valid `ExecuteCommandParams` object +---@param command_params table A valid `ExecuteCommandParams` object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand -function M.execute_command(command) +function M.execute_command(command_params) validate { - command = { command.command, 's' }, - arguments = { command.arguments, 't', true } + command = { command_params.command, 's' }, + arguments = { command_params.arguments, 't', true } + } + command_params = { + command=command_params.command, + arguments=command_params.arguments, + workDoneToken=command_params.workDoneToken, } - request('workspace/executeCommand', command) + request('workspace/executeCommand', command_params ) end return M |