From ad4e14c201c2f400e721362d8581f524fdad9038 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 24 Oct 2024 09:55:23 +0100 Subject: refactor(lsp.buf): use alias for vim.lsp --- runtime/lua/vim/lsp/buf.lua | 53 +++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index fc41246588..0bb7904ca1 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -1,4 +1,5 @@ local api = vim.api +local lsp = vim.lsp local validate = vim.validate local util = require('vim.lsp.util') local npcall = vim.F.npcall @@ -23,7 +24,7 @@ local M = {} local function request(method, params, handler) validate('method', method, 'string') validate('handler', handler, 'function', true) - return vim.lsp.buf_request(0, method, params, handler) + return lsp.buf_request(0, method, params, handler) end --- Displays hover information about the symbol under the cursor in a floating @@ -35,15 +36,15 @@ end --- You can scroll the contents the same as you would any other buffer. function M.hover() local params = util.make_position_params() - request(ms.textDocument_hover, params) + lsp.buf_request(0, ms.textDocument_hover, params) end local function request_with_opts(name, params, opts) local req_handler --- @type function? if opts then req_handler = function(err, result, ctx, config) - local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) - local handler = client.handlers[name] or vim.lsp.handlers[name] + local client = assert(lsp.get_client_by_id(ctx.client_id)) + local handler = client.handlers[name] or lsp.handlers[name] handler(err, result, ctx, vim.tbl_extend('force', config or {}, opts)) end end @@ -55,9 +56,9 @@ end local function get_locations(method, opts) opts = opts or {} local bufnr = api.nvim_get_current_buf() - local clients = vim.lsp.get_clients({ method = method, bufnr = bufnr }) + local clients = lsp.get_clients({ method = method, bufnr = bufnr }) if not next(clients) then - vim.notify(vim.lsp._unsupported_method(method), vim.log.levels.WARN) + vim.notify(lsp._unsupported_method(method), vim.log.levels.WARN) return end local win = api.nvim_get_current_win() @@ -307,7 +308,7 @@ function M.format(opts) method = ms.textDocument_formatting end - local clients = vim.lsp.get_clients({ + local clients = lsp.get_clients({ id = opts.id, bufnr = bufnr, name = opts.name, @@ -344,7 +345,7 @@ function M.format(opts) end local params = set_range(client, util.make_formatting_params(opts.formatting_options)) client.request(method, params, function(...) - local handler = client.handlers[method] or vim.lsp.handlers[method] + local handler = client.handlers[method] or lsp.handlers[method] handler(...) do_format(next(clients, idx)) end, bufnr) @@ -386,7 +387,7 @@ end function M.rename(new_name, opts) opts = opts or {} local bufnr = opts.bufnr or api.nvim_get_current_buf() - local clients = vim.lsp.get_clients({ + local clients = lsp.get_clients({ bufnr = bufnr, name = opts.name, -- Clients must at least support rename, prepareRename is optional @@ -428,7 +429,7 @@ function M.rename(new_name, opts) local params = util.make_position_params(win, client.offset_encoding) params.newName = name local handler = client.handlers[ms.textDocument_rename] - or vim.lsp.handlers[ms.textDocument_rename] + or lsp.handlers[ms.textDocument_rename] client.request(ms.textDocument_rename, params, function(...) handler(...) try_use_client(next(clients, idx)) @@ -508,7 +509,7 @@ end function M.references(context, opts) validate('context', context, 'table', true) local bufnr = api.nvim_get_current_buf() - local clients = vim.lsp.get_clients({ method = ms.textDocument_references, bufnr = bufnr }) + local clients = lsp.get_clients({ method = ms.textDocument_references, bufnr = bufnr }) if not next(clients) then return end @@ -575,7 +576,7 @@ end --- @param handler? lsp.Handler --- @param bufnr? integer local function request_with_id(client_id, method, params, handler, bufnr) - local client = vim.lsp.get_client_by_id(client_id) + local client = lsp.get_client_by_id(client_id) if not client then vim.notify( string.format('Client with id=%d disappeared during call hierarchy request', client_id), @@ -654,9 +655,9 @@ end function M.typehierarchy(kind) local method = kind == 'subtypes' and ms.typeHierarchy_subtypes or ms.typeHierarchy_supertypes local bufnr = api.nvim_get_current_buf() - local clients = vim.lsp.get_clients({ bufnr = bufnr, method = method }) + local clients = lsp.get_clients({ bufnr = bufnr, method = method }) if not next(clients) then - vim.notify(vim.lsp._unsupported_method(method), vim.log.levels.WARN) + vim.notify(lsp._unsupported_method(method), vim.log.levels.WARN) return end @@ -713,7 +714,7 @@ end --- function M.list_workspace_folders() local workspace_folders = {} - for _, client in pairs(vim.lsp.get_clients({ bufnr = 0 })) do + for _, client in pairs(lsp.get_clients({ bufnr = 0 })) do for _, folder in pairs(client.workspace_folders or {}) do table.insert(workspace_folders, folder.name) end @@ -736,7 +737,7 @@ function M.add_workspace_folder(workspace_folder) return end local bufnr = api.nvim_get_current_buf() - for _, client in pairs(vim.lsp.get_clients({ bufnr = bufnr })) do + for _, client in pairs(lsp.get_clients({ bufnr = bufnr })) do client:_add_workspace_folder(workspace_folder) end end @@ -753,7 +754,7 @@ function M.remove_workspace_folder(workspace_folder) return end local bufnr = api.nvim_get_current_buf() - for _, client in pairs(vim.lsp.get_clients({ bufnr = bufnr })) do + for _, client in pairs(lsp.get_clients({ bufnr = bufnr })) do client:_remove_workspace_folder(workspace_folder) end print(workspace_folder, 'is not currently part of the workspace') @@ -916,7 +917,7 @@ local function on_code_action_results(results, opts) -- command: string -- arguments?: any[] -- - local client = assert(vim.lsp.get_client_by_id(choice.ctx.client_id)) + local client = assert(lsp.get_client_by_id(choice.ctx.client_id)) local action = choice.action local bufnr = assert(choice.ctx.bufnr, 'Must have buffer number') @@ -951,14 +952,14 @@ local function on_code_action_results(results, opts) ---@param item {action: lsp.Command|lsp.CodeAction, ctx: lsp.HandlerContext} local function format_item(item) - local clients = vim.lsp.get_clients({ bufnr = item.ctx.bufnr }) + local clients = lsp.get_clients({ bufnr = item.ctx.bufnr }) local title = item.action.title:gsub('\r\n', '\\r\\n'):gsub('\n', '\\n') if #clients == 1 then return title end - local source = vim.lsp.get_client_by_id(item.ctx.client_id).name + local source = lsp.get_client_by_id(item.ctx.client_id).name return ('%s [%s]'):format(title, source) end @@ -987,16 +988,16 @@ function M.code_action(opts) end local context = opts.context and vim.deepcopy(opts.context) or {} if not context.triggerKind then - context.triggerKind = vim.lsp.protocol.CodeActionTriggerKind.Invoked + context.triggerKind = lsp.protocol.CodeActionTriggerKind.Invoked end local mode = api.nvim_get_mode().mode local bufnr = api.nvim_get_current_buf() local win = api.nvim_get_current_win() - local clients = vim.lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_codeAction }) + local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_codeAction }) local remaining = #clients if remaining == 0 then - if next(vim.lsp.get_clients({ bufnr = bufnr })) then - vim.notify(vim.lsp._unsupported_method(ms.textDocument_codeAction), vim.log.levels.WARN) + if next(lsp.get_clients({ bufnr = bufnr })) then + vim.notify(lsp._unsupported_method(ms.textDocument_codeAction), vim.log.levels.WARN) end return end @@ -1033,8 +1034,8 @@ function M.code_action(opts) if context.diagnostics then params.context = context else - local ns_push = vim.lsp.diagnostic.get_namespace(client.id, false) - local ns_pull = vim.lsp.diagnostic.get_namespace(client.id, true) + local ns_push = lsp.diagnostic.get_namespace(client.id, false) + local ns_pull = lsp.diagnostic.get_namespace(client.id, true) local diagnostics = {} local lnum = api.nvim_win_get_cursor(0)[1] - 1 vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_pull, lnum = lnum })) -- cgit From 2ee39b7eb46f091bf22dd1ba3066afff51139bdd Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 24 Oct 2024 09:58:22 +0100 Subject: refactor(lsp.buf): remove buf_request wrapper --- runtime/lua/vim/lsp/buf.lua | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 0bb7904ca1..4a48172ab1 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -7,26 +7,6 @@ local ms = require('vim.lsp.protocol').Methods local M = {} ---- Sends an async request to all active clients attached to the current ---- buffer. ---- ----@param method (string) LSP method name ----@param params (table|nil) Parameters to send to the server ----@param handler lsp.Handler? See |lsp-handler|. Follows |lsp-handler-resolution| ---- ----@return table client_request_ids Map of client-id:request-id pairs ----for all successful requests. ----@return function _cancel_all_requests Function which can be used to ----cancel all the requests. You could instead ----iterate all clients and call their `cancel_request()` methods. ---- ----@see |vim.lsp.buf_request()| -local function request(method, params, handler) - validate('method', method, 'string') - validate('handler', handler, 'function', true) - return lsp.buf_request(0, method, params, handler) -end - --- Displays hover information about the symbol under the cursor in a floating --- window. The window will be dismissed on cursor move. --- Calling the function twice will jump into the floating window @@ -48,7 +28,7 @@ local function request_with_opts(name, params, opts) handler(err, result, ctx, vim.tbl_extend('force', config or {}, opts)) end end - request(name, params, req_handler) + lsp.buf_request(0, name, params, req_handler) end ---@param method string @@ -187,7 +167,7 @@ end --- floating window. function M.signature_help() local params = util.make_position_params() - request(ms.textDocument_signatureHelp, params) + lsp.buf_request(0, ms.textDocument_signatureHelp, params) end --- Retrieves the completion items at the current cursor position. Can only be @@ -201,7 +181,7 @@ end function M.completion(context) local params = util.make_position_params() params.context = context - return request(ms.textDocument_completion, params) + return lsp.buf_request(0, ms.textDocument_completion, params) end ---@param bufnr integer @@ -609,7 +589,7 @@ end local function call_hierarchy(method) local params = util.make_position_params() --- @param result lsp.CallHierarchyItem[]? - request(ms.textDocument_prepareCallHierarchy, params, function(err, result, ctx) + lsp.buf_request(0, ms.textDocument_prepareCallHierarchy, params, function(err, result, ctx) if err then vim.notify(err.message, vim.log.levels.WARN) return @@ -794,7 +774,7 @@ end --- |hl-LspReferenceWrite| function M.document_highlight() local params = util.make_position_params() - request(ms.textDocument_documentHighlight, params) + lsp.buf_request(0, ms.textDocument_documentHighlight, params) end --- Removes document highlights from current buffer. @@ -1063,7 +1043,7 @@ function M.execute_command(command_params) arguments = command_params.arguments, workDoneToken = command_params.workDoneToken, } - request(ms.workspace_executeCommand, command_params) + lsp.buf_request(0, ms.workspace_executeCommand, command_params) end return M -- cgit From 3275ae830da97ef907ff3cfb0170706b6a430f57 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 24 Oct 2024 10:31:34 +0100 Subject: fix(lsp.protocal): improve typing of constants --- runtime/lua/vim/lsp/protocol.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 1699fff0c1..b299a8438f 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -12,6 +12,8 @@ end local sysname = vim.uv.os_uname().sysname +--- @class vim.lsp.protocol.constants +--- @nodoc local constants = { --- @enum lsp.DiagnosticSeverity DiagnosticSeverity = { @@ -314,7 +316,9 @@ local constants = { }, } --- Protocol for the Microsoft Language Server Protocol (mslsp) +--- Protocol for the Microsoft Language Server Protocol (mslsp) +--- @class vim.lsp.protocol : vim.lsp.protocol.constants +--- @nodoc local protocol = {} --- @diagnostic disable:no-unknown -- cgit From 2dcbfe78fcec5f73ce061bb24b718187b9c6b134 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 24 Oct 2024 10:18:36 +0100 Subject: fix(lsp.buf): use correct offset_encoding for all requests Problem: `lsp.buf_request` send the same params to all servers and many calls to this pass PositionalParams which depends on the clients offset_encoding. This can result with incorrect params being sent to a server. Solution: `lsp.buf_request` `params` argument can now be passed as a function which takes the client as the first argument. This is used in lsp/buf.lua to construct correct params for each client request. --- runtime/lua/vim/lsp.lua | 5 ++-- runtime/lua/vim/lsp/buf.lua | 68 ++++++++++++++++++++++++++++----------------- 2 files changed, 46 insertions(+), 27 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 76658b7012..4f13ad5721 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -854,7 +854,7 @@ api.nvim_create_autocmd('VimLeavePre', { --- ---@param bufnr (integer) Buffer handle, or 0 for current. ---@param method (string) LSP method name ----@param params table|nil Parameters to send to the server +---@param params? table|(fun(client: vim.lsp.Client, bufnr: integer): table?) Parameters to send to the server ---@param handler? lsp.Handler See |lsp-handler| --- If nil, follows resolution strategy defined in |lsp-handler-configuration| ---@param on_unsupported? fun() @@ -879,7 +879,8 @@ function lsp.buf_request(bufnr, method, params, handler, on_unsupported) if client.supports_method(method, { bufnr = bufnr }) then method_supported = true - local request_success, request_id = client.request(method, params, handler, bufnr) + local cparams = type(params) == 'function' and params(client, bufnr) or params --[[@as table?]] + local request_success, request_id = client.request(method, cparams, handler, bufnr) -- This could only fail if the client shut down in the time since we looked -- it up and we did the request, which should be rare. if request_success then diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 4a48172ab1..80ba3c648f 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -7,6 +7,19 @@ local ms = require('vim.lsp.protocol').Methods local M = {} +--- @param params? table +--- @return fun(client: vim.lsp.Client): lsp.TextDocumentPositionParams +local function client_positional_params(params) + local win = api.nvim_get_current_win() + return function(client) + local ret = util.make_position_params(win, client.offset_encoding) + if params then + ret = vim.tbl_extend('force', ret, params) + end + return ret + end +end + --- Displays hover information about the symbol under the cursor in a floating --- window. The window will be dismissed on cursor move. --- Calling the function twice will jump into the floating window @@ -15,8 +28,7 @@ local M = {} --- except that "q" dismisses the window. --- You can scroll the contents the same as you would any other buffer. function M.hover() - local params = util.make_position_params() - lsp.buf_request(0, ms.textDocument_hover, params) + lsp.buf_request(0, ms.textDocument_hover, client_positional_params()) end local function request_with_opts(name, params, opts) @@ -166,8 +178,7 @@ end --- Displays signature information about the symbol under the cursor in a --- floating window. function M.signature_help() - local params = util.make_position_params() - lsp.buf_request(0, ms.textDocument_signatureHelp, params) + lsp.buf_request(0, ms.textDocument_signatureHelp, client_positional_params()) end --- Retrieves the completion items at the current cursor position. Can only be @@ -179,9 +190,13 @@ end --- ---@see vim.lsp.protocol.CompletionTriggerKind function M.completion(context) - local params = util.make_position_params() - params.context = context - return lsp.buf_request(0, ms.textDocument_completion, params) + return lsp.buf_request( + 0, + ms.textDocument_completion, + client_positional_params({ + context = context, + }) + ) end ---@param bufnr integer @@ -587,23 +602,27 @@ end --- @param method string local function call_hierarchy(method) - local params = util.make_position_params() - --- @param result lsp.CallHierarchyItem[]? - lsp.buf_request(0, ms.textDocument_prepareCallHierarchy, params, function(err, result, ctx) - if err then - vim.notify(err.message, vim.log.levels.WARN) - return - end - if not result or vim.tbl_isempty(result) then - vim.notify('No item resolved', vim.log.levels.WARN) - return - end - local item = pick_call_hierarchy_item(result) - if not item then - return + lsp.buf_request( + 0, + ms.textDocument_prepareCallHierarchy, + client_positional_params(), + --- @param result lsp.CallHierarchyItem[]? + function(err, result, ctx) + if err then + vim.notify(err.message, vim.log.levels.WARN) + return + end + if not result or vim.tbl_isempty(result) then + vim.notify('No item resolved', vim.log.levels.WARN) + return + end + local item = pick_call_hierarchy_item(result) + if not item then + return + end + request_with_id(ctx.client_id, method, { item = item }, nil, ctx.bufnr) end - request_with_id(ctx.client_id, method, { item = item }, nil, ctx.bufnr) - end) + ) end --- Lists all the call sites of the symbol under the cursor in the @@ -773,8 +792,7 @@ end --- |hl-LspReferenceRead| --- |hl-LspReferenceWrite| function M.document_highlight() - local params = util.make_position_params() - lsp.buf_request(0, ms.textDocument_documentHighlight, params) + lsp.buf_request(0, ms.textDocument_documentHighlight, client_positional_params()) end --- Removes document highlights from current buffer. -- cgit