commit d7e0d46ffa8f9f1eaf27f8b7ee32ef9a21cb9b84
parent 34b4df774d4fb5653422d6a1c1e730ef8565a315
Author: Lewis Russell <lewis6991@gmail.com>
Date: Thu, 17 Apr 2025 10:21:41 +0100
feat(lsp): use stricter types for methods
This change modifies gen_lsp.lua so alias types are generated for
various types of lsp methods to distinguish between notifications
and requests:
- vim.lsp.protocol.Method.ServerToClient.Request
- vim.lsp.protocol.Method.ServerToClient.Notification
- vim.lsp.protocol.Method.ClientToServer.Request
- vim.lsp.protocol.Method.ClientToServer.Notification
These types are then used instead of `string` where appropriate.
Diffstat:
8 files changed, 103 insertions(+), 103 deletions(-)
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
@@ -1285,7 +1285,7 @@ end
---@since 7
---
---@param bufnr integer Buffer handle, or 0 for current.
----@param method string LSP method name
+---@param method vim.lsp.protocol.Method.ClientToServer.Request LSP method name
---@param params? table|(fun(client: vim.lsp.Client, bufnr: integer): table?) Parameters to send to the server.
--- Can also be passed as a function that returns the params table for cases where
--- parameters are specific to the client.
diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua
@@ -1,11 +1,11 @@
--[[
-THIS FILE IS GENERATED by scripts/gen_lsp.lua
+THIS FILE IS GENERATED by scr/gen/gen_lsp.lua
DO NOT EDIT MANUALLY
Based on LSP protocol 3.18
Regenerate:
-nvim -l scripts/gen_lsp.lua gen --version 3.18
+nvim -l scr/gen/gen_lsp.lua gen --version 3.18
--]]
---@meta
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
@@ -158,7 +158,7 @@ local function request_with_opts(name, params, opts)
lsp.buf_request(0, name, params, req_handler)
end
----@param method string
+---@param method vim.lsp.protocol.Method.ClientToServer.Request
---@param opts? vim.lsp.LocationOpts
local function get_locations(method, opts)
opts = opts or {}
@@ -814,7 +814,7 @@ function M.document_symbol(opts)
end
--- @param client_id integer
---- @param method string
+--- @param method vim.lsp.protocol.Method.ClientToServer.Request
--- @param params table
--- @param handler? lsp.Handler
--- @param bufnr? integer
@@ -845,7 +845,7 @@ local hierarchy_methods = {
[ms.callHierarchy_outgoingCalls] = 'call',
}
---- @param method string
+--- @param method vim.lsp.protocol.Method.ClientToServer.Request
local function hierarchy(method)
local kind = hierarchy_methods[method]
if not kind then
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
@@ -656,7 +656,7 @@ end
--- This is a thin wrapper around {client.rpc.request} with some additional
--- checks for capabilities and handler availability.
---
---- @param method string LSP method name.
+--- @param method vim.lsp.protocol.Method.ClientToServer.Request LSP method name.
--- @param params? table LSP request params.
--- @param handler? lsp.Handler Response |lsp-handler| for this method.
--- @param bufnr? integer (default: 0) Buffer handle, or 0 for current.
@@ -721,7 +721,7 @@ end
---
--- This is a wrapper around |Client:request()|
---
---- @param method string LSP method name.
+--- @param method vim.lsp.protocol.Method.ClientToServer.Request LSP method name.
--- @param params table LSP request params.
--- @param timeout_ms integer? Maximum time in milliseconds to wait for
--- a result. Defaults to 1000
@@ -757,7 +757,7 @@ end
--- Sends a notification to an LSP server.
---
---- @param method string LSP method name.
+--- @param method vim.lsp.protocol.Method.ClientToServer.Notification LSP method name.
--- @param params table? LSP request params.
--- @return boolean status indicating if the notification was successful.
--- If it is false, then the client has shutdown.
@@ -828,7 +828,7 @@ function Client:stop(force)
end
--- Get options for a method that is registered dynamically.
---- @param method string
+--- @param method vim.lsp.protocol.Method
function Client:_supports_registration(method)
local capability = vim.tbl_get(self.capabilities, unpack(vim.split(method, '/')))
return type(capability) == 'table' and capability.dynamicRegistration
@@ -901,7 +901,7 @@ function Client:_get_language_id(bufnr)
return self.get_language_id(bufnr, vim.bo[bufnr].filetype)
end
---- @param method string
+--- @param method vim.lsp.protocol.Method
--- @param bufnr? integer
--- @return lsp.Registration?
function Client:_get_registration(method, bufnr)
@@ -1051,7 +1051,7 @@ end
--- Always returns true for unknown off-spec methods.
---
--- Note: Some language server capabilities can be file specific.
---- @param method string
+--- @param method vim.lsp.protocol.Method.ClientToServer
--- @param bufnr? integer
function Client:supports_method(method, bufnr)
-- Deprecated form
@@ -1082,27 +1082,11 @@ function Client:supports_method(method, bufnr)
return false
end
---- Get options for a method that is registered dynamically.
---- @param method string
---- @param bufnr? integer
---- @return lsp.LSPAny?
-function Client:_get_registration_options(method, bufnr)
- if not self:_supports_registration(method) then
- return
- end
-
- local reg = self:_get_registration(method, bufnr)
-
- if reg then
- return reg.registerOptions
- end
-end
-
--- @private
--- Handles a notification sent by an LSP server by invoking the
--- corresponding handler.
---
---- @param method string LSP method name
+--- @param method vim.lsp.protocol.Method.ServerToClient.Notification LSP method name
--- @param params table The parameters for that method.
function Client:_notification(method, params)
log.trace('notification', method, params)
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
@@ -621,22 +621,15 @@ function protocol.resolve_capabilities(server_capabilities)
end
-- Generated by gen_lsp.lua, keep at end of file.
---- @alias vim.lsp.protocol.Method.ClientToServer
+--- @alias vim.lsp.protocol.Method.ClientToServer.Request
--- | 'callHierarchy/incomingCalls',
--- | 'callHierarchy/outgoingCalls',
--- | 'codeAction/resolve',
--- | 'codeLens/resolve',
--- | 'completionItem/resolve',
--- | 'documentLink/resolve',
---- | '$/setTrace',
---- | 'exit',
--- | 'initialize',
---- | 'initialized',
--- | 'inlayHint/resolve',
---- | 'notebookDocument/didChange',
---- | 'notebookDocument/didClose',
---- | 'notebookDocument/didOpen',
---- | 'notebookDocument/didSave',
--- | 'shutdown',
--- | 'textDocument/codeAction',
--- | 'textDocument/codeLens',
@@ -645,10 +638,6 @@ end
--- | 'textDocument/declaration',
--- | 'textDocument/definition',
--- | 'textDocument/diagnostic',
---- | 'textDocument/didChange',
---- | 'textDocument/didClose',
---- | 'textDocument/didOpen',
---- | 'textDocument/didSave',
--- | 'textDocument/documentColor',
--- | 'textDocument/documentHighlight',
--- | 'textDocument/documentLink',
@@ -676,19 +665,11 @@ end
--- | 'textDocument/semanticTokens/range',
--- | 'textDocument/signatureHelp',
--- | 'textDocument/typeDefinition',
---- | 'textDocument/willSave',
--- | 'textDocument/willSaveWaitUntil',
--- | 'typeHierarchy/subtypes',
--- | 'typeHierarchy/supertypes',
---- | 'window/workDoneProgress/cancel',
--- | 'workspaceSymbol/resolve',
--- | 'workspace/diagnostic',
---- | 'workspace/didChangeConfiguration',
---- | 'workspace/didChangeWatchedFiles',
---- | 'workspace/didChangeWorkspaceFolders',
---- | 'workspace/didCreateFiles',
---- | 'workspace/didDeleteFiles',
---- | 'workspace/didRenameFiles',
--- | 'workspace/executeCommand',
--- | 'workspace/symbol',
--- | 'workspace/textDocumentContent',
@@ -696,15 +677,35 @@ end
--- | 'workspace/willDeleteFiles',
--- | 'workspace/willRenameFiles',
---- @alias vim.lsp.protocol.Method.ServerToClient
+--- @alias vim.lsp.protocol.Method.ClientToServer.Notification
+--- | '$/setTrace',
+--- | 'exit',
+--- | 'initialized',
+--- | 'notebookDocument/didChange',
+--- | 'notebookDocument/didClose',
+--- | 'notebookDocument/didOpen',
+--- | 'notebookDocument/didSave',
+--- | 'textDocument/didChange',
+--- | 'textDocument/didClose',
+--- | 'textDocument/didOpen',
+--- | 'textDocument/didSave',
+--- | 'textDocument/willSave',
+--- | 'window/workDoneProgress/cancel',
+--- | 'workspace/didChangeConfiguration',
+--- | 'workspace/didChangeWatchedFiles',
+--- | 'workspace/didChangeWorkspaceFolders',
+--- | 'workspace/didCreateFiles',
+--- | 'workspace/didDeleteFiles',
+--- | 'workspace/didRenameFiles',
+
+--- @alias vim.lsp.protocol.Method.ClientToServer
+--- | vim.lsp.protocol.Method.ClientToServer.Request
+--- | vim.lsp.protocol.Method.ClientToServer.Notification
+
+--- @alias vim.lsp.protocol.Method.ServerToClient.Request
--- | 'client/registerCapability',
--- | 'client/unregisterCapability',
---- | '$/logTrace',
---- | 'telemetry/event',
---- | 'textDocument/publishDiagnostics',
---- | 'window/logMessage',
--- | 'window/showDocument',
---- | 'window/showMessage',
--- | 'window/showMessageRequest',
--- | 'window/workDoneProgress/create',
--- | 'workspace/applyEdit',
@@ -718,6 +719,17 @@ end
--- | 'workspace/textDocumentContent/refresh',
--- | 'workspace/workspaceFolders',
+--- @alias vim.lsp.protocol.Method.ServerToClient.Notification
+--- | '$/logTrace',
+--- | 'telemetry/event',
+--- | 'textDocument/publishDiagnostics',
+--- | 'window/logMessage',
+--- | 'window/showMessage',
+
+--- @alias vim.lsp.protocol.Method.ServerToClient
+--- | vim.lsp.protocol.Method.ServerToClient.Request
+--- | vim.lsp.protocol.Method.ServerToClient.Notification
+
--- @alias vim.lsp.protocol.Method
--- | vim.lsp.protocol.Method.ClientToServer
--- | vim.lsp.protocol.Method.ServerToClient
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
@@ -2164,7 +2164,7 @@ end
---@class (private) vim.lsp.util._cancel_requests.Filter
---@field bufnr? integer
---@field clients? vim.lsp.Client[]
----@field method? string
+---@field method? vim.lsp.protocol.Method.ClientToServer.Request
---@field type? string
---@private
diff --git a/src/gen/gen_lsp.lua b/src/gen/gen_lsp.lua
@@ -33,6 +33,24 @@ end
--- @field enumerations vim._gen_lsp.Enumeration[]
--- @field typeAliases vim._gen_lsp.TypeAlias[]
+--- @class vim._gen_lsp.Notification
+--- @field deprecated? string
+--- @field documentation? string
+--- @field messageDirection string
+--- @field clientCapability? string
+--- @field serverCapability? string
+--- @field method string
+--- @field params? any
+--- @field proposed? boolean
+--- @field registrationMethod? string
+--- @field registrationOptions? any
+--- @field since? string
+
+--- @class vim._gen_lsp.Request : vim._gen_lsp.Notification
+--- @field errorData? any
+--- @field partialResult? any
+--- @field result any
+
---@param opt vim._gen_lsp.opt
---@return vim._gen_lsp.Protocol
local function read_json(opt)
@@ -66,64 +84,47 @@ local function write_to_protocol(protocol, gen_methods, gen_capabilities)
local indent = (' '):rep(2)
- --- @class vim._gen_lsp.Request
- --- @field deprecated? string
- --- @field documentation? string
- --- @field messageDirection string
- --- @field clientCapability? string
- --- @field serverCapability? string
- --- @field method string
- --- @field params? any
- --- @field proposed? boolean
- --- @field registrationMethod? string
- --- @field registrationOptions? any
- --- @field since? string
-
- --- @class vim._gen_lsp.Notification
- --- @field deprecated? string
- --- @field documentation? string
- --- @field errorData? any
- --- @field messageDirection string
- --- @field clientCapability? string
- --- @field serverCapability? string
- --- @field method string
- --- @field params? any[]
- --- @field partialResult? any
- --- @field proposed? boolean
- --- @field registrationMethod? string
- --- @field registrationOptions? any
- --- @field result any
- --- @field since? string
+ local function compare_method(a, b)
+ return to_luaname(a.method) < to_luaname(b.method)
+ end
---@type (vim._gen_lsp.Request|vim._gen_lsp.Notification)[]
- local all = vim.list_extend(protocol.requests, protocol.notifications)
- table.sort(all, function(a, b)
- return to_luaname(a.method) < to_luaname(b.method)
- end)
+ local all = {}
+ vim.list_extend(all, protocol.notifications)
+ vim.list_extend(all, protocol.requests)
+
+ table.sort(all, compare_method)
+ table.sort(protocol.requests, compare_method)
+ table.sort(protocol.notifications, compare_method)
local output = { '-- Generated by gen_lsp.lua, keep at end of file.' }
if gen_methods then
- output[#output + 1] = '--- @alias vim.lsp.protocol.Method.ClientToServer'
-
- for _, item in ipairs(all) do
- if item.method and item.messageDirection == 'clientToServer' then
- output[#output + 1] = ("--- | '%s',"):format(item.method)
+ for _, dir in ipairs({ 'clientToServer', 'serverToClient' }) do
+ local dir1 = dir:sub(1, 1):upper() .. dir:sub(2)
+ local alias = ('vim.lsp.protocol.Method.%s'):format(dir1)
+ for _, b in ipairs({
+ { title = 'Request', methods = protocol.requests },
+ { title = 'Notification', methods = protocol.notifications },
+ }) do
+ output[#output + 1] = ('--- @alias %s.%s'):format(alias, b.title)
+ for _, item in ipairs(b.methods) do
+ if item.messageDirection == dir then
+ output[#output + 1] = ("--- | '%s',"):format(item.method)
+ end
+ end
+ output[#output + 1] = ''
end
- end
- vim.list_extend(output, {
- '',
- '--- @alias vim.lsp.protocol.Method.ServerToClient',
- })
- for _, item in ipairs(all) do
- if item.method and item.messageDirection == 'serverToClient' then
- output[#output + 1] = ("--- | '%s',"):format(item.method)
- end
+ vim.list_extend(output, {
+ ('--- @alias %s'):format(alias),
+ ('--- | %s.Request'):format(alias),
+ ('--- | %s.Notification'):format(alias),
+ '',
+ })
end
vim.list_extend(output, {
- '',
'--- @alias vim.lsp.protocol.Method',
'--- | vim.lsp.protocol.Method.ClientToServer',
'--- | vim.lsp.protocol.Method.ServerToClient',
diff --git a/src/gen/gen_vimdoc.lua b/src/gen/gen_vimdoc.lua
@@ -427,6 +427,9 @@ end
--- @param generics? table<string,string>
--- @param default? string
local function render_type(ty, generics, default)
+ -- TODO(lewis6991): Document LSP protocol types
+ ty = ty:gsub('vim%.lsp%.protocol%.Method.[%w.]+', 'string')
+
if generics then
ty = replace_generics(ty, generics)
end