From 3692fd4c873a2cd7ad69eb09765eed2993570c49 Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Mon, 11 Dec 2023 04:10:00 -0500 Subject: feat(gen_lsp.lua): validate CLI args #26514 - Improve CLI argument parsing, rejects invalid argument and commands as early as possible. Also prints USAGE in the command line. - No longer allows `--`, use `--out ` instead. - Print a little bit of verbose messages to better know what's going on rather than remaining silent at all times. - Add type annotation `gen_lsp._opt` to avoid type warnings. --- runtime/lua/vim/lsp/_meta/protocol.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua index 72b0f00f65..979dad84fd 100644 --- a/runtime/lua/vim/lsp/_meta/protocol.lua +++ b/runtime/lua/vim/lsp/_meta/protocol.lua @@ -1,7 +1,7 @@ --[[ This file is autogenerated from scripts/gen_lsp.lua Regenerate: -nvim -l scripts/gen_lsp.lua gen --version 3.18 --runtime/lua/vim/lsp/_meta/protocol.lua +nvim -l scripts/gen_lsp.lua gen --version 3.18 --out runtime/lua/vim/lsp/_meta/protocol.lua --]] ---@meta -- cgit From 97bea3163a3fe50359e7f6ffda747e28974a818a Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 13 Dec 2023 12:00:11 +0000 Subject: feat(lsp): more annotations --- runtime/lua/vim/lsp/_meta.lua | 3 +- runtime/lua/vim/lsp/buf.lua | 6 +- runtime/lua/vim/lsp/codelens.lua | 14 ++- runtime/lua/vim/lsp/diagnostic.lua | 9 ++ runtime/lua/vim/lsp/handlers.lua | 92 ++++++++------- runtime/lua/vim/lsp/inlay_hint.lua | 28 +++-- runtime/lua/vim/lsp/log.lua | 4 +- runtime/lua/vim/lsp/protocol.lua | 2 +- runtime/lua/vim/lsp/rpc.lua | 192 ++++++++++++++++++-------------- runtime/lua/vim/lsp/semantic_tokens.lua | 58 ++++++---- runtime/lua/vim/lsp/sync.lua | 28 +++-- runtime/lua/vim/lsp/util.lua | 4 +- 12 files changed, 263 insertions(+), 177 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_meta.lua b/runtime/lua/vim/lsp/_meta.lua index acf799264e..559939c236 100644 --- a/runtime/lua/vim/lsp/_meta.lua +++ b/runtime/lua/vim/lsp/_meta.lua @@ -1,13 +1,14 @@ ---@meta error('Cannot require a meta file') ----@alias lsp-handler fun(err: lsp.ResponseError|nil, result: any, context: lsp.HandlerContext, config: table|nil): any? +---@alias lsp.Handler fun(err: lsp.ResponseError?, result: any, context: lsp.HandlerContext, config?: table): ...any ---@class lsp.HandlerContext ---@field method string ---@field client_id integer ---@field bufnr? integer ---@field params? any +---@field version? integer ---@class lsp.ResponseError ---@field code integer diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index cf9acc0808..2f754444e9 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -49,7 +49,7 @@ local function request_with_options(name, params, options) local req_handler if options then req_handler = function(err, result, ctx, config) - local client = vim.lsp.get_client_by_id(ctx.client_id) + local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) local handler = client.handlers[name] or vim.lsp.handlers[name] handler(err, result, ctx, vim.tbl_extend('force', config or {}, options)) end @@ -299,12 +299,12 @@ function M.rename(new_name, options) )[1] end - local try_use_client - try_use_client = function(idx, client) + local function try_use_client(idx, client) if not client then return end + --- @param name string local function rename(name) local params = util.make_position_params(win, client.offset_encoding) params.newName = name diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index 9cccaa1d66..199da288f4 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -6,7 +6,7 @@ local M = {} --- bufnr → true|nil --- to throttle refreshes to at most one at a time -local active_refreshes = {} +local active_refreshes = {} --- @type table ---@type table> --- bufnr -> client_id -> lenses @@ -75,7 +75,7 @@ end function M.run() local line = api.nvim_win_get_cursor(0)[1] local bufnr = api.nvim_get_current_buf() - local options = {} + local options = {} --- @type {client: integer, lens: lsp.CodeLens}[] local lenses_by_client = lens_cache_by_buf[bufnr] or {} for client, lenses in pairs(lenses_by_client) do for _, lens in pairs(lenses) do @@ -230,6 +230,7 @@ local function resolve_lenses(lenses, bufnr, client_id, callback) if lens.command then countdown() else + assert(client) client.request('codeLens/resolve', lens, function(_, result) if api.nvim_buf_is_loaded(bufnr) and result and result.command then lens.command = result.command @@ -257,10 +258,13 @@ end --- |lsp-handler| for the method `textDocument/codeLens` --- +---@param ctx lsp.HandlerContext function M.on_codelens(err, result, ctx, _) if err then - active_refreshes[ctx.bufnr] = nil - local _ = log.error() and log.error('codelens', err) + active_refreshes[assert(ctx.bufnr)] = nil + if log.error() then + log.error('codelens', err) + end return end @@ -270,7 +274,7 @@ function M.on_codelens(err, result, ctx, _) -- once resolved. M.display(result, ctx.bufnr, ctx.client_id) resolve_lenses(result, ctx.bufnr, ctx.client_id, function() - active_refreshes[ctx.bufnr] = nil + active_refreshes[assert(ctx.bufnr)] = nil M.display(result, ctx.bufnr, ctx.client_id) end) end diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index b6f0cfa0b3..cba5b66672 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -37,6 +37,10 @@ local function severity_vim_to_lsp(severity) return severity end +---@param lines string[] +---@param lnum integer +---@param col integer +---@param offset_encoding string ---@return integer local function line_byte_from_position(lines, lnum, col, offset_encoding) if not lines or offset_encoding == 'utf-8' then @@ -52,6 +56,8 @@ local function line_byte_from_position(lines, lnum, col, offset_encoding) return col end +---@param bufnr integer +---@return string[] local function get_buf_lines(bufnr) if vim.api.nvim_buf_is_loaded(bufnr) then return vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) @@ -223,6 +229,7 @@ end --- ) --- ``` --- +---@param ctx lsp.HandlerContext ---@param config table Configuration table (see |vim.diagnostic.config()|). function M.on_publish_diagnostics(_, result, ctx, config) local client_id = ctx.client_id @@ -284,6 +291,7 @@ end --- ) --- ``` --- +---@param ctx lsp.HandlerContext ---@param config table Configuration table (see |vim.diagnostic.config()|). function M.on_diagnostic(_, result, ctx, config) local client_id = ctx.client_id @@ -400,6 +408,7 @@ end local bufstates = {} --- Disable pull diagnostics for a buffer +--- @param bufnr integer --- @private local function disable(bufnr) local bufstate = bufstates[bufnr] diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 6fde55cf04..c03a17fa59 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -4,6 +4,7 @@ local ms = protocol.Methods local util = require('vim.lsp.util') local api = vim.api +--- @type table local M = {} -- FIXME: DOC: Expose in vimdocs @@ -108,8 +109,7 @@ end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability M[ms.client_registerCapability] = function(_, result, ctx) local client_id = ctx.client_id - ---@type lsp.Client - local client = vim.lsp.get_client_by_id(client_id) + local client = assert(vim.lsp.get_client_by_id(client_id)) client.dynamic_capabilities:register(result.registrations) for bufnr, _ in pairs(client.attached_buffers) do @@ -139,7 +139,7 @@ end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_unregisterCapability M[ms.client_unregisterCapability] = function(_, result, ctx) local client_id = ctx.client_id - local client = vim.lsp.get_client_by_id(client_id) + local client = assert(vim.lsp.get_client_by_id(client_id)) client.dynamic_capabilities:unregister(result.unregisterations) for _, unreg in ipairs(result.unregisterations) do @@ -158,7 +158,7 @@ M[ms.workspace_applyEdit] = function(_, workspace_edit, ctx) ) -- TODO(ashkan) Do something more with label? local client_id = ctx.client_id - local client = vim.lsp.get_client_by_id(client_id) + local client = assert(vim.lsp.get_client_by_id(client_id)) if workspace_edit.label then print('Workspace edit', workspace_edit.label) end @@ -231,22 +231,23 @@ end M[ms.textDocument_references] = function(_, result, ctx, config) if not result or vim.tbl_isempty(result) then vim.notify('No references found') - else - local client = vim.lsp.get_client_by_id(ctx.client_id) - config = config or {} - local title = 'References' - local items = util.locations_to_items(result, client.offset_encoding) + return + end - if config.loclist then - vim.fn.setloclist(0, {}, ' ', { title = title, items = items, context = ctx }) - api.nvim_command('lopen') - elseif config.on_list then - assert(type(config.on_list) == 'function', 'on_list is not a function') - config.on_list({ title = title, items = items, context = ctx }) - else - vim.fn.setqflist({}, ' ', { title = title, items = items, context = ctx }) - api.nvim_command('botright copen') - end + local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) + config = config or {} + local title = 'References' + local items = util.locations_to_items(result, client.offset_encoding) + + if config.loclist then + vim.fn.setloclist(0, {}, ' ', { title = title, items = items, context = ctx }) + api.nvim_command('lopen') + elseif config.on_list then + assert(type(config.on_list) == 'function', 'on_list is not a function') + config.on_list({ title = title, items = items, context = ctx }) + else + vim.fn.setqflist({}, ' ', { title = title, items = items, context = ctx }) + api.nvim_command('botright copen') end end @@ -259,26 +260,27 @@ end --- ---@param map_result function `((resp, bufnr) -> list)` to convert the response ---@param entity string name of the resource used in a `not found` error message ----@param title_fn function Function to call to generate list title +---@param title_fn fun(ctx: lsp.HandlerContext): string Function to call to generate list title +---@return lsp.Handler local function response_to_list(map_result, entity, title_fn) return function(_, result, ctx, config) if not result or vim.tbl_isempty(result) then vim.notify('No ' .. entity .. ' found') + return + end + config = config or {} + local title = title_fn(ctx) + local items = map_result(result, ctx.bufnr) + + if config.loclist then + vim.fn.setloclist(0, {}, ' ', { title = title, items = items, context = ctx }) + api.nvim_command('lopen') + elseif config.on_list then + assert(type(config.on_list) == 'function', 'on_list is not a function') + config.on_list({ title = title, items = items, context = ctx }) else - config = config or {} - local title = title_fn(ctx) - local items = map_result(result, ctx.bufnr) - - if config.loclist then - vim.fn.setloclist(0, {}, ' ', { title = title, items = items, context = ctx }) - api.nvim_command('lopen') - elseif config.on_list then - assert(type(config.on_list) == 'function', 'on_list is not a function') - config.on_list({ title = title, items = items, context = ctx }) - else - vim.fn.setqflist({}, ' ', { title = title, items = items, context = ctx }) - api.nvim_command('botright copen') - end + vim.fn.setqflist({}, ' ', { title = title, items = items, context = ctx }) + api.nvim_command('botright copen') end end end @@ -304,7 +306,7 @@ M[ms.textDocument_rename] = function(_, result, ctx, _) vim.notify("Language server couldn't provide rename result", vim.log.levels.INFO) return end - local client = vim.lsp.get_client_by_id(ctx.client_id) + local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) util.apply_workspace_edit(result, client.offset_encoding) end @@ -313,7 +315,7 @@ M[ms.textDocument_rangeFormatting] = function(_, result, ctx, _) if not result then return end - local client = vim.lsp.get_client_by_id(ctx.client_id) + local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) util.apply_text_edits(result, ctx.bufnr, client.offset_encoding) end @@ -322,7 +324,7 @@ M[ms.textDocument_formatting] = function(_, result, ctx, _) if not result then return end - local client = vim.lsp.get_client_by_id(ctx.client_id) + local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) util.apply_text_edits(result, ctx.bufnr, client.offset_encoding) end @@ -331,7 +333,8 @@ M[ms.textDocument_completion] = function(_, result, _, _) if vim.tbl_isempty(result or {}) then return end - local row, col = unpack(api.nvim_win_get_cursor(0)) + local cursor = api.nvim_win_get_cursor(0) + local row, col = cursor[1], cursor[2] local line = assert(api.nvim_buf_get_lines(0, row - 1, row, false)[1]) local line_to_cursor = line:sub(col + 1) local textMatch = vim.fn.match(line_to_cursor, '\\k*$') @@ -354,6 +357,7 @@ end --- ) --- ``` --- +---@param ctx lsp.HandlerContext ---@param config table Configuration table. --- - border: (default=nil) --- - Add borders to the floating window @@ -394,14 +398,16 @@ M[ms.textDocument_hover] = M.hover --- Jumps to a location. Used as a handler for multiple LSP methods. ---@param _ nil not used ---@param result (table) result of LSP method; a location or a list of locations. ----@param ctx (table) table containing the context of the request, including the method +---@param ctx (lsp.HandlerContext) table containing the context of the request, including the method ---(`textDocument/definition` can return `Location` or `Location[]` local function location_handler(_, result, ctx, config) if result == nil or vim.tbl_isempty(result) then - local _ = log.info() and log.info(ctx.method, 'No location found') + if log.info() then + log.info(ctx.method, 'No location found') + end return nil end - local client = vim.lsp.get_client_by_id(ctx.client_id) + local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) config = config or {} @@ -450,7 +456,7 @@ M[ms.textDocument_implementation] = location_handler --- ``` --- ---@param result table Response from the language server ----@param ctx table Client context +---@param ctx lsp.HandlerContext Client context ---@param config table Configuration table. --- - border: (default=nil) --- - Add borders to the floating window @@ -470,7 +476,7 @@ function M.signature_help(_, result, ctx, config) end return end - local client = vim.lsp.get_client_by_id(ctx.client_id) + local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) local triggers = vim.tbl_get(client.server_capabilities, 'signatureHelpProvider', 'triggerCharacters') local ft = vim.bo[ctx.bufnr].filetype diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index 4f7a3b0076..ce1680549e 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -17,13 +17,17 @@ local augroup = api.nvim_create_augroup('vim_lsp_inlayhint', {}) --- |lsp-handler| for the method `textDocument/inlayHint` --- Store hints for a specific buffer and client +---@param result lsp.InlayHint[]? +---@param ctx lsp.HandlerContext ---@private function M.on_inlayhint(err, result, ctx, _) if err then - local _ = log.error() and log.error('inlayhint', err) + if log.error() then + log.error('inlayhint', err) + end return end - local bufnr = ctx.bufnr + local bufnr = assert(ctx.bufnr) if util.buf_versions[bufnr] ~= ctx.version then return end @@ -40,7 +44,7 @@ function M.on_inlayhint(err, result, ctx, _) bufstate.version = ctx.version end local hints_by_client = bufstate.client_hint - local client = vim.lsp.get_client_by_id(client_id) + local client = assert(vim.lsp.get_client_by_id(client_id)) local new_hints_by_lnum = vim.defaulttable() local num_unprocessed = #result @@ -52,6 +56,8 @@ function M.on_inlayhint(err, result, ctx, _) end local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false) + ---@param position lsp.Position + ---@return integer local function pos_to_byte(position) local col = position.character if col > 0 then @@ -78,6 +84,7 @@ function M.on_inlayhint(err, result, ctx, _) end --- |lsp-handler| for the method `textDocument/inlayHint/refresh` +---@param ctx lsp.HandlerContext ---@private function M.on_refresh(err, _, ctx, _) if err then @@ -212,7 +219,7 @@ local function clear(bufnr) end local bufstate = bufstates[bufnr] local client_lens = (bufstate or {}).client_hint or {} - local client_ids = vim.tbl_keys(client_lens) + local client_ids = vim.tbl_keys(client_lens) --- @type integer[] for _, iter_client_id in ipairs(client_ids) do if bufstate then bufstate.client_hint[iter_client_id] = {} @@ -236,7 +243,7 @@ end --- Refresh inlay hints, only if we have attached clients that support it ---@param bufnr (integer) Buffer handle, or 0 for current ----@param opts? table Additional options to pass to util._refresh +---@param opts? lsp.util.RefreshOptions Additional options to pass to util._refresh ---@private local function _refresh(bufnr, opts) opts = opts or {} @@ -312,7 +319,7 @@ api.nvim_set_decoration_provider(namespace, { if bufstate.version ~= util.buf_versions[bufnr] then return end - local hints_by_client = bufstate.client_hint + local hints_by_client = assert(bufstate.client_hint) for lnum = topline, botline do if bufstate.applied[lnum] ~= bufstate.version then @@ -321,14 +328,15 @@ api.nvim_set_decoration_provider(namespace, { local line_hints = hints_by_lnum[lnum] or {} for _, hint in pairs(line_hints) do local text = '' - if type(hint.label) == 'string' then - text = hint.label + local label = hint.label + if type(label) == 'string' then + text = label else - for _, part in ipairs(hint.label) do + for _, part in ipairs(label) do text = text .. part.value end end - local vt = {} + local vt = {} --- @type {[1]: string, [2]: string?}[] if hint.paddingLeft then vt[#vt + 1] = { ' ' } end diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 6d2e0bc292..00433474fe 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -91,7 +91,9 @@ do -- -- Recommended usage: -- ``` - -- local _ = log.warn() and log.warn("123") + -- if log.warn() then + -- log.warn("123") + -- end -- ``` -- -- This way you can avoid string allocations if the log level isn't high enough. diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index a7c3914834..b2a92cd1ee 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -891,7 +891,7 @@ end --- Creates a normalized object describing LSP server capabilities. ---@param server_capabilities table Table of capabilities supported by the server ----@return table|nil Normalized table of capabilities +---@return lsp.ServerCapabilities|nil Normalized table of capabilities function protocol.resolve_capabilities(server_capabilities) local TextDocumentSyncKind = protocol.TextDocumentSyncKind local textDocumentSync = server_capabilities.textDocumentSync diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 6ab5708721..61ad1e479c 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -26,23 +26,42 @@ local function format_message_with_content_length(encoded_message) }) end +local function log_error(...) + if log.error() then + log.error(...) + end +end + +local function log_info(...) + if log.info() then + log.info(...) + end +end + +local function log_debug(...) + if log.debug() then + log.debug(...) + end +end + --- Parses an LSP Message's header --- ---@param header string: The header to parse. ---@return table # parsed headers local function parse_headers(header) assert(type(header) == 'string', 'header must be a string') - local headers = {} + local headers = {} --- @type table for line in vim.gsplit(header, '\r\n', { plain = true }) do if line == '' then break end + --- @type string?, string? local key, value = line:match('^%s*(%S+)%s*:%s*(.+)%s*$') if key then - key = key:lower():gsub('%-', '_') + key = key:lower():gsub('%-', '_') --- @type string headers[key] = value else - local _ = log.error() and log.error('invalid header line %q', line) + log_error('invalid header line %q', line) error(string.format('invalid header line %q', line)) end end @@ -96,17 +115,17 @@ local function request_parser_loop() end local body = table.concat(body_chunks) -- Yield our data. - buffer = rest - .. ( - coroutine.yield(headers, body) - or error('Expected more data for the body. The server may have died.') - ) -- TODO hmm. + + --- @type string + local data = coroutine.yield(headers, body) + or error('Expected more data for the body. The server may have died.') + buffer = rest .. data else -- Get more data since we don't have enough. - buffer = buffer - .. ( - coroutine.yield() or error('Expected more data for the header. The server may have died.') - ) -- TODO hmm. + --- @type string + local data = coroutine.yield() + or error('Expected more data for the header. The server may have died.') + buffer = buffer .. data end end end @@ -138,7 +157,7 @@ function M.format_rpc_error(err) -- There is ErrorCodes in the LSP specification, -- but in ResponseError.code it is not used and the actual type is number. - local code + local code --- @type string if protocol.ErrorCodes[err.code] then code = string.format('code_name = %s,', protocol.ErrorCodes[err.code]) else @@ -174,48 +193,51 @@ function M.rpc_response_error(code, message, data) }) end -local default_dispatchers = {} +--- @class vim.rpc.Dispatchers +--- @field notification fun(method: string, params: table) +--- @field server_request fun(method: string, params: table): any?, string? +--- @field on_exit fun(code: integer, signal: integer) +--- @field on_error fun(code: integer, err: any) ----@private ---- Default dispatcher for notifications sent to an LSP server. ---- ----@param method (string) The invoked LSP method ----@param params (table): Parameters for the invoked LSP method -function default_dispatchers.notification(method, params) - local _ = log.debug() and log.debug('notification', method, params) -end - ----@private ---- Default dispatcher for requests sent to an LSP server. ---- ----@param method (string) The invoked LSP method ----@param params (table): Parameters for the invoked LSP method ----@return nil ----@return table `vim.lsp.protocol.ErrorCodes.MethodNotFound` -function default_dispatchers.server_request(method, params) - local _ = log.debug() and log.debug('server_request', method, params) - return nil, M.rpc_response_error(protocol.ErrorCodes.MethodNotFound) -end - ----@private ---- Default dispatcher for when a client exits. ---- ----@param code (integer): Exit code ----@param signal (integer): Number describing the signal used to terminate (if ----any) -function default_dispatchers.on_exit(code, signal) - local _ = log.info() and log.info('client_exit', { code = code, signal = signal }) -end +--- @type vim.rpc.Dispatchers +local default_dispatchers = { + --- Default dispatcher for notifications sent to an LSP server. + --- + ---@param method (string) The invoked LSP method + ---@param params (table): Parameters for the invoked LSP method + notification = function(method, params) + log_debug('notification', method, params) + end, ----@private ---- Default dispatcher for client errors. ---- ----@param code (integer): Error code ----@param err (any): Details about the error ----any) -function default_dispatchers.on_error(code, err) - local _ = log.error() and log.error('client_error:', M.client_errors[code], err) -end + --- Default dispatcher for requests sent to an LSP server. + --- + ---@param method (string) The invoked LSP method + ---@param params (table): Parameters for the invoked LSP method + ---@return nil + ---@return table, `vim.lsp.protocol.ErrorCodes.MethodNotFound` + server_request = function(method, params) + log_debug('server_request', method, params) + return nil, M.rpc_response_error(protocol.ErrorCodes.MethodNotFound) + end, + + --- Default dispatcher for when a client exits. + --- + ---@param code (integer): Exit code + ---@param signal (integer): Number describing the signal used to terminate (if + ---any) + on_exit = function(code, signal) + log_info('client_exit', { code = code, signal = signal }) + end, + + --- Default dispatcher for client errors. + --- + ---@param code (integer): Error code + ---@param err (any): Details about the error + ---any) + on_error = function(code, err) + log_error('client_error:', M.client_errors[code], err) + end, +} ---@private function M.create_read_loop(handle_body, on_no_chunk, on_error) @@ -248,8 +270,8 @@ end ---@class RpcClient ---@field message_index integer ----@field message_callbacks table ----@field notify_reply_callbacks table +---@field message_callbacks table +---@field notify_reply_callbacks table ---@field transport table ---@field dispatchers table @@ -258,7 +280,7 @@ local Client = {} ---@private function Client:encode_and_send(payload) - local _ = log.debug() and log.debug('rpc.send', payload) + log_debug('rpc.send', payload) if self.transport.is_closing() then return false end @@ -267,7 +289,7 @@ function Client:encode_and_send(payload) return true end ----@private +---@package --- Sends a notification to the LSP server. ---@param method (string) The invoked LSP method ---@param params (any): Parameters for the invoked LSP method @@ -291,7 +313,7 @@ function Client:send_response(request_id, err, result) }) end ----@private +---@package --- Sends a request to the LSP server and runs {callback} upon response. --- ---@param method (string) The invoked LSP method @@ -329,7 +351,7 @@ function Client:request(method, params, callback, notify_reply_callback) end end ----@private +---@package function Client:on_error(errkind, ...) assert(M.client_errors[errkind]) -- TODO what to do if this fails? @@ -354,17 +376,17 @@ end -- time and log them. This would require storing the timestamp. I could call -- them with an error then, perhaps. ----@private +---@package function Client:handle_body(body) local ok, decoded = pcall(vim.json.decode, body, { luanil = { object = true } }) if not ok then self:on_error(M.client_errors.INVALID_SERVER_JSON, decoded) return end - local _ = log.debug() and log.debug('rpc.receive', decoded) + log_debug('rpc.receive', decoded) if type(decoded.method) == 'string' and decoded.id then - local err + local err --- @type table? -- Schedule here so that the users functions don't trigger an error and -- we can still use the result. schedule(function() @@ -376,11 +398,10 @@ function Client:handle_body(body) decoded.method, decoded.params ) - local _ = log.debug() - and log.debug( - 'server_request: callback result', - { status = status, result = result, err = err } - ) + log_debug( + 'server_request: callback result', + { status = status, result = result, err = err } + ) if status then if result == nil and err == nil then error( @@ -431,7 +452,7 @@ function Client:handle_body(body) if decoded.error then local mute_error = false if decoded.error.code == protocol.ErrorCodes.RequestCancelled then - local _ = log.debug() and log.debug('Received cancellation ack', decoded) + log_debug('Received cancellation ack', decoded) mute_error = true end @@ -467,7 +488,7 @@ function Client:handle_body(body) ) else self:on_error(M.client_errors.NO_RESULT_CALLBACK_FOUND, decoded) - local _ = log.error() and log.error('No callback found for server response id ' .. result_id) + log_error('No callback found for server response id ' .. result_id) end elseif type(decoded.method) == 'string' then -- Notification @@ -495,7 +516,14 @@ local function new_client(dispatchers, transport) return setmetatable(state, { __index = Client }) end +--- @class RpcClientPublic +--- @field is_closing fun(): boolean +--- @field terminate fun() +--- @field request fun(method: string, params: table?, callback: function, notify_reply_callbacks?: function) +--- @field notify fun(methid: string, params: table?): boolean + ---@param client RpcClient +---@return RpcClientPublic local function public_client(client) local result = {} @@ -531,12 +559,14 @@ local function public_client(client) return result end +--- @param dispatchers vim.rpc.Dispatchers? +--- @return vim.rpc.Dispatchers local function merge_dispatchers(dispatchers) if dispatchers then local user_dispatchers = dispatchers dispatchers = {} for dispatch_name, default_dispatch in pairs(default_dispatchers) do - local user_dispatcher = user_dispatchers[dispatch_name] + local user_dispatcher = user_dispatchers[dispatch_name] --- @type function if user_dispatcher then if type(user_dispatcher) ~= 'function' then error(string.format('dispatcher.%s must be a function', dispatch_name)) @@ -547,8 +577,10 @@ local function merge_dispatchers(dispatchers) then user_dispatcher = schedule_wrap(user_dispatcher) end + --- @diagnostic disable-next-line:no-unknown dispatchers[dispatch_name] = user_dispatcher else + --- @diagnostic disable-next-line:no-unknown dispatchers[dispatch_name] = default_dispatch end end @@ -567,7 +599,7 @@ end function M.connect(host, port) return function(dispatchers) dispatchers = merge_dispatchers(dispatchers) - local tcp = uv.new_tcp() + local tcp = assert(uv.new_tcp()) local closing = false local transport = { write = function(msg) @@ -624,15 +656,13 @@ end --- server process. May contain: --- - {cwd} (string) Working directory for the LSP server process --- - {env} (table) Additional environment variables for LSP server process ----@return table|nil Client RPC object, with these methods: +---@return RpcClientPublic|nil Client RPC object, with these methods: --- - `notify()` |vim.lsp.rpc.notify()| --- - `request()` |vim.lsp.rpc.request()| --- - `is_closing()` returns a boolean indicating if the RPC is closing. --- - `terminate()` terminates the RPC client. function M.start(cmd, cmd_args, dispatchers, extra_spawn_params) - if log.info() then - log.info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params }) - end + log_info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params }) validate({ cmd = { cmd, 's' }, @@ -671,8 +701,8 @@ function M.start(cmd, cmd_args, dispatchers, extra_spawn_params) end) local stderr_handler = function(_, chunk) - if chunk and log.error() then - log.error('rpc', cmd, 'stderr', chunk) + if chunk then + log_error('rpc', cmd, 'stderr', chunk) end end @@ -697,13 +727,13 @@ function M.start(cmd, cmd_args, dispatchers, extra_spawn_params) if not ok then local err = sysobj_or_err --[[@as string]] - local msg = string.format('Spawning language server with cmd: `%s` failed', cmd) + local sfx --- @type string if string.match(err, 'ENOENT') then - msg = msg - .. '. The language server is either not installed, missing from PATH, or not executable.' + sfx = '. The language server is either not installed, missing from PATH, or not executable.' else - msg = msg .. string.format(' with error message: %s', err) + sfx = string.format(' with error message: %s', err) end + local msg = string.format('Spawning language server with cmd: `%s` failed%s', cmd, sfx) vim.notify(msg, vim.log.levels.WARN) return end diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index a5831c0beb..b0cec0dd0e 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -10,7 +10,7 @@ local uv = vim.uv --- @field start_col integer start column 0-based --- @field end_col integer end column 0-based --- @field type string token type as string ---- @field modifiers table token modifiers as a set. E.g., { static = true, readonly = true } +--- @field modifiers table token modifiers as a set. E.g., { static = true, readonly = true } --- @field marked boolean whether this token has had extmarks applied --- --- @class STCurrentResult @@ -21,8 +21,8 @@ local uv = vim.uv --- @field namespace_cleared? boolean whether the namespace was cleared for this result yet --- --- @class STActiveRequest ---- @field request_id integer the LSP request ID of the most recent request sent to the server ---- @field version integer the document version associated with the most recent request +--- @field request_id? integer the LSP request ID of the most recent request sent to the server +--- @field version? integer the document version associated with the most recent request --- --- @class STClientState --- @field namespace integer @@ -72,9 +72,11 @@ end --- Extracts modifier strings from the encoded number in the token array --- +---@param x integer +---@param modifiers_table table ---@return table local function modifiers_from_number(x, modifiers_table) - local modifiers = {} + local modifiers = {} ---@type table local idx = 1 while x > 0 do if bit.band(x, 1) == 1 then @@ -89,20 +91,24 @@ end --- Converts a raw token list to a list of highlight ranges used by the on_win callback --- +---@param data integer[] +---@param bufnr integer +---@param client lsp.Client +---@param request STActiveRequest ---@return STTokenRange[] local function tokens_to_ranges(data, bufnr, client, request) local legend = client.server_capabilities.semanticTokensProvider.legend local token_types = legend.tokenTypes local token_modifiers = legend.tokenModifiers local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false) - local ranges = {} + local ranges = {} ---@type STTokenRange[] local start = uv.hrtime() local ms_to_ns = 1000 * 1000 local yield_interval_ns = 5 * ms_to_ns local co, is_main = coroutine.running() - local line + local line ---@type integer? local start_char = 0 for i = 1, #data, 5 do -- if this function is called from the main coroutine, let it run to completion with no yield @@ -167,6 +173,7 @@ end --- ---@private ---@param bufnr integer +---@return STHighlighter function STHighlighter.new(bufnr) local self = setmetatable({}, { __index = STHighlighter }) @@ -221,7 +228,7 @@ function STHighlighter.new(bufnr) return self end ----@private +---@package function STHighlighter:destroy() for client_id, _ in pairs(self.client_state) do self:detach(client_id) @@ -231,7 +238,7 @@ function STHighlighter:destroy() STHighlighter.active[self.bufnr] = nil end ----@private +---@package function STHighlighter:attach(client_id) local state = self.client_state[client_id] if not state then @@ -244,7 +251,7 @@ function STHighlighter:attach(client_id) end end ----@private +---@package function STHighlighter:detach(client_id) local state = self.client_state[client_id] if state then @@ -267,7 +274,7 @@ end --- Finally, if the request was successful, the requestId and document version --- are saved to facilitate document synchronization in the response. --- ----@private +---@package function STHighlighter:send_request() local version = util.buf_versions[self.bufnr] @@ -303,7 +310,8 @@ function STHighlighter:send_request() -- look client up again using ctx.client_id instead of using a captured -- client object local c = vim.lsp.get_client_by_id(ctx.client_id) - local highlighter = STHighlighter.active[ctx.bufnr] + local bufnr = assert(ctx.bufnr) + local highlighter = STHighlighter.active[bufnr] if not err and c and highlighter then coroutine.wrap(STHighlighter.process_response)(highlighter, response, c, version) end @@ -328,6 +336,7 @@ end --- Finally, a redraw command is issued to force nvim to redraw the screen to --- pick up changed highlight tokens. --- +---@param response lsp.SemanticTokens|lsp.SemanticTokensDelta ---@private function STHighlighter:process_response(response, client, version) local state = self.client_state[client.id] @@ -348,15 +357,15 @@ function STHighlighter:process_response(response, client, version) -- if we have a response to a delta request, update the state of our tokens -- appropriately. if it's a full response, just use that - local tokens + local tokens ---@type integer[] local token_edits = response.edits if token_edits then table.sort(token_edits, function(a, b) return a.start < b.start end) - tokens = {} - local old_tokens = state.current_result.tokens + tokens = {} --- @type integer[] + local old_tokens = assert(state.current_result.tokens) local idx = 1 for _, token_edit in ipairs(token_edits) do vim.list_extend(tokens, old_tokens, idx, token_edit.start) @@ -404,7 +413,9 @@ end --- handler to avoid the "blink" that occurs due to the timing between the --- response handler and the actual redraw. --- ----@private +---@package +---@param topline integer +---@param botline integer function STHighlighter:on_win(topline, botline) for client_id, state in pairs(self.client_state) do local current_result = state.current_result @@ -450,7 +461,7 @@ function STHighlighter:on_win(topline, botline) end local ft = vim.bo[self.bufnr].filetype - local highlights = current_result.highlights + local highlights = assert(current_result.highlights) local first = lower_bound(highlights, topline, 1, #highlights + 1) local last = upper_bound(highlights, botline, first, #highlights + 1) - 1 @@ -480,7 +491,7 @@ end --- Reset the buffer's highlighting state and clears the extmark highlights. --- ----@private +---@package function STHighlighter:reset() for client_id, state in pairs(self.client_state) do api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1) @@ -499,7 +510,7 @@ end --- in the on_win callback. The rest of the current results are saved --- in case the server supports delta requests. --- ----@private +---@package ---@param client_id integer function STHighlighter:mark_dirty(client_id) local state = self.client_state[client_id] @@ -521,7 +532,7 @@ function STHighlighter:mark_dirty(client_id) end end ----@private +---@package function STHighlighter:on_change() self:reset_timer() if self.debounce > 0 then @@ -636,6 +647,9 @@ function M.stop(bufnr, client_id) end end +--- @class STTokenRangeInspect : STTokenRange +--- @field client_id integer + --- Return the semantic token(s) at the given position. --- If called without arguments, returns the token under the cursor. --- @@ -643,13 +657,14 @@ end ---@param row integer|nil Position row (default cursor position) ---@param col integer|nil Position column (default cursor position) --- ----@return table|nil (table|nil) List of tokens at position. Each token has +---@return STTokenRangeInspect[]|nil (table|nil) List of tokens at position. Each token has --- the following fields: --- - line (integer) line number, 0-based --- - start_col (integer) start column, 0-based --- - end_col (integer) end column, 0-based --- - type (string) token type as string, e.g. "variable" --- - modifiers (table) token modifiers as a set. E.g., { static = true, readonly = true } +--- - client_id (integer) function M.get_at_pos(bufnr, row, col) if bufnr == nil or bufnr == 0 then bufnr = api.nvim_get_current_buf() @@ -665,13 +680,14 @@ function M.get_at_pos(bufnr, row, col) row, col = cursor[1] - 1, cursor[2] end - local tokens = {} + local tokens = {} --- @type STTokenRangeInspect[] for client_id, client in pairs(highlighter.client_state) do local highlights = client.current_result.highlights if highlights then local idx = lower_bound(highlights, row, 1, #highlights + 1) for i = idx, #highlights do local token = highlights[i] + --- @cast token STTokenRangeInspect if token.line > row then break diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index ca01cdc08b..c2b5b54cb0 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -58,7 +58,7 @@ local function byte_to_utf(line, byte, offset_encoding) -- convert to 0 based indexing for str_utfindex byte = byte - 1 - local utf_idx + local utf_idx --- @type integer local _ -- Convert the byte range to utf-{8,16,32} and convert 1-based (lua) indexing to 0-based if offset_encoding == 'utf-16' then @@ -73,8 +73,11 @@ local function byte_to_utf(line, byte, offset_encoding) return utf_idx + 1 end +---@param line string +---@param offset_encoding string +---@return integer local function compute_line_length(line, offset_encoding) - local length + local length --- @type integer local _ if offset_encoding == 'utf-16' then _, length = str_utfindex(line) @@ -94,7 +97,7 @@ end ---@return integer byte_idx of first change position ---@return integer char_idx of first change position local function align_end_position(line, byte, offset_encoding) - local char + local char --- @type integer -- If on the first byte, or an empty string: the trivial case if byte == 1 or #line == 0 then char = byte @@ -120,8 +123,8 @@ local function align_end_position(line, byte, offset_encoding) end --- Finds the first line, byte, and char index of the difference between the previous and current lines buffer normalized to the previous codepoint. ----@param prev_lines table list of lines from previous buffer ----@param curr_lines table list of lines from current buffer +---@param prev_lines string[] list of lines from previous buffer +---@param curr_lines string[] list of lines from current buffer ---@param firstline integer firstline from on_lines, adjusted to 1-index ---@param lastline integer lastline from on_lines, adjusted to 1-index ---@param new_lastline integer new_lastline from on_lines, adjusted to 1-index @@ -135,14 +138,14 @@ local function compute_start_range( new_lastline, offset_encoding ) - local char_idx - local byte_idx + local char_idx --- @type integer? + local byte_idx --- @type integer? -- If firstline == lastline, no existing text is changed. All edit operations -- occur on a new line pointed to by lastline. This occurs during insertion of -- new lines(O), the new newline is inserted at the line indicated by -- new_lastline. if firstline == lastline then - local line_idx + local line_idx --- @type integer local line = prev_lines[firstline - 1] if line then line_idx = firstline - 1 @@ -343,6 +346,12 @@ end -- codeunits for utf-32 -- Line endings count here as 2 chars for \r\n (dos), 1 char for \n (unix), and 1 char for \r (mac) -- These correspond to Windows, Linux/macOS (OSX and newer), and macOS (version 9 and prior) +---@param lines string[] +---@param start_range table +---@param end_range table +---@param offset_encoding string +---@param line_ending string +---@return integer local function compute_range_length(lines, start_range, end_range, offset_encoding, line_ending) local line_ending_length = #line_ending -- Single line case @@ -351,7 +360,7 @@ local function compute_range_length(lines, start_range, end_range, offset_encodi end local start_line = lines[start_range.line_idx] - local range_length + local range_length --- @type integer if start_line and #start_line > 0 then range_length = compute_line_length(start_line, offset_encoding) - start_range.char_idx @@ -387,6 +396,7 @@ end ---@param lastline integer line to begin search in old_lines for last difference ---@param new_lastline integer line to begin search in new_lines for last difference ---@param offset_encoding string encoding requested by language server +---@param line_ending string ---@return table TextDocumentContentChangeEvent see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent function M.compute_diff( prev_lines, diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 32b220746f..dc8fb25563 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -2089,7 +2089,7 @@ end --- Creates a `DocumentFormattingParams` object for the current buffer and cursor position. --- ---@param options table|nil with valid `FormattingOptions` entries ----@return `DocumentFormattingParams` object +---@return lsp.DocumentFormattingParams object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting function M.make_formatting_params(options) validate({ options = { options, 't', true } }) @@ -2228,6 +2228,6 @@ end M._get_line_byte_from_position = get_line_byte_from_position ---@nodoc -M.buf_versions = {} +M.buf_versions = {} ---@type table return M -- cgit From 5a2536de0c4beae4eba50a0d2868983c1690ecc7 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 17 Dec 2023 09:54:38 +0000 Subject: refactor(lsp): move changetracking to separate file (#26577) * refactor(lsp): move changetracking to separate file - Prefixed changetracking types with `vim.lsp.` * fixup!: make _reset_timer a local function * fixup!: remove @private annotations * fixup!: changetracking.lua -> _changetracking.lua * fixup! types * fixup! add send_changes_for_group --- runtime/lua/vim/lsp/_changetracking.lua | 373 ++++++++++++++++++++++++++++++++ runtime/lua/vim/lsp/sync.lua | 2 +- 2 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 runtime/lua/vim/lsp/_changetracking.lua (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_changetracking.lua b/runtime/lua/vim/lsp/_changetracking.lua new file mode 100644 index 0000000000..67c74f069d --- /dev/null +++ b/runtime/lua/vim/lsp/_changetracking.lua @@ -0,0 +1,373 @@ +local protocol = require('vim.lsp.protocol') +local sync = require('vim.lsp.sync') +local util = require('vim.lsp.util') + +local api = vim.api +local uv = vim.uv + +local M = {} + +--- LSP has 3 different sync modes: +--- - None (Servers will read the files themselves when needed) +--- - Full (Client sends the full buffer content on updates) +--- - Incremental (Client sends only the changed parts) +--- +--- Changes are tracked per buffer. +--- A buffer can have multiple clients attached and each client needs to send the changes +--- To minimize the amount of changesets to compute, computation is grouped: +--- +--- None: One group for all clients +--- Full: One group for all clients +--- Incremental: One group per `offset_encoding` +--- +--- Sending changes can be debounced per buffer. To simplify the implementation the +--- smallest debounce interval is used and we don't group clients by different intervals. +--- +--- @class vim.lsp.CTGroup +--- @field sync_kind integer TextDocumentSyncKind, considers config.flags.allow_incremental_sync +--- @field offset_encoding "utf-8"|"utf-16"|"utf-32" +--- +--- @class vim.lsp.CTBufferState +--- @field name string name of the buffer +--- @field lines string[] snapshot of buffer lines from last didChange +--- @field lines_tmp string[] +--- @field pending_changes table[] List of debounced changes in incremental sync mode +--- @field timer uv.uv_timer_t? uv_timer +--- @field last_flush nil|number uv.hrtime of the last flush/didChange-notification +--- @field needs_flush boolean true if buffer updates haven't been sent to clients/servers yet +--- @field refs integer how many clients are using this group +--- +--- @class vim.lsp.CTGroupState +--- @field buffers table +--- @field debounce integer debounce duration in ms +--- @field clients table clients using this state. {client_id, client} + +---@param group vim.lsp.CTGroup +---@return string +local function group_key(group) + if group.sync_kind == protocol.TextDocumentSyncKind.Incremental then + return tostring(group.sync_kind) .. '\0' .. group.offset_encoding + end + return tostring(group.sync_kind) +end + +---@type table +local state_by_group = setmetatable({}, { + __index = function(tbl, k) + return rawget(tbl, group_key(k)) + end, + __newindex = function(tbl, k, v) + rawset(tbl, group_key(k), v) + end, +}) + +---@param client lsp.Client +---@return vim.lsp.CTGroup +local function get_group(client) + local allow_inc_sync = vim.F.if_nil(client.config.flags.allow_incremental_sync, true) + local change_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'change') + local sync_kind = change_capability or protocol.TextDocumentSyncKind.None + if not allow_inc_sync and change_capability == protocol.TextDocumentSyncKind.Incremental then + sync_kind = protocol.TextDocumentSyncKind.Full --[[@as integer]] + end + return { + sync_kind = sync_kind, + offset_encoding = client.offset_encoding, + } +end + +---@param state vim.lsp.CTBufferState +---@param encoding string +---@param bufnr integer +---@param firstline integer +---@param lastline integer +---@param new_lastline integer +---@return lsp.TextDocumentContentChangeEvent +local function incremental_changes(state, encoding, bufnr, firstline, lastline, new_lastline) + local prev_lines = state.lines + local curr_lines = state.lines_tmp + + local changed_lines = api.nvim_buf_get_lines(bufnr, firstline, new_lastline, true) + for i = 1, firstline do + curr_lines[i] = prev_lines[i] + end + for i = firstline + 1, new_lastline do + curr_lines[i] = changed_lines[i - firstline] + end + for i = lastline + 1, #prev_lines do + curr_lines[i - lastline + new_lastline] = prev_lines[i] + end + if vim.tbl_isempty(curr_lines) then + -- Can happen when deleting the entire contents of a buffer, see https://github.com/neovim/neovim/issues/16259. + curr_lines[1] = '' + end + + local line_ending = vim.lsp._buf_get_line_ending(bufnr) + local incremental_change = sync.compute_diff( + state.lines, + curr_lines, + firstline, + lastline, + new_lastline, + encoding, + line_ending + ) + + -- Double-buffering of lines tables is used to reduce the load on the garbage collector. + -- At this point the prev_lines table is useless, but its internal storage has already been allocated, + -- so let's keep it around for the next didChange event, in which it will become the next + -- curr_lines table. Note that setting elements to nil doesn't actually deallocate slots in the + -- internal storage - it merely marks them as free, for the GC to deallocate them. + for i in ipairs(prev_lines) do + prev_lines[i] = nil + end + state.lines = curr_lines + state.lines_tmp = prev_lines + + return incremental_change +end + +---@param client lsp.Client +---@param bufnr integer +function M.init(client, bufnr) + assert(client.offset_encoding, 'lsp client must have an offset_encoding') + local group = get_group(client) + local state = state_by_group[group] + if state then + state.debounce = math.min(state.debounce, client.config.flags.debounce_text_changes or 150) + state.clients[client.id] = client + else + state = { + buffers = {}, + debounce = client.config.flags.debounce_text_changes or 150, + clients = { + [client.id] = client, + }, + } + state_by_group[group] = state + end + local buf_state = state.buffers[bufnr] + if buf_state then + buf_state.refs = buf_state.refs + 1 + else + buf_state = { + name = api.nvim_buf_get_name(bufnr), + lines = {}, + lines_tmp = {}, + pending_changes = {}, + needs_flush = false, + refs = 1, + } + state.buffers[bufnr] = buf_state + if group.sync_kind == protocol.TextDocumentSyncKind.Incremental then + buf_state.lines = api.nvim_buf_get_lines(bufnr, 0, -1, true) + end + end +end + +--- @param client lsp.Client +--- @param bufnr integer +--- @param name string +--- @return string +function M._get_and_set_name(client, bufnr, name) + local state = state_by_group[get_group(client)] or {} + local buf_state = (state.buffers or {})[bufnr] + local old_name = buf_state.name + buf_state.name = name + return old_name +end + +---@param buf_state vim.lsp.CTBufferState +local function reset_timer(buf_state) + local timer = buf_state.timer + if timer then + buf_state.timer = nil + if not timer:is_closing() then + timer:stop() + timer:close() + end + end +end + +--- @param client lsp.Client +--- @param bufnr integer +function M.reset_buf(client, bufnr) + M.flush(client, bufnr) + local state = state_by_group[get_group(client)] + if not state then + return + end + assert(state.buffers, 'CTGroupState must have buffers') + local buf_state = state.buffers[bufnr] + buf_state.refs = buf_state.refs - 1 + assert(buf_state.refs >= 0, 'refcount on buffer state must not get negative') + if buf_state.refs == 0 then + state.buffers[bufnr] = nil + reset_timer(buf_state) + end +end + +--- @param client lsp.Client +function M.reset(client) + local state = state_by_group[get_group(client)] + if not state then + return + end + state.clients[client.id] = nil + if vim.tbl_count(state.clients) == 0 then + for _, buf_state in pairs(state.buffers) do + reset_timer(buf_state) + end + state.buffers = {} + end +end + +-- Adjust debounce time by taking time of last didChange notification into +-- consideration. If the last didChange happened more than `debounce` time ago, +-- debounce can be skipped and otherwise maybe reduced. +-- +-- This turns the debounce into a kind of client rate limiting +-- +---@param debounce integer +---@param buf_state vim.lsp.CTBufferState +---@return number +local function next_debounce(debounce, buf_state) + if debounce == 0 then + return 0 + end + local ns_to_ms = 0.000001 + if not buf_state.last_flush then + return debounce + end + local now = uv.hrtime() + local ms_since_last_flush = (now - buf_state.last_flush) * ns_to_ms + return math.max(debounce - ms_since_last_flush, 0) +end + +---@param bufnr integer +---@param sync_kind integer protocol.TextDocumentSyncKind +---@param state vim.lsp.CTGroupState +---@param buf_state vim.lsp.CTBufferState +local function send_changes(bufnr, sync_kind, state, buf_state) + if not buf_state.needs_flush then + return + end + buf_state.last_flush = uv.hrtime() + buf_state.needs_flush = false + + if not api.nvim_buf_is_valid(bufnr) then + buf_state.pending_changes = {} + return + end + + local changes --- @type lsp.TextDocumentContentChangeEvent[] + if sync_kind == protocol.TextDocumentSyncKind.None then + return + elseif sync_kind == protocol.TextDocumentSyncKind.Incremental then + changes = buf_state.pending_changes + buf_state.pending_changes = {} + else + changes = { + { text = vim.lsp._buf_get_full_text(bufnr) }, + } + end + local uri = vim.uri_from_bufnr(bufnr) + for _, client in pairs(state.clients) do + if not client.is_stopped() and vim.lsp.buf_is_attached(bufnr, client.id) then + client.notify(protocol.Methods.textDocument_didChange, { + textDocument = { + uri = uri, + version = util.buf_versions[bufnr], + }, + contentChanges = changes, + }) + end + end +end + +--- @param bufnr integer +--- @param firstline integer +--- @param lastline integer +--- @param new_lastline integer +--- @param group vim.lsp.CTGroup +local function send_changes_for_group(bufnr, firstline, lastline, new_lastline, group) + local state = state_by_group[group] + if not state then + error( + string.format( + 'changetracking.init must have been called for all LSP clients. group=%s states=%s', + vim.inspect(group), + vim.inspect(vim.tbl_keys(state_by_group)) + ) + ) + end + local buf_state = state.buffers[bufnr] + buf_state.needs_flush = true + reset_timer(buf_state) + local debounce = next_debounce(state.debounce, buf_state) + if group.sync_kind == protocol.TextDocumentSyncKind.Incremental then + -- This must be done immediately and cannot be delayed + -- The contents would further change and startline/endline may no longer fit + local changes = incremental_changes( + buf_state, + group.offset_encoding, + bufnr, + firstline, + lastline, + new_lastline + ) + table.insert(buf_state.pending_changes, changes) + end + if debounce == 0 then + send_changes(bufnr, group.sync_kind, state, buf_state) + else + local timer = assert(uv.new_timer(), 'Must be able to create timer') + buf_state.timer = timer + timer:start( + debounce, + 0, + vim.schedule_wrap(function() + reset_timer(buf_state) + send_changes(bufnr, group.sync_kind, state, buf_state) + end) + ) + end +end + +--- @param bufnr integer +--- @param firstline integer +--- @param lastline integer +--- @param new_lastline integer +function M.send_changes(bufnr, firstline, lastline, new_lastline) + local groups = {} ---@type table + for _, client in pairs(vim.lsp.get_clients({ bufnr = bufnr })) do + local group = get_group(client) + groups[group_key(group)] = group + end + for _, group in pairs(groups) do + send_changes_for_group(bufnr, firstline, lastline, new_lastline, group) + end +end + +--- Flushes any outstanding change notification. +---@param client lsp.Client +---@param bufnr? integer +function M.flush(client, bufnr) + local group = get_group(client) + local state = state_by_group[group] + if not state then + return + end + if bufnr then + local buf_state = state.buffers[bufnr] or {} + reset_timer(buf_state) + send_changes(bufnr, group.sync_kind, state, buf_state) + else + for buf, buf_state in pairs(state.buffers) do + reset_timer(buf_state) + send_changes(buf, group.sync_kind, state, buf_state) + end + end +end + +return M diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index c2b5b54cb0..7ebe2dbb88 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -397,7 +397,7 @@ end ---@param new_lastline integer line to begin search in new_lines for last difference ---@param offset_encoding string encoding requested by language server ---@param line_ending string ----@return table TextDocumentContentChangeEvent see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent +---@return lsp.TextDocumentContentChangeEvent : see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent function M.compute_diff( prev_lines, curr_lines, -- cgit From db0ec84fb46b8235f8651d5aa25eb56a9b117eb5 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 22 Dec 2023 11:38:02 +0100 Subject: feat(lsp): add type annotations for lsp.util.locations_to_items (#26694) Problem: luals reported many warnings Solution: Add type annotations --- runtime/lua/vim/lsp/util.lua | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index dc8fb25563..63c4c1e7fc 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1754,6 +1754,13 @@ local position_sort = sort_by_key(function(v) return { v.start.line, v.start.character } end) +---@class vim.lsp.util.LocationItem +---@field filename string +---@field lnum integer 1-indexed line number +---@field col integer 1-indexed column +---@field text string +---@field user_data lsp.Location|lsp.LocationLink + --- Returns the items with the byte position calculated correctly and in sorted --- order, for display in quickfix and location lists. --- @@ -1763,10 +1770,10 @@ end) --- The result can be passed to the {list} argument of |setqflist()| or --- |setloclist()|. --- ----@param locations table list of `Location`s or `LocationLink`s +---@param locations lsp.Location[]|lsp.LocationLink[] ---@param offset_encoding string offset_encoding for locations utf-8|utf-16|utf-32 --- default to first client of buffer ----@return table list of items +---@return vim.lsp.util.LocationItem[] list of items function M.locations_to_items(locations, offset_encoding) if offset_encoding == nil then vim.notify_once( @@ -1777,6 +1784,7 @@ function M.locations_to_items(locations, offset_encoding) end local items = {} + ---@type table local grouped = setmetatable({}, { __index = function(t, k) local v = {} @@ -1791,6 +1799,7 @@ function M.locations_to_items(locations, offset_encoding) table.insert(grouped[uri], { start = range.start, location = d }) end + ---@type string[] local keys = vim.tbl_keys(grouped) table.sort(keys) -- TODO(ashkan) I wish we could do this lazily. @@ -1799,16 +1808,13 @@ function M.locations_to_items(locations, offset_encoding) table.sort(rows, position_sort) local filename = vim.uri_to_fname(uri) - -- list of row numbers - local uri_rows = {} + local line_numbers = {} for _, temp in ipairs(rows) do - local pos = temp.start - local row = pos.line - table.insert(uri_rows, row) + table.insert(line_numbers, temp.start.line) end -- get all the lines for this uri - local lines = get_lines(vim.uri_to_bufnr(uri), uri_rows) + local lines = get_lines(vim.uri_to_bufnr(uri), line_numbers) for _, temp in ipairs(rows) do local pos = temp.start -- cgit From 92204b06e7365cf4c68e6ea8258dce801f0a5df9 Mon Sep 17 00:00:00 2001 From: Steven Arcangeli <506791+stevearc@users.noreply.github.com> Date: Fri, 22 Dec 2023 02:40:01 -0800 Subject: refactor(lsp): move glob parsing to util (#26519) refactor(lsp): move glob parsing to vim.glob Moving the logic for using vim.lpeg to create a match pattern from a glob into `vim.glob`. There are several places in the LSP spec that use globs, and it's very useful to have glob matching as a generally-available utility. --- runtime/lua/vim/lsp/_dynamic.lua | 4 +- runtime/lua/vim/lsp/_watchfiles.lua | 93 +++---------------------------------- 2 files changed, 8 insertions(+), 89 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua index 04040e8e28..4bee58559f 100644 --- a/runtime/lua/vim/lsp/_dynamic.lua +++ b/runtime/lua/vim/lsp/_dynamic.lua @@ -1,4 +1,4 @@ -local wf = require('vim.lsp._watchfiles') +local glob = require('vim.glob') --- @class lsp.DynamicCapabilities --- @field capabilities table @@ -97,7 +97,7 @@ function M.match(bufnr, documentSelector) if matches and filter.scheme and not vim.startswith(uri, filter.scheme .. ':') then matches = false end - if matches and filter.pattern and not wf._match(filter.pattern, fname) then + if matches and filter.pattern and not glob.to_lpeg(filter.pattern):match(fname) then matches = false end if matches then diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua index 1fd112631d..af4cc65f71 100644 --- a/runtime/lua/vim/lsp/_watchfiles.lua +++ b/runtime/lua/vim/lsp/_watchfiles.lua @@ -1,4 +1,5 @@ local bit = require('bit') +local glob = require('vim.glob') local watch = require('vim._watch') local protocol = require('vim.lsp.protocol') local ms = protocol.Methods @@ -6,88 +7,6 @@ local lpeg = vim.lpeg local M = {} ---- Parses the raw pattern into an |lpeg| pattern. LPeg patterns natively support the "this" or "that" ---- alternative constructions described in the LSP spec that cannot be expressed in a standard Lua pattern. ---- ----@param pattern string The raw glob pattern ----@return vim.lpeg.Pattern? pattern An |lpeg| representation of the pattern, or nil if the pattern is invalid. -local function parse(pattern) - local l = lpeg - - local P, S, V = lpeg.P, lpeg.S, lpeg.V - local C, Cc, Ct, Cf = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cf - - local pathsep = '/' - - local function class(inv, ranges) - for i, r in ipairs(ranges) do - ranges[i] = r[1] .. r[2] - end - local patt = l.R(unpack(ranges)) - if inv == '!' then - patt = P(1) - patt - end - return patt - end - - local function add(acc, a) - return acc + a - end - - local function mul(acc, m) - return acc * m - end - - local function star(stars, after) - return (-after * (l.P(1) - pathsep)) ^ #stars * after - end - - local function dstar(after) - return (-after * l.P(1)) ^ 0 * after - end - - local p = P({ - 'Pattern', - Pattern = V('Elem') ^ -1 * V('End'), - Elem = Cf( - (V('DStar') + V('Star') + V('Ques') + V('Class') + V('CondList') + V('Literal')) - * (V('Elem') + V('End')), - mul - ), - DStar = P('**') * (P(pathsep) * (V('Elem') + V('End')) + V('End')) / dstar, - Star = C(P('*') ^ 1) * (V('Elem') + V('End')) / star, - Ques = P('?') * Cc(l.P(1) - pathsep), - Class = P('[') * C(P('!') ^ -1) * Ct(Ct(C(1) * '-' * C(P(1) - ']')) ^ 1 * ']') / class, - CondList = P('{') * Cf(V('Cond') * (P(',') * V('Cond')) ^ 0, add) * '}', - -- TODO: '*' inside a {} condition is interpreted literally but should probably have the same - -- wildcard semantics it usually has. - -- Fixing this is non-trivial because '*' should match non-greedily up to "the rest of the - -- pattern" which in all other cases is the entire succeeding part of the pattern, but at the end of a {} - -- condition means "everything after the {}" where several other options separated by ',' may - -- exist in between that should not be matched by '*'. - Cond = Cf((V('Ques') + V('Class') + V('CondList') + (V('Literal') - S(',}'))) ^ 1, mul) - + Cc(l.P(0)), - Literal = P(1) / l.P, - End = P(-1) * Cc(l.P(-1)), - }) - - return p:match(pattern) --[[@as vim.lpeg.Pattern?]] -end - ----@private ---- Implementation of LSP 3.17.0's pattern matching: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#pattern ---- ----@param pattern string|vim.lpeg.Pattern The glob pattern (raw or parsed) to match. ----@param s string The string to match against pattern. ----@return boolean Whether or not pattern matches s. -function M._match(pattern, s) - if type(pattern) == 'string' then - local p = assert(parse(pattern)) - return p:match(s) ~= nil - end - return pattern:match(s) ~= nil -end - M._watchfunc = (vim.fn.has('win32') == 1 or vim.fn.has('mac') == 1) and watch.watch or watch.poll ---@type table> client id -> registration id -> cancel function @@ -112,9 +31,9 @@ local to_lsp_change_type = { --- Default excludes the same as VSCode's `files.watcherExclude` setting. --- https://github.com/microsoft/vscode/blob/eef30e7165e19b33daa1e15e92fa34ff4a5df0d3/src/vs/workbench/contrib/files/browser/files.contribution.ts#L261 ---@type vim.lpeg.Pattern parsed Lpeg pattern -M._poll_exclude_pattern = parse('**/.git/{objects,subtree-cache}/**') - + parse('**/node_modules/*/**') - + parse('**/.hg/store/**') +M._poll_exclude_pattern = glob.to_lpeg('**/.git/{objects,subtree-cache}/**') + + glob.to_lpeg('**/node_modules/*/**') + + glob.to_lpeg('**/.hg/store/**') --- Registers the workspace/didChangeWatchedFiles capability dynamically. --- @@ -143,7 +62,7 @@ function M.register(reg, ctx) local glob_pattern = w.globPattern if type(glob_pattern) == 'string' then - local pattern = parse(glob_pattern) + local pattern = glob.to_lpeg(glob_pattern) if not pattern then error('Cannot parse pattern: ' .. glob_pattern) end @@ -155,7 +74,7 @@ function M.register(reg, ctx) local base_uri = glob_pattern.baseUri local uri = type(base_uri) == 'string' and base_uri or base_uri.uri local base_dir = vim.uri_to_fname(uri) - local pattern = parse(glob_pattern.pattern) + local pattern = glob.to_lpeg(glob_pattern.pattern) if not pattern then error('Cannot parse pattern: ' .. glob_pattern.pattern) end -- cgit From 031088fc0afffe4af6fa90d68d5b93ca09992ef1 Mon Sep 17 00:00:00 2001 From: Michal Liszcz Date: Fri, 22 Dec 2023 15:03:13 +0100 Subject: fix(lsp): filetype matching to documentSelector in dynamic capabilities (#25425) Use the get_language_id client option to resolve the filetype when matching the document selector in a dynamic capability. Co-authored-by: Mathias Fussenegger --- runtime/lua/vim/lsp/_dynamic.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua index 4bee58559f..5edb27b498 100644 --- a/runtime/lua/vim/lsp/_dynamic.lua +++ b/runtime/lua/vim/lsp/_dynamic.lua @@ -55,7 +55,7 @@ function M:unregister(unregisterations) end --- @param method string ---- @param opts? {bufnr?: number} +--- @param opts? {bufnr: integer?} --- @return lsp.Registration? (table|nil) the registration if found --- @private function M:get(method, opts) @@ -69,14 +69,14 @@ function M:get(method, opts) if not documentSelector then return reg end - if M.match(opts.bufnr, documentSelector) then + if self:match(opts.bufnr, documentSelector) then return reg end end end --- @param method string ---- @param opts? {bufnr?: number} +--- @param opts? {bufnr: integer?} --- @private function M:supports(method, opts) return self:get(method, opts) ~= nil @@ -85,13 +85,17 @@ end --- @param bufnr number --- @param documentSelector lsp.DocumentSelector --- @private -function M.match(bufnr, documentSelector) - local ft = vim.bo[bufnr].filetype +function M:match(bufnr, documentSelector) + local client = vim.lsp.get_client_by_id(self.client_id) + if not client then + return false + end + local language = client.config.get_language_id(bufnr, vim.bo[bufnr].filetype) local uri = vim.uri_from_bufnr(bufnr) local fname = vim.uri_to_fname(uri) for _, filter in ipairs(documentSelector) do local matches = true - if filter.language and ft ~= filter.language then + if filter.language and language ~= filter.language then matches = false end if matches and filter.scheme and not vim.startswith(uri, filter.scheme .. ':') then -- cgit From 5f9d4d8afeb5dc3d5df4965c24cbb4c6e01694f7 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 25 Dec 2023 21:28:28 +0100 Subject: refactor: use vim.deprecate on all deprecated functions --- runtime/lua/vim/lsp/buf.lua | 2 +- runtime/lua/vim/lsp/util.lua | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 2f754444e9..051b9d4550 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -34,7 +34,7 @@ end ---@return boolean if server responds. ---@deprecated function M.server_ready() - vim.deprecate('vim.lsp.buf.server_ready', nil, '0.10.0') + vim.deprecate('vim.lsp.buf.server_ready()', nil, '0.10') return not not vim.lsp.buf_notify(0, 'window/progress', {}) end diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 63c4c1e7fc..ba7ce3c2b6 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -180,6 +180,7 @@ local _str_byteindex_enc = M._str_byteindex_enc ---@param new_lines (table) list of strings to replace the original ---@return table The modified {lines} object function M.set_lines(lines, A, B, new_lines) + vim.deprecate('vim.lsp.util.set_lines()', 'nil', '0.12') -- 0-indexing to 1-indexing local i_0 = A[1] + 1 -- If it extends past the end, truncate it to the end. This is because the @@ -346,7 +347,7 @@ end ---@private ---@deprecated Use vim.lsp.status() or access client.progress directly function M.get_progress_messages() - vim.deprecate('vim.lsp.util.get_progress_messages', 'vim.lsp.status', '0.11.0') + vim.deprecate('vim.lsp.util.get_progress_messages()', 'vim.lsp.status()', '0.11') local new_messages = {} local progress_remove = {} @@ -552,7 +553,7 @@ end ---@return lsp.CompletionItem[] List of completion items ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion function M.extract_completion_items(result) - vim.deprecate('vim.lsp.util.extract_completion_items', nil, '0.11') + vim.deprecate('vim.lsp.util.extract_completion_items()', nil, '0.11') if type(result) == 'table' and result.items then -- result is a `CompletionList` return result.items @@ -612,7 +613,7 @@ end ---@param input string unparsed snippet ---@return string parsed snippet function M.parse_snippet(input) - vim.deprecate('vim.lsp.util.parse_snippet', nil, '0.11') + vim.deprecate('vim.lsp.util.parse_snippet()', nil, '0.11') local ok, parsed = pcall(function() return snippet.parse(input) end) @@ -634,7 +635,7 @@ end ---@return table[] items ---@see complete-items function M.text_document_completion_list_to_complete_items(result, prefix) - vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items', nil, '0.11') + vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.11') return require('vim.lsp._completion')._lsp_to_complete_items(result, prefix) end @@ -1885,6 +1886,7 @@ end ---@param lines table list of lines to trim ---@return table trimmed list of lines function M.trim_empty_lines(lines) + vim.deprecate('vim.lsp.util.trim_empty_lines()', 'vim.split() with `trimempty`', '0.12') local start = 1 for i = 1, #lines do if lines[i] ~= nil and #lines[i] > 0 then @@ -1911,6 +1913,7 @@ end ---@param lines table list of lines ---@return string filetype or "markdown" if it was unchanged. function M.try_trim_markdown_code_blocks(lines) + vim.deprecate('vim.lsp.util.try_trim_markdown_code_blocks()', 'nil', '0.12') local language_id = lines[1]:match('^```(.*)') if language_id then local has_inner_code_fence = false -- cgit From 5cb906e91cb56302d0737aa80e2d890dde452029 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 26 Dec 2023 15:16:45 +0100 Subject: fix: correct versions in deprecation warnings The following functions should be removed in 0.12 according to the deprecation strategy in MAINTAIN.md: - vim.lsp.util.extract_completion_items() - vim.lsp.util.parse_snippet() - vim.lsp.util.text_document_completion_list_to_complete_items() --- runtime/lua/vim/lsp/util.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index ba7ce3c2b6..90e2f28ef4 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -553,7 +553,7 @@ end ---@return lsp.CompletionItem[] List of completion items ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion function M.extract_completion_items(result) - vim.deprecate('vim.lsp.util.extract_completion_items()', nil, '0.11') + vim.deprecate('vim.lsp.util.extract_completion_items()', nil, '0.12') if type(result) == 'table' and result.items then -- result is a `CompletionList` return result.items @@ -613,7 +613,7 @@ end ---@param input string unparsed snippet ---@return string parsed snippet function M.parse_snippet(input) - vim.deprecate('vim.lsp.util.parse_snippet()', nil, '0.11') + vim.deprecate('vim.lsp.util.parse_snippet()', nil, '0.12') local ok, parsed = pcall(function() return snippet.parse(input) end) @@ -635,7 +635,7 @@ end ---@return table[] items ---@see complete-items function M.text_document_completion_list_to_complete_items(result, prefix) - vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.11') + vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.12') return require('vim.lsp._completion')._lsp_to_complete_items(result, prefix) end -- cgit From 3767468b9615b617e252e9e9498e070087fe570f Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Mon, 11 Dec 2023 00:05:24 -0500 Subject: docs(gen_lsp.lua): re-generate vim.lsp._meta.protocol type annotations The purpose of this commit is to make diff clean and easy to read; to see the diff resulted from actual changes in gen_lsp.lua, not from the updated LSP protocol JSON data. Ran: `nvim -l scripts/gen_lsp.lua gen --methods` Based on 3.18.0 (2023-12-23) --- runtime/lua/vim/lsp/_meta/protocol.lua | 127 ++++++++++++++++++++++++++------- runtime/lua/vim/lsp/protocol.lua | 44 ++++++------ 2 files changed, 122 insertions(+), 49 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua index 979dad84fd..dc7970c1b4 100644 --- a/runtime/lua/vim/lsp/_meta/protocol.lua +++ b/runtime/lua/vim/lsp/_meta/protocol.lua @@ -472,6 +472,9 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@class lsp.InlayHint ---The position of this hint. +--- +---If multiple hints have the same position, they will be shown in the order +---they appear in the response. ---@field position lsp.Position ---The label of this hint. A human readable string or an array of ---InlayHintLabelPart label parts. @@ -614,12 +617,16 @@ error('Cannot require a meta file') ---A parameter literal used in inline completion requests. --- ---@since 3.18.0 +---@proposed ---@class lsp.InlineCompletionParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams ---Additional information about the context in which inline completions were ---requested. ---@field context lsp.InlineCompletionContext ---Represents a collection of {@link InlineCompletionItem inline completion items} to be presented in the editor. +--- +---@since 3.18.0 +---@proposed ---@class lsp.InlineCompletionList ---The inline completion items ---@field items lsp.InlineCompletionItem[] @@ -627,11 +634,10 @@ error('Cannot require a meta file') ---An inline completion item represents a text snippet that is proposed inline to complete text that is being typed. --- ---@since 3.18.0 +---@proposed ---@class lsp.InlineCompletionItem ---The text to replace the range with. Must be set. ----@field insertText string ----The format of the insert text. The format applies to the `insertText`. If omitted defaults to `InsertTextFormat.PlainText`. ----@field insertTextFormat? lsp.InsertTextFormat +---@field insertText string|lsp.StringValue ---A text that is used to decide if this inline completion should be shown. When `falsy` the {@link InlineCompletionItem.insertText} is used. ---@field filterText? string ---The range to replace. Must begin and end on the same line. @@ -642,6 +648,7 @@ error('Cannot require a meta file') ---Inline completion options used during static or dynamic registration. --- ---@since 3.18.0 +---@proposed ---@class lsp.InlineCompletionRegistrationOptions: lsp.InlineCompletionOptions, lsp.StaticRegistrationOptions ---@class lsp.RegistrationParams @@ -981,14 +988,23 @@ error('Cannot require a meta file') ---In future version of the protocol this property might become ---mandatory to better express this. ---@field activeSignature? uinteger ----The active parameter of the active signature. If omitted or the value ----lies outside the range of `signatures[activeSignature].parameters` ----defaults to 0 if the active signature has parameters. If ----the active signature has no parameters it is ignored. +---The active parameter of the active signature. +--- +---If `null`, no parameter of the signature is active (for example a named +---argument that does not match any declared parameters). This is only valid +---since 3.18.0 and if the client specifies the client capability +---`textDocument.signatureHelp.noActiveParameterSupport === true` +--- +---If omitted or the value lies outside the range of +---`signatures[activeSignature].parameters` defaults to 0 if the active +---signature has parameters. +--- +---If the active signature has no parameters it is ignored. +--- ---In future version of the protocol this property might become ----mandatory to better express the active parameter if the ----active signature does have any. ----@field activeParameter? uinteger +---mandatory (but still nullable) to better express the active parameter if +---the active signature does have any. +---@field activeParameter? uinteger|lsp.null ---Registration options for a {@link SignatureHelpRequest}. ---@class lsp.SignatureHelpRegistrationOptions: lsp.TextDocumentRegistrationOptions @@ -1192,8 +1208,7 @@ error('Cannot require a meta file') ---The command this code lens represents. ---@field command? lsp.Command ---A data entry field that is preserved on a code lens item between ----a {@link CodeLensRequest} and a [CodeLensResolveRequest] ----(#CodeLensResolveRequest) +---a {@link CodeLensRequest} and a {@link CodeLensResolveRequest} ---@field data? lsp.LSPAny ---Registration options for a {@link CodeLensRequest}. @@ -1470,7 +1485,7 @@ error('Cannot require a meta file') ---@class lsp.ConfigurationItem ---The scope to get the configuration section for. ----@field scopeUri? string +---@field scopeUri? lsp.URI ---The configuration section asked for. ---@field section? string @@ -1503,14 +1518,14 @@ error('Cannot require a meta file') ---offset of b is 3 since `𐐀` is represented using two code units in UTF-16. ---Since 3.17 clients and servers can agree on a different string encoding ---representation (e.g. UTF-8). The client announces it's supported encoding ----via the client capability [`general.positionEncodings`](#clientCapabilities). +---via the client capability [`general.positionEncodings`](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#clientCapabilities). ---The value is an array of position encodings the client supports, with ---decreasing preference (e.g. the encoding at index `0` is the most preferred ---one). To stay backwards compatible the only mandatory encoding is UTF-16 ---represented via the string `utf-16`. The server can pick one of the ---encodings offered by the client and signals that encoding back to the ---client via the initialize result's property ----[`capabilities.positionEncoding`](#serverCapabilities). If the string value +---[`capabilities.positionEncoding`](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#serverCapabilities). If the string value ---`utf-16` is missing from the client's capability `general.positionEncodings` ---servers can safely assume that the client supports UTF-16. If the server ---omits the position encoding in its initialize result the encoding defaults @@ -1915,18 +1930,36 @@ error('Cannot require a meta file') ---Provides information about the context in which an inline completion was requested. --- ---@since 3.18.0 +---@proposed ---@class lsp.InlineCompletionContext ---Describes how the inline completion was triggered. ---@field triggerKind lsp.InlineCompletionTriggerKind ---Provides information about the currently selected item in the autocomplete widget if it is visible. ---@field selectedCompletionInfo? lsp.SelectedCompletionInfo +---A string value used as a snippet is a template which allows to insert text +---and to control the editor cursor when insertion happens. +--- +---A snippet can define tab stops and placeholders with `$1`, `$2` +---and `${3:foo}`. `$0` defines the final tab stop, it defaults to +---the end of the snippet. Variables are defined with `$name` and +---`${name:default value}`. +--- +---@since 3.18.0 +---@proposed +---@class lsp.StringValue +---The kind of string value. +---@field kind "snippet" +---The snippet string. +---@field value string + ---Inline completion options used during static registration. --- ---@since 3.18.0 +---@proposed ---@class lsp.InlineCompletionOptions ----General parameters to to register for an notification or to register a provider. +---General parameters to register for a notification or to register a provider. ---@class lsp.Registration ---The id used to register the request. The id can be used to deregister ---the request again. @@ -2097,6 +2130,7 @@ error('Cannot require a meta file') ---Inline completion options used during static registration. --- ---@since 3.18.0 +---@proposed ---@field inlineCompletionProvider? boolean|lsp.InlineCompletionOptions ---Workspace specific server capabilities. ---@field workspace? anonym12 @@ -2261,10 +2295,16 @@ error('Cannot require a meta file') ---@field parameters? lsp.ParameterInformation[] ---The index of the active parameter. --- ----If provided, this is used in place of `SignatureHelp.activeParameter`. +---If `null`, no parameter of the signature is active (for example a named +---argument that does not match any declared parameters). This is only valid +---since 3.18.0 and if the client specifies the client capability +---`textDocument.signatureHelp.noActiveParameterSupport === true` +--- +---If provided (or `null`), this is used in place of +---`SignatureHelp.activeParameter`. --- ---@since 3.16.0 ----@field activeParameter? uinteger +---@field activeParameter? uinteger|lsp.null ---Server Capabilities for a {@link SignatureHelpRequest}. ---@class lsp.SignatureHelpOptions @@ -2545,6 +2585,7 @@ error('Cannot require a meta file') ---Describes the currently selected completion item. --- ---@since 3.18.0 +---@proposed ---@class lsp.SelectedCompletionInfo ---The range that will be replaced if this completion item is accepted. ---@field range lsp.Range @@ -2758,6 +2799,11 @@ error('Cannot require a meta file') --- ---@since 3.17.0. ---@field diagnostics? lsp.DiagnosticWorkspaceClientCapabilities +---Capabilities specific to the folding range requests scoped to the workspace. +--- +---@since 3.18.0 +---@proposed +---@field foldingRange? lsp.FoldingRangeWorkspaceClientCapabilities ---Text document specific client capabilities. ---@class lsp.TextDocumentClientCapabilities @@ -2853,6 +2899,7 @@ error('Cannot require a meta file') ---Client capabilities specific to inline completions. --- ---@since 3.18.0 +---@proposed ---@field inlineCompletion? lsp.InlineCompletionClientCapabilities ---Capabilities specific to the notebook document support. @@ -3083,6 +3130,23 @@ error('Cannot require a meta file') ---change that requires such a calculation. ---@field refreshSupport? boolean +---Client workspace capabilities specific to folding ranges +--- +---@since 3.18.0 +---@proposed +---@class lsp.FoldingRangeWorkspaceClientCapabilities +---Whether the client implementation supports a refresh request sent from the +---server to the client. +--- +---Note that this event is global and will force the client to refresh all +---folding ranges currently shown. It should be used with absolute care and is +---useful for situation where a server for example detects a project wide +---change that requires such a calculation. +--- +---@since 3.18.0 +---@proposed +---@field refreshSupport? boolean + ---@class lsp.TextDocumentSyncClientCapabilities ---Whether text document synchronization supports dynamic registration. ---@field dynamicRegistration? boolean @@ -3474,6 +3538,7 @@ error('Cannot require a meta file') ---Client capabilities specific to inline completions. --- ---@since 3.18.0 +---@proposed ---@class lsp.InlineCompletionClientCapabilities ---Whether implementation supports dynamic registration for inline completion providers. ---@field dynamicRegistration? boolean @@ -3662,18 +3727,13 @@ error('Cannot require a meta file') ---| 1 # Type ---| 2 # Parameter ----Defines whether the insert text in a completion item should be interpreted as ----plain text or a snippet. ----@alias lsp.InsertTextFormat ----| 1 # PlainText ----| 2 # Snippet - ---The message type ---@alias lsp.MessageType ---| 1 # Error ---| 2 # Warning ---| 3 # Info ---| 4 # Log +---| 5 # Debug ---Defines how the host (editor) should sync ---document changes to the language server. @@ -3723,6 +3783,12 @@ error('Cannot require a meta file') ---@alias lsp.CompletionItemTag ---| 1 # Deprecated +---Defines whether the insert text in a completion item should be interpreted as +---plain text or a snippet. +---@alias lsp.InsertTextFormat +---| 1 # PlainText +---| 2 # Snippet + ---How whitespace and indentation is handled during completion ---item insertion. --- @@ -3766,6 +3832,7 @@ error('Cannot require a meta file') ---Describes how an {@link InlineCompletionItemProvider inline completion provider} was triggered. --- ---@since 3.18.0 +---@proposed ---@alias lsp.InlineCompletionTriggerKind ---| 0 # Invoked ---| 1 # Automatic @@ -4247,6 +4314,12 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@field activeParameterSupport? boolean +---The client supports the `activeParameter` property on +---`SignatureInformation` being set to `null` to indicate that no +---parameter should be active. +--- +---@since 3.18.0 +---@field noActiveParameterSupport? boolean ---@class anonym31 ---The symbol kind values the client supports. When this @@ -4352,7 +4425,7 @@ error('Cannot require a meta file') ---@field language string ---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ---@field scheme? string ----A glob pattern, like `*.{ts,js}`. +---A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. ---@field pattern? string ---@class anonym50 @@ -4360,7 +4433,7 @@ error('Cannot require a meta file') ---@field language? string ---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ---@field scheme string ----A glob pattern, like `*.{ts,js}`. +---A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. ---@field pattern? string ---@class anonym51 @@ -4368,7 +4441,7 @@ error('Cannot require a meta file') ---@field language? string ---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ---@field scheme? string ----A glob pattern, like `*.{ts,js}`. +---A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. ---@field pattern string ---@class anonym52 diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index b2a92cd1ee..df12c36396 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -934,7 +934,7 @@ end -- Generated by gen_lsp.lua, keep at end of file. --- LSP method names. --- ----@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#metaModel +---@see https://microsoft.github.io/language-server-protocol/specification/#metaModel protocol.Methods = { --- A request to resolve the incoming calls for a given `CallHierarchyItem`. --- @since 3.16.0 @@ -1021,16 +1021,14 @@ protocol.Methods = { --- `filterText`, `insertText`, and `textEdit`, must not be changed during resolve. textDocument_completion = 'textDocument/completion', --- A request to resolve the type definition locations of a symbol at a given text - --- document position. The request's parameter is of type [TextDocumentPositionParams] - --- (#TextDocumentPositionParams) the response is of type {@link Declaration} - --- or a typed array of {@link DeclarationLink} or a Thenable that resolves - --- to such. + --- document position. The request's parameter is of type {@link TextDocumentPositionParams} + --- the response is of type {@link Declaration} or a typed array of {@link DeclarationLink} + --- or a Thenable that resolves to such. textDocument_declaration = 'textDocument/declaration', --- A request to resolve the definition location of a symbol at a given text - --- document position. The request's parameter is of type [TextDocumentPosition] - --- (#TextDocumentPosition) the response is of either type {@link Definition} - --- or a typed array of {@link DefinitionLink} or a Thenable that resolves - --- to such. + --- document position. The request's parameter is of type {@link TextDocumentPosition} + --- the response is of either type {@link Definition} or a typed array of + --- {@link DefinitionLink} or a Thenable that resolves to such. textDocument_definition = 'textDocument/definition', --- The document diagnostic request definition. --- @since 3.17.0 @@ -1064,9 +1062,9 @@ protocol.Methods = { --- that resolves to such. textDocument_documentColor = 'textDocument/documentColor', --- Request to resolve a {@link DocumentHighlight} for a given - --- text document position. The request's parameter is of type [TextDocumentPosition] - --- (#TextDocumentPosition) the request response is of type [DocumentHighlight[]] - --- (#DocumentHighlight) or a Thenable that resolves to such. + --- text document position. The request's parameter is of type {@link TextDocumentPosition} + --- the request response is an array of type {@link DocumentHighlight} + --- or a Thenable that resolves to such. textDocument_documentHighlight = 'textDocument/documentHighlight', --- A request to provide document links textDocument_documentLink = 'textDocument/documentLink', @@ -1080,16 +1078,15 @@ protocol.Methods = { --- response is of type {@link FoldingRangeList} or a Thenable --- that resolves to such. textDocument_foldingRange = 'textDocument/foldingRange', - --- A request to to format a whole document. + --- A request to format a whole document. textDocument_formatting = 'textDocument/formatting', --- Request to request hover information at a given text document position. The request's --- parameter is of type {@link TextDocumentPosition} the response is of --- type {@link Hover} or a Thenable that resolves to such. textDocument_hover = 'textDocument/hover', --- A request to resolve the implementation locations of a symbol at a given text - --- document position. The request's parameter is of type [TextDocumentPositionParams] - --- (#TextDocumentPositionParams) the response is of type {@link Definition} or a - --- Thenable that resolves to such. + --- document position. The request's parameter is of type {@link TextDocumentPositionParams} + --- the response is of type {@link Definition} or a Thenable that resolves to such. textDocument_implementation = 'textDocument/implementation', --- A request to provide inlay hints in a document. The request's parameter is of --- type {@link InlayHintsParams}, the response is of type @@ -1100,6 +1097,7 @@ protocol.Methods = { --- type {@link InlineCompletionParams}, the response is of type --- {@link InlineCompletion InlineCompletion[]} or a Thenable that resolves to such. --- @since 3.18.0 + --- @proposed textDocument_inlineCompletion = 'textDocument/inlineCompletion', --- A request to provide inline values in a document. The request's parameter is of --- type {@link InlineValueParams}, the response is of type @@ -1155,9 +1153,8 @@ protocol.Methods = { textDocument_semanticTokens_range = 'textDocument/semanticTokens/range', textDocument_signatureHelp = 'textDocument/signatureHelp', --- A request to resolve the type definition locations of a symbol at a given text - --- document position. The request's parameter is of type [TextDocumentPositionParams] - --- (#TextDocumentPositionParams) the response is of type {@link Definition} or a - --- Thenable that resolves to such. + --- document position. The request's parameter is of type {@link TextDocumentPositionParams} + --- the response is of type {@link Definition} or a Thenable that resolves to such. textDocument_typeDefinition = 'textDocument/typeDefinition', --- A document will save notification is sent from the client to the server before --- the document is actually saved. @@ -1200,14 +1197,14 @@ protocol.Methods = { --- symbol's location. --- @since 3.17.0 workspaceSymbol_resolve = 'workspaceSymbol/resolve', - --- A request sent from the server to the client to modified certain resources. + --- A request sent from the server to the client to modify certain resources. workspace_applyEdit = 'workspace/applyEdit', --- A request to refresh all code actions --- @since 3.16.0 workspace_codeLens_refresh = 'workspace/codeLens/refresh', --- The 'workspace/configuration' request is sent from the server to the client to fetch a certain --- configuration setting. - --- This pull model replaces the old push model were the client signaled configuration change via an + --- This pull model replaces the old push model where the client signaled configuration change via an --- event. If the server still needs to react to configuration changes (since the server caches the --- result of `workspace/configuration` requests) the server should register for an empty configuration --- change event and empty the cache if such an event is received. @@ -1240,9 +1237,12 @@ protocol.Methods = { --- files were renamed from within the client. --- @since 3.16.0 workspace_didRenameFiles = 'workspace/didRenameFiles', - --- A request send from the client to the server to execute a command. The request might return + --- A request sent from the client to the server to execute a command. The request might return --- a workspace edit which the client will apply to the workspace. workspace_executeCommand = 'workspace/executeCommand', + --- @since 3.18.0 + --- @proposed + workspace_foldingRange_refresh = 'workspace/foldingRange/refresh', --- @since 3.17.0 workspace_inlayHint_refresh = 'workspace/inlayHint/refresh', --- @since 3.17.0 -- cgit From 6c35fb421e888d0cbdfac07a5ff4579c9be7f0ec Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Mon, 11 Dec 2023 02:25:17 -0500 Subject: fix(gen_lsp.lua): improve type name, and fix wrong type inheritance Style improvements: 1. Anonymous classes derived from `StructureLiteralType` should have a better name. The class name can be also nested. Examples: ```diff ----@field serverInfo? anonym1 +---@field serverInfo? lsp._anonym1.serverInfo ``` ```diff ----@field insertTextModeSupport? anonym26 +---@field insertTextModeSupport? lsp._anonym26.completionItem.insertTextModeSupport ``` 2. Add one separate empty line before each `@field` definition. Without these, empty lines the doc can look confusing because descriptions also may contain empty lines. See `lsp.CompletionItem` for example: ```lua ---The kind of this completion item. Based of the kind ---an icon is chosen by the editor. ---@field kind? lsp.CompletionItemKind ---Tags for this completion item. --- ---@since 3.15.0 ---@field tags? lsp.CompletionItemTag[] ``` It might feel like "Tags for this completion item" belongs to `kind`, not `tags` due to the lack of separator blank lines. The following (after this commit) should look much better: ```diff ---The kind of this completion item. Based of the kind ---an icon is chosen by the editor. ---@field kind? lsp.CompletionItemKind +--- ---Tags for this completion item. --- ---@since 3.15.0 ---@field tags? lsp.CompletionItemTag[] ``` 3. Escape some LSP-specific annotations that can't be recognized by lua-ls. It'd be better to make them visible in LSP hover doc windows. Example: `@sample ...`. Fixes: 1. A type may extend from more than one base types (as well as mixin types). Previously only the first base class was being considered, resulting incomplete base classes for `@class` definitions. Example: `InlayHintOptions` (should have both of `resolveProvider` and `workDoneProgress`, the latter is from `WorkDoneProgressOptions`) ```diff ----@class lsp.InlayHintOptions +---@class lsp.InlayHintOptions: lsp.WorkDoneProgressOptions ``` 2. Remove `<200b>` (zero-width space) unicode characters. 3. Add the missing newline at EOF. --- runtime/lua/vim/lsp/_meta/protocol.lua | 1182 ++++++++++++++++++++++++++------ 1 file changed, 985 insertions(+), 197 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua index dc7970c1b4..4c053cb57e 100644 --- a/runtime/lua/vim/lsp/_meta/protocol.lua +++ b/runtime/lua/vim/lsp/_meta/protocol.lua @@ -21,99 +21,123 @@ error('Cannot require a meta file') ---Represents a location inside a resource, such as a line ---inside a text file. ---@class lsp.Location +--- ---@field uri lsp.DocumentUri +--- ---@field range lsp.Range ----@class lsp.ImplementationRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions +---@class lsp.ImplementationRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.ImplementationOptions, lsp.StaticRegistrationOptions ---@class lsp.TypeDefinitionParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams, lsp.PartialResultParams ----@class lsp.TypeDefinitionRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions +---@class lsp.TypeDefinitionRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.TypeDefinitionOptions, lsp.StaticRegistrationOptions ---A workspace folder inside a client. ---@class lsp.WorkspaceFolder +--- ---The associated URI for this workspace folder. ---@field uri lsp.URI +--- ---The name of the workspace folder. Used to refer to this ---workspace folder in the user interface. ---@field name string ---The parameters of a `workspace/didChangeWorkspaceFolders` notification. ---@class lsp.DidChangeWorkspaceFoldersParams +--- ---The actual workspace folder change event. ---@field event lsp.WorkspaceFoldersChangeEvent ---The parameters of a configuration request. ---@class lsp.ConfigurationParams +--- ---@field items lsp.ConfigurationItem[] ---Parameters for a {@link DocumentColorRequest}. ----@class lsp.DocumentColorParams +---@class lsp.DocumentColorParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier ---Represents a color range from a document. ---@class lsp.ColorInformation +--- ---The range in the document where this color appears. ---@field range lsp.Range +--- ---The actual color value for this color range. ---@field color lsp.Color ----@class lsp.DocumentColorRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions +---@class lsp.DocumentColorRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.DocumentColorOptions, lsp.StaticRegistrationOptions ---Parameters for a {@link ColorPresentationRequest}. ----@class lsp.ColorPresentationParams +---@class lsp.ColorPresentationParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The color to request presentations for. ---@field color lsp.Color +--- ---The range where the color would be inserted. Serves as a context. ---@field range lsp.Range ---@class lsp.ColorPresentation +--- ---The label of this color presentation. It will be shown on the color ---picker header. By default this is also the text that is inserted when selecting ---this color presentation. ---@field label string +--- ---An {@link TextEdit edit} which is applied to a document when selecting ---this presentation for the color. When `falsy` the {@link ColorPresentation.label label} ---is used. ---@field textEdit? lsp.TextEdit +--- ---An optional array of additional {@link TextEdit text edits} that are applied when ---selecting this color presentation. Edits must not overlap with the main {@link ColorPresentation.textEdit edit} nor with themselves. ---@field additionalTextEdits? lsp.TextEdit[] ---@class lsp.WorkDoneProgressOptions +--- ---@field workDoneProgress? boolean ---General text document registration options. ---@class lsp.TextDocumentRegistrationOptions +--- ---A document selector to identify the scope of the registration. If set to null ---the document selector provided on the client side will be used. ---@field documentSelector lsp.DocumentSelector|lsp.null ---Parameters for a {@link FoldingRangeRequest}. ----@class lsp.FoldingRangeParams +---@class lsp.FoldingRangeParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier ---Represents a folding range. To be valid, start and end line must be bigger than zero and smaller ---than the number of lines in the document. Clients are free to ignore invalid ranges. ---@class lsp.FoldingRange +--- ---The zero-based start line of the range to fold. The folded area starts after the line's last character. ---To be valid, the end must be zero or larger and smaller than the number of lines in the document. ---@field startLine uinteger +--- ---The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. ---@field startCharacter? uinteger +--- ---The zero-based end line of the range to fold. The folded area ends with the line's last character. ---To be valid, the end must be zero or larger and smaller than the number of lines in the document. ---@field endLine uinteger +--- ---The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. ---@field endCharacter? uinteger +--- ---Describes the kind of the folding range such as `comment' or 'region'. The kind ---is used to categorize folding ranges and used by commands like 'Fold all comments'. ---See {@link FoldingRangeKind} for an enumeration of standardized kinds. ---@field kind? lsp.FoldingRangeKind +--- ---The text that the client should show when the specified range is ---collapsed. If not defined or not supported by the client, a default ---will be chosen by the client. @@ -121,34 +145,40 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@field collapsedText? string ----@class lsp.FoldingRangeRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions +---@class lsp.FoldingRangeRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.FoldingRangeOptions, lsp.StaticRegistrationOptions ---@class lsp.DeclarationParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams, lsp.PartialResultParams ----@class lsp.DeclarationRegistrationOptions: lsp.DeclarationOptions, lsp.StaticRegistrationOptions +---@class lsp.DeclarationRegistrationOptions: lsp.DeclarationOptions, lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions ---A parameter literal used in selection range requests. ----@class lsp.SelectionRangeParams +---@class lsp.SelectionRangeParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The positions inside the text document. ---@field positions lsp.Position[] ---A selection range represents a part of a selection hierarchy. A selection range ---may have a parent selection range that contains it. ---@class lsp.SelectionRange +--- ---The {@link Range range} of this selection range. ---@field range lsp.Range +--- ---The parent selection range containing this range. Therefore `parent.range` must contain `this.range`. ---@field parent? lsp.SelectionRange ----@class lsp.SelectionRangeRegistrationOptions: lsp.SelectionRangeOptions, lsp.StaticRegistrationOptions +---@class lsp.SelectionRangeRegistrationOptions: lsp.SelectionRangeOptions, lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions ---@class lsp.WorkDoneProgressCreateParams +--- ---The token to be used to report progress. ---@field token lsp.ProgressToken ---@class lsp.WorkDoneProgressCancelParams +--- ---The token to be used to report progress. ---@field token lsp.ProgressToken @@ -162,21 +192,29 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.CallHierarchyItem +--- ---The name of this item. ---@field name string +--- ---The kind of this item. ---@field kind lsp.SymbolKind +--- ---Tags for this item. ---@field tags? lsp.SymbolTag[] +--- ---More detail for this item, e.g. the signature of a function. ---@field detail? string +--- ---The resource identifier of this item. ---@field uri lsp.DocumentUri +--- ---The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. ---@field range lsp.Range +--- ---The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. ---Must be contained by the {@link CallHierarchyItem.range `range`}. ---@field selectionRange lsp.Range +--- ---A data entry field that is preserved between a call hierarchy prepare and ---incoming calls or outgoing calls requests. ---@field data? lsp.LSPAny @@ -184,20 +222,23 @@ error('Cannot require a meta file') ---Call hierarchy options used during static or dynamic registration. --- ---@since 3.16.0 ----@class lsp.CallHierarchyRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions +---@class lsp.CallHierarchyRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.CallHierarchyOptions, lsp.StaticRegistrationOptions ---The parameter of a `callHierarchy/incomingCalls` request. --- ---@since 3.16.0 ----@class lsp.CallHierarchyIncomingCallsParams +---@class lsp.CallHierarchyIncomingCallsParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---@field item lsp.CallHierarchyItem ---Represents an incoming call, e.g. a caller of a method or constructor. --- ---@since 3.16.0 ---@class lsp.CallHierarchyIncomingCall +--- ---The item that makes the call. ---@field from lsp.CallHierarchyItem +--- ---The ranges at which the calls appear. This is relative to the caller ---denoted by {@link CallHierarchyIncomingCall.from `this.from`}. ---@field fromRanges lsp.Range[] @@ -205,64 +246,78 @@ error('Cannot require a meta file') ---The parameter of a `callHierarchy/outgoingCalls` request. --- ---@since 3.16.0 ----@class lsp.CallHierarchyOutgoingCallsParams +---@class lsp.CallHierarchyOutgoingCallsParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---@field item lsp.CallHierarchyItem ---Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. --- ---@since 3.16.0 ---@class lsp.CallHierarchyOutgoingCall +--- ---The item that is called. ---@field to lsp.CallHierarchyItem +--- ---The range at which this item is called. This is the range relative to the caller, e.g the item ---passed to {@link CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls `provideCallHierarchyOutgoingCalls`} ---and not {@link CallHierarchyOutgoingCall.to `this.to`}. ---@field fromRanges lsp.Range[] ---@since 3.16.0 ----@class lsp.SemanticTokensParams +---@class lsp.SemanticTokensParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier ---@since 3.16.0 ---@class lsp.SemanticTokens +--- ---An optional result id. If provided and clients support delta updating ---the client will include the result id in the next semantic token request. ---A server can then instead of computing all semantic tokens again simply ---send a delta. ---@field resultId? string +--- ---The actual tokens. ---@field data uinteger[] ---@since 3.16.0 ---@class lsp.SemanticTokensPartialResult +--- ---@field data uinteger[] ---@since 3.16.0 ----@class lsp.SemanticTokensRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions +---@class lsp.SemanticTokensRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.SemanticTokensOptions, lsp.StaticRegistrationOptions ---@since 3.16.0 ----@class lsp.SemanticTokensDeltaParams +---@class lsp.SemanticTokensDeltaParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The result id of a previous response. The result Id can either point to a full response ---or a delta response depending on what was received last. ---@field previousResultId string ---@since 3.16.0 ---@class lsp.SemanticTokensDelta +--- ---@field resultId? string +--- ---The semantic token edits to transform a previous result into a new result. ---@field edits lsp.SemanticTokensEdit[] ---@since 3.16.0 ---@class lsp.SemanticTokensDeltaPartialResult +--- ---@field edits lsp.SemanticTokensEdit[] ---@since 3.16.0 ----@class lsp.SemanticTokensRangeParams +---@class lsp.SemanticTokensRangeParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The range the semantic tokens are requested for. ---@field range lsp.Range @@ -270,17 +325,21 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.ShowDocumentParams +--- ---The uri to show. ---@field uri lsp.URI +--- ---Indicates to show the resource in an external program. ---To show, for example, `https://code.visualstudio.com/` ---in the default WEB browser set `external` to `true`. ---@field external? boolean +--- ---An optional property to indicate whether the editor ---showing the document should take focus or not. ---Clients might ignore this property if an external ---program is started. ---@field takeFocus? boolean +--- ---An optional selection range if the document is a text ---document. Clients might ignore the property if an ---external program is started or the file is not a text @@ -291,6 +350,7 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.ShowDocumentResult +--- ---A boolean indicating if the show was successful. ---@field success boolean @@ -300,21 +360,24 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.LinkedEditingRanges +--- ---A list of ranges that can be edited together. The ranges must have ---identical length and contain identical text content. The ranges cannot overlap. ---@field ranges lsp.Range[] +--- ---An optional word pattern (regular expression) that describes valid contents for ---the given ranges. If no pattern is provided, the client configuration's word ---pattern will be used. ---@field wordPattern? string ----@class lsp.LinkedEditingRangeRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions +---@class lsp.LinkedEditingRangeRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.LinkedEditingRangeOptions, lsp.StaticRegistrationOptions ---The parameters sent in notifications/requests for user-initiated creation of ---files. --- ---@since 3.16.0 ---@class lsp.CreateFilesParams +--- ---An array of all files/folders created in this operation. ---@field files lsp.FileCreate[] @@ -331,8 +394,10 @@ error('Cannot require a meta file') ---cause failure of the operation. How the client recovers from the failure is described by ---the client capability: `workspace.workspaceEdit.failureHandling` ---@class lsp.WorkspaceEdit +--- ---Holds changes to existing resources. ---@field changes? table +--- ---Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes ---are either an array of `TextDocumentEdit`s to express changes to n different text documents ---where each text document edit addresses a specific version of a text document. Or it can contain @@ -344,6 +409,7 @@ error('Cannot require a meta file') ---If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then ---only plain `TextEdit`s using the `changes` property are supported. ---@field documentChanges? lsp.TextDocumentEdit|lsp.CreateFile|lsp.RenameFile|lsp.DeleteFile[] +--- ---A map of change annotations that can be referenced in `AnnotatedTextEdit`s or create, rename and ---delete file / folder operations. --- @@ -356,6 +422,7 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.FileOperationRegistrationOptions +--- ---The actual filters. ---@field filters lsp.FileOperationFilter[] @@ -364,6 +431,7 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.RenameFilesParams +--- ---An array of all files/folders renamed in this operation. When a folder is renamed, only ---the folder will be included, and not its children. ---@field files lsp.FileRename[] @@ -373,6 +441,7 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.DeleteFilesParams +--- ---An array of all files/folders deleted in this operation. ---@field files lsp.FileDelete[] @@ -382,17 +451,21 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.Moniker +--- ---The scheme of the moniker. For example tsc or .Net ---@field scheme string +--- ---The identifier of the moniker. The value is opaque in LSIF however ---schema owners are allowed to define the structure if they want. ---@field identifier string +--- ---The scope in which the moniker is unique ---@field unique lsp.UniquenessLevel +--- ---The moniker kind if known. ---@field kind? lsp.MonikerKind ----@class lsp.MonikerRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.MonikerRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.MonikerOptions ---The parameter of a `textDocument/prepareTypeHierarchy` request. --- @@ -401,23 +474,31 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@class lsp.TypeHierarchyItem +--- ---The name of this item. ---@field name string +--- ---The kind of this item. ---@field kind lsp.SymbolKind +--- ---Tags for this item. ---@field tags? lsp.SymbolTag[] +--- ---More detail for this item, e.g. the signature of a function. ---@field detail? string +--- ---The resource identifier of this item. ---@field uri lsp.DocumentUri +--- ---The range enclosing this symbol not including leading/trailing whitespace ---but everything else, e.g. comments and code. ---@field range lsp.Range +--- ---The range that should be selected and revealed when this symbol is being ---picked, e.g. the name of a function. Must be contained by the ---{@link TypeHierarchyItem.range `range`}. ---@field selectionRange lsp.Range +--- ---A data entry field that is preserved between a type hierarchy prepare and ---supertypes or subtypes requests. It could also be used to identify the ---type hierarchy in the server, helping improve the performance on @@ -427,28 +508,33 @@ error('Cannot require a meta file') ---Type hierarchy options used during static or dynamic registration. --- ---@since 3.17.0 ----@class lsp.TypeHierarchyRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions +---@class lsp.TypeHierarchyRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.TypeHierarchyOptions, lsp.StaticRegistrationOptions ---The parameter of a `typeHierarchy/supertypes` request. --- ---@since 3.17.0 ----@class lsp.TypeHierarchySupertypesParams +---@class lsp.TypeHierarchySupertypesParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---@field item lsp.TypeHierarchyItem ---The parameter of a `typeHierarchy/subtypes` request. --- ---@since 3.17.0 ----@class lsp.TypeHierarchySubtypesParams +---@class lsp.TypeHierarchySubtypesParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---@field item lsp.TypeHierarchyItem ---A parameter literal used in inline value requests. --- ---@since 3.17.0 ----@class lsp.InlineValueParams +---@class lsp.InlineValueParams: lsp.WorkDoneProgressParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The document range for which inline values should be computed. ---@field range lsp.Range +--- ---Additional information about the context in which inline values were ---requested. ---@field context lsp.InlineValueContext @@ -456,14 +542,16 @@ error('Cannot require a meta file') ---Inline value options used during static or dynamic registration. --- ---@since 3.17.0 ----@class lsp.InlineValueRegistrationOptions: lsp.InlineValueOptions, lsp.StaticRegistrationOptions +---@class lsp.InlineValueRegistrationOptions: lsp.InlineValueOptions, lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions ---A parameter literal used in inlay hint requests. --- ---@since 3.17.0 ----@class lsp.InlayHintParams +---@class lsp.InlayHintParams: lsp.WorkDoneProgressParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The document range for which inlay hints should be computed. ---@field range lsp.Range @@ -471,39 +559,47 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.InlayHint +--- ---The position of this hint. --- ---If multiple hints have the same position, they will be shown in the order ---they appear in the response. ---@field position lsp.Position +--- ---The label of this hint. A human readable string or an array of ---InlayHintLabelPart label parts. --- ---*Note* that neither the string nor the label part can be empty. ---@field label string|lsp.InlayHintLabelPart[] +--- ---The kind of this hint. Can be omitted in which case the client ---should fall back to a reasonable default. ---@field kind? lsp.InlayHintKind +--- ---Optional text edits that are performed when accepting this inlay hint. --- ---*Note* that edits are expected to change the document so that the inlay ---hint (or its nearest variant) is now part of the document and the inlay ---hint itself is now obsolete. ---@field textEdits? lsp.TextEdit[] +--- ---The tooltip text when you hover over this item. ---@field tooltip? string|lsp.MarkupContent +--- ---Render padding before the hint. --- ---Note: Padding should use the editor's background color, not the ---background color of the hint itself. That means padding can be used ---to visually align/separate an inlay hint. ---@field paddingLeft? boolean +--- ---Render padding after the hint. --- ---Note: Padding should use the editor's background color, not the ---background color of the hint itself. That means padding can be used ---to visually align/separate an inlay hint. ---@field paddingRight? boolean +--- ---A data entry field that is preserved on an inlay hint between ---a `textDocument/inlayHint` and a `inlayHint/resolve` request. ---@field data? lsp.LSPAny @@ -511,16 +607,19 @@ error('Cannot require a meta file') ---Inlay hint options used during static or dynamic registration. --- ---@since 3.17.0 ----@class lsp.InlayHintRegistrationOptions: lsp.InlayHintOptions, lsp.StaticRegistrationOptions +---@class lsp.InlayHintRegistrationOptions: lsp.InlayHintOptions, lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions ---Parameters of the document diagnostic request. --- ---@since 3.17.0 ----@class lsp.DocumentDiagnosticParams +---@class lsp.DocumentDiagnosticParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The additional identifier provided during registration. ---@field identifier? string +--- ---The result id of a previous response if provided. ---@field previousResultId? string @@ -528,25 +627,29 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.DocumentDiagnosticReportPartialResult +--- ---@field relatedDocuments table ---Cancellation data returned from a diagnostic request. --- ---@since 3.17.0 ---@class lsp.DiagnosticServerCancellationData +--- ---@field retriggerRequest boolean ---Diagnostic registration options. --- ---@since 3.17.0 ----@class lsp.DiagnosticRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions +---@class lsp.DiagnosticRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.DiagnosticOptions, lsp.StaticRegistrationOptions ---Parameters of the workspace diagnostic request. --- ---@since 3.17.0 ----@class lsp.WorkspaceDiagnosticParams +---@class lsp.WorkspaceDiagnosticParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The additional identifier provided during registration. ---@field identifier? string +--- ---The currently known diagnostic reports with their ---previous result ids. ---@field previousResultIds lsp.PreviousResultId[] @@ -555,20 +658,24 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.WorkspaceDiagnosticReport +--- ---@field items lsp.WorkspaceDocumentDiagnosticReport[] ---A partial result for a workspace diagnostic report. --- ---@since 3.17.0 ---@class lsp.WorkspaceDiagnosticReportPartialResult +--- ---@field items lsp.WorkspaceDocumentDiagnosticReport[] ---The params sent in an open notebook document notification. --- ---@since 3.17.0 ---@class lsp.DidOpenNotebookDocumentParams +--- ---The notebook document that got opened. ---@field notebookDocument lsp.NotebookDocument +--- ---The text documents that represent the content ---of a notebook cell. ---@field cellTextDocuments lsp.TextDocumentItem[] @@ -577,11 +684,13 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.DidChangeNotebookDocumentParams +--- ---The notebook document that did change. The version number points ---to the version after all provided changes have been applied. If ---only the text document content of a cell changes the notebook version ---doesn't necessarily have to change. ---@field notebookDocument lsp.VersionedNotebookDocumentIdentifier +--- ---The actual changes to the notebook document. --- ---The changes describe single state changes to the notebook document. @@ -601,6 +710,7 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.DidSaveNotebookDocumentParams +--- ---The notebook document that got saved. ---@field notebookDocument lsp.NotebookDocumentIdentifier @@ -608,8 +718,10 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.DidCloseNotebookDocumentParams +--- ---The notebook document that got closed. ---@field notebookDocument lsp.NotebookDocumentIdentifier +--- ---The text documents that represent the content ---of a notebook cell that got closed. ---@field cellTextDocuments lsp.TextDocumentIdentifier[] @@ -619,6 +731,7 @@ error('Cannot require a meta file') ---@since 3.18.0 ---@proposed ---@class lsp.InlineCompletionParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams +--- ---Additional information about the context in which inline completions were ---requested. ---@field context lsp.InlineCompletionContext @@ -628,6 +741,7 @@ error('Cannot require a meta file') ---@since 3.18.0 ---@proposed ---@class lsp.InlineCompletionList +--- ---The inline completion items ---@field items lsp.InlineCompletionItem[] @@ -636,12 +750,16 @@ error('Cannot require a meta file') ---@since 3.18.0 ---@proposed ---@class lsp.InlineCompletionItem +--- ---The text to replace the range with. Must be set. ---@field insertText string|lsp.StringValue +--- ---A text that is used to decide if this inline completion should be shown. When `falsy` the {@link InlineCompletionItem.insertText} is used. ---@field filterText? string +--- ---The range to replace. Must begin and end on the same line. ---@field range? lsp.Range +--- ---An optional {@link Command} that is executed *after* inserting this completion. ---@field command? lsp.Command @@ -649,28 +767,33 @@ error('Cannot require a meta file') --- ---@since 3.18.0 ---@proposed ----@class lsp.InlineCompletionRegistrationOptions: lsp.InlineCompletionOptions, lsp.StaticRegistrationOptions +---@class lsp.InlineCompletionRegistrationOptions: lsp.InlineCompletionOptions, lsp.TextDocumentRegistrationOptions, lsp.StaticRegistrationOptions ---@class lsp.RegistrationParams +--- ---@field registrations lsp.Registration[] ---@class lsp.UnregistrationParams +--- ---@field unregisterations lsp.Unregistration[] ----@class lsp.InitializeParams: lsp._InitializeParams +---@class lsp.InitializeParams: lsp._InitializeParams, lsp.WorkspaceFoldersInitializeParams ---The result returned from an initialize request. ---@class lsp.InitializeResult +--- ---The capabilities the language server provides. ---@field capabilities lsp.ServerCapabilities +--- ---Information about the server. --- ---@since 3.15.0 ----@field serverInfo? anonym1 +---@field serverInfo? lsp._anonym1.serverInfo ---The data type of the ResponseError if the ---initialize request fails. ---@class lsp.InitializeError +--- ---Indicates whether the client execute the following retry logic: ---(1) show the message provided by the ResponseError to the user ---(2) user selects retry or cancel @@ -681,49 +804,62 @@ error('Cannot require a meta file') ---The parameters of a change configuration notification. ---@class lsp.DidChangeConfigurationParams +--- ---The actual changed settings ---@field settings lsp.LSPAny ---@class lsp.DidChangeConfigurationRegistrationOptions +--- ---@field section? string|string[] ---The parameters of a notification message. ---@class lsp.ShowMessageParams +--- ---The message type. See {@link MessageType} ---@field type lsp.MessageType +--- ---The actual message. ---@field message string ---@class lsp.ShowMessageRequestParams +--- ---The message type. See {@link MessageType} ---@field type lsp.MessageType +--- ---The actual message. ---@field message string +--- ---The message action items to present. ---@field actions? lsp.MessageActionItem[] ---@class lsp.MessageActionItem +--- ---A short title like 'Retry', 'Open Log' etc. ---@field title string ---The log message parameters. ---@class lsp.LogMessageParams +--- ---The message type. See {@link MessageType} ---@field type lsp.MessageType +--- ---The actual message. ---@field message string ---The parameters sent in an open text document notification ---@class lsp.DidOpenTextDocumentParams +--- ---The document that was opened. ---@field textDocument lsp.TextDocumentItem ---The change text document notification's parameters. ---@class lsp.DidChangeTextDocumentParams +--- ---The document that did change. The version number points ---to the version after all provided content changes have ---been applied. ---@field textDocument lsp.VersionedTextDocumentIdentifier +--- ---The actual content changes. The content changes describe single state changes ---to the document. So if there are two content changes c1 (at array index 0) and ---c2 (at array index 1) for a document in state S then c1 moves the document from @@ -739,64 +875,78 @@ error('Cannot require a meta file') ---Describe options to be used when registered for text document change events. ---@class lsp.TextDocumentChangeRegistrationOptions: lsp.TextDocumentRegistrationOptions +--- ---How documents are synced to the server. ---@field syncKind lsp.TextDocumentSyncKind ---The parameters sent in a close text document notification ---@class lsp.DidCloseTextDocumentParams +--- ---The document that was closed. ---@field textDocument lsp.TextDocumentIdentifier ---The parameters sent in a save text document notification ---@class lsp.DidSaveTextDocumentParams +--- ---The document that was saved. ---@field textDocument lsp.TextDocumentIdentifier +--- ---Optional the content when saved. Depends on the includeText value ---when the save notification was requested. ---@field text? string ---Save registration options. ----@class lsp.TextDocumentSaveRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.TextDocumentSaveRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.SaveOptions ---The parameters sent in a will save text document notification. ---@class lsp.WillSaveTextDocumentParams +--- ---The document that will be saved. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The 'TextDocumentSaveReason'. ---@field reason lsp.TextDocumentSaveReason ---A text edit applicable to a text document. ---@class lsp.TextEdit +--- ---The range of the text document to be manipulated. To insert ---text into a document create a range where start === end. ---@field range lsp.Range +--- ---The string to be inserted. For delete operations use an ---empty string. ---@field newText string ---The watched files change notification's parameters. ---@class lsp.DidChangeWatchedFilesParams +--- ---The actual file events. ---@field changes lsp.FileEvent[] ---Describe options to be used when registered for text document change events. ---@class lsp.DidChangeWatchedFilesRegistrationOptions +--- ---The watchers to register. ---@field watchers lsp.FileSystemWatcher[] ---The publish diagnostic notification's parameters. ---@class lsp.PublishDiagnosticsParams +--- ---The URI for which diagnostic information is reported. ---@field uri lsp.DocumentUri +--- ---Optional the version number of the document the diagnostics are published for. --- ---@since 3.15.0 ---@field version? integer +--- ---An array of diagnostic information items. ---@field diagnostics lsp.Diagnostic[] ---Completion parameters ---@class lsp.CompletionParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The completion context. This is only available it the client specifies ---to send this using the client capability `textDocument.completion.contextSupport === true` ---@field context? lsp.CompletionContext @@ -804,6 +954,7 @@ error('Cannot require a meta file') ---A completion item represents a text snippet that is ---proposed to complete text that is being typed. ---@class lsp.CompletionItem +--- ---The label of this completion item. --- ---The label property is also by default the text that @@ -812,39 +963,49 @@ error('Cannot require a meta file') ---If label details are provided the label itself should ---be an unqualified name of the completion item. ---@field label string +--- ---Additional details for the label --- ---@since 3.17.0 ---@field labelDetails? lsp.CompletionItemLabelDetails +--- ---The kind of this completion item. Based of the kind ---an icon is chosen by the editor. ---@field kind? lsp.CompletionItemKind +--- ---Tags for this completion item. --- ---@since 3.15.0 ---@field tags? lsp.CompletionItemTag[] +--- ---A human-readable string with additional information ---about this item, like type or symbol information. ---@field detail? string +--- ---A human-readable string that represents a doc-comment. ---@field documentation? string|lsp.MarkupContent +--- ---Indicates if this item is deprecated. ---@deprecated Use `tags` instead. ---@field deprecated? boolean +--- ---Select this item when showing. --- ---*Note* that only one completion item can be selected and that the ---tool / client decides which item that is. The rule is that the *first* ---item of those that match best is selected. ---@field preselect? boolean +--- ---A string that should be used when comparing this item ---with other items. When `falsy` the {@link CompletionItem.label label} ---is used. ---@field sortText? string +--- ---A string that should be used when filtering a set of ---completion items. When `falsy` the {@link CompletionItem.label label} ---is used. ---@field filterText? string +--- ---A string that should be inserted into a document when selecting ---this completion. When `falsy` the {@link CompletionItem.label label} ---is used. @@ -857,6 +1018,7 @@ error('Cannot require a meta file') ---recommended to use `textEdit` instead since it avoids additional client ---side interpretation. ---@field insertText? string +--- ---The format of the insert text. The format applies to both the ---`insertText` property and the `newText` property of a provided ---`textEdit`. If omitted defaults to `InsertTextFormat.PlainText`. @@ -864,12 +1026,14 @@ error('Cannot require a meta file') ---Please note that the insertTextFormat doesn't apply to ---`additionalTextEdits`. ---@field insertTextFormat? lsp.InsertTextFormat +--- ---How whitespace and indentation is handled during completion ---item insertion. If not provided the clients default value depends on ---the `textDocument.completion.insertTextMode` client capability. --- ---@since 3.16.0 ---@field insertTextMode? lsp.InsertTextMode +--- ---An {@link TextEdit edit} which is applied to a document when selecting ---this completion. When an edit is provided the value of ---{@link CompletionItem.insertText insertText} is ignored. @@ -891,6 +1055,7 @@ error('Cannot require a meta file') --- ---@since 3.16.0 additional type `InsertReplaceEdit` ---@field textEdit? lsp.TextEdit|lsp.InsertReplaceEdit +--- ---The edit text used if the completion item is part of a CompletionList and ---CompletionList defines an item default for the text edit range. --- @@ -902,6 +1067,7 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@field textEditText? string +--- ---An optional array of additional {@link TextEdit text edits} that are applied when ---selecting this completion. Edits must not overlap (including the same insert position) ---with the main {@link CompletionItem.textEdit edit} nor with themselves. @@ -910,14 +1076,17 @@ error('Cannot require a meta file') ---(for example adding an import statement at the top of the file if the completion item will ---insert an unqualified type). ---@field additionalTextEdits? lsp.TextEdit[] +--- ---An optional set of characters that when pressed while this completion is active will accept it first and ---then type that character. *Note* that all commit characters should have `length=1` and that superfluous ---characters will be ignored. ---@field commitCharacters? string[] +--- ---An optional {@link Command command} that is executed *after* inserting this completion. *Note* that ---additional modifications to the current document should be described with the ---{@link CompletionItem.additionalTextEdits additionalTextEdits}-property. ---@field command? lsp.Command +--- ---A data entry field that is preserved on a completion item between a ---{@link CompletionRequest} and a {@link CompletionResolveRequest}. ---@field data? lsp.LSPAny @@ -925,11 +1094,13 @@ error('Cannot require a meta file') ---Represents a collection of {@link CompletionItem completion items} to be presented ---in the editor. ---@class lsp.CompletionList +--- ---This list it not complete. Further typing results in recomputing this list. --- ---Recomputed lists have all their items replaced (not appended) in the ---incomplete completion sessions. ---@field isIncomplete boolean +--- ---In many cases the items of an actual completion result share the same ---value for properties like `commitCharacters` or the range of a text ---edit. A completion list can therefore define item defaults which will @@ -943,29 +1114,33 @@ error('Cannot require a meta file') ---capability. --- ---@since 3.17.0 ----@field itemDefaults? anonym3 +---@field itemDefaults? lsp._anonym2.itemDefaults +--- ---The completion items. ---@field items lsp.CompletionItem[] ---Registration options for a {@link CompletionRequest}. ----@class lsp.CompletionRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.CompletionRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.CompletionOptions ---Parameters for a {@link HoverRequest}. ---@class lsp.HoverParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams ---The result of a hover request. ---@class lsp.Hover +--- ---The hover's content ---@field contents lsp.MarkupContent|lsp.MarkedString|lsp.MarkedString[] +--- ---An optional range inside the text document that is used to ---visualize the hover, e.g. by changing the background color. ---@field range? lsp.Range ---Registration options for a {@link HoverRequest}. ----@class lsp.HoverRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.HoverRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.HoverOptions ---Parameters for a {@link SignatureHelpRequest}. ---@class lsp.SignatureHelpParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams +--- ---The signature help context. This is only available if the client specifies ---to send this using the client capability `textDocument.signatureHelp.contextSupport === true` --- @@ -976,8 +1151,10 @@ error('Cannot require a meta file') ---callable. There can be multiple signature but only one ---active and only one active parameter. ---@class lsp.SignatureHelp +--- ---One or more signatures. ---@field signatures lsp.SignatureInformation[] +--- ---The active signature. If omitted or the value lies outside the ---range of `signatures` the value defaults to zero or is ignored if ---the `SignatureHelp` has no signatures. @@ -988,6 +1165,7 @@ error('Cannot require a meta file') ---In future version of the protocol this property might become ---mandatory to better express this. ---@field activeSignature? uinteger +--- ---The active parameter of the active signature. --- ---If `null`, no parameter of the signature is active (for example a named @@ -1007,20 +1185,21 @@ error('Cannot require a meta file') ---@field activeParameter? uinteger|lsp.null ---Registration options for a {@link SignatureHelpRequest}. ----@class lsp.SignatureHelpRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.SignatureHelpRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.SignatureHelpOptions ---Parameters for a {@link DefinitionRequest}. ---@class lsp.DefinitionParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams, lsp.PartialResultParams ---Registration options for a {@link DefinitionRequest}. ----@class lsp.DefinitionRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.DefinitionRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.DefinitionOptions ---Parameters for a {@link ReferencesRequest}. ---@class lsp.ReferenceParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---@field context lsp.ReferenceContext ---Registration options for a {@link ReferencesRequest}. ----@class lsp.ReferenceRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.ReferenceRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.ReferenceOptions ---Parameters for a {@link DocumentHighlightRequest}. ---@class lsp.DocumentHighlightParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams, lsp.PartialResultParams @@ -1029,26 +1208,31 @@ error('Cannot require a meta file') ---special attention. Usually a document highlight is visualized by changing ---the background color of its range. ---@class lsp.DocumentHighlight +--- ---The range this highlight applies to. ---@field range lsp.Range +--- ---The highlight kind, default is {@link DocumentHighlightKind.Text text}. ---@field kind? lsp.DocumentHighlightKind ---Registration options for a {@link DocumentHighlightRequest}. ----@class lsp.DocumentHighlightRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.DocumentHighlightRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.DocumentHighlightOptions ---Parameters for a {@link DocumentSymbolRequest}. ----@class lsp.DocumentSymbolParams +---@class lsp.DocumentSymbolParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier ---Represents information about programming constructs like variables, classes, ---interfaces etc. ---@class lsp.SymbolInformation: lsp.BaseSymbolInformation +--- ---Indicates if this symbol is deprecated. --- ---@deprecated Use tags instead ---@field deprecated? boolean +--- ---The location of this symbol. The location's range is used by a tool ---to reveal the location in the editor. If the symbol is selected in the ---tool the range's start information is used to position the cursor. So @@ -1065,40 +1249,51 @@ error('Cannot require a meta file') ---have two ranges: one that encloses its definition and one that points to ---its most interesting range, e.g. the range of an identifier. ---@class lsp.DocumentSymbol +--- ---The name of this symbol. Will be displayed in the user interface and therefore must not be ---an empty string or a string only consisting of white spaces. ---@field name string +--- ---More detail for this symbol, e.g the signature of a function. ---@field detail? string +--- ---The kind of this symbol. ---@field kind lsp.SymbolKind +--- ---Tags for this document symbol. --- ---@since 3.16.0 ---@field tags? lsp.SymbolTag[] +--- ---Indicates if this symbol is deprecated. --- ---@deprecated Use tags instead ---@field deprecated? boolean +--- ---The range enclosing this symbol not including leading/trailing whitespace but everything else ---like comments. This information is typically used to determine if the clients cursor is ---inside the symbol to reveal in the symbol in the UI. ---@field range lsp.Range +--- ---The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. ---Must be contained by the `range`. ---@field selectionRange lsp.Range +--- ---Children of this symbol, e.g. properties of a class. ---@field children? lsp.DocumentSymbol[] ---Registration options for a {@link DocumentSymbolRequest}. ----@class lsp.DocumentSymbolRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.DocumentSymbolRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.DocumentSymbolOptions ---The parameters of a {@link CodeActionRequest}. ----@class lsp.CodeActionParams +---@class lsp.CodeActionParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The document in which the command was invoked. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The range for which the command was invoked. ---@field range lsp.Range +--- ---Context carrying additional information. ---@field context lsp.CodeActionContext @@ -1107,10 +1302,13 @@ error('Cannot require a meta file') ---an array of arguments which will be passed to the command handler ---function when invoked. ---@class lsp.Command +--- ---Title of the command, like `save`. ---@field title string +--- ---The identifier of the actual command handler. ---@field command string +--- ---Arguments that the command handler should be ---invoked with. ---@field arguments? lsp.LSPAny[] @@ -1120,14 +1318,18 @@ error('Cannot require a meta file') --- ---A CodeAction must set either `edit` and/or a `command`. If both are supplied, the `edit` is applied first, then the `command` is executed. ---@class lsp.CodeAction +--- ---A short, human-readable, title for this code action. ---@field title string +--- ---The kind of the code action. --- ---Used to filter code actions. ---@field kind? lsp.CodeActionKind +--- ---The diagnostics that this code action resolves. ---@field diagnostics? lsp.Diagnostic[] +--- ---Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted ---by keybindings. --- @@ -1136,6 +1338,7 @@ error('Cannot require a meta file') --- ---@since 3.15.0 ---@field isPreferred? boolean +--- ---Marks that the code action cannot currently be applied. --- ---Clients should follow the following guidelines regarding disabled code actions: @@ -1151,13 +1354,16 @@ error('Cannot require a meta file') --- error message with `reason` in the editor. --- ---@since 3.16.0 ----@field disabled? anonym4 +---@field disabled? lsp._anonym4.disabled +--- ---The workspace edit this code action performs. ---@field edit? lsp.WorkspaceEdit +--- ---A command this code action executes. If a code action ---provides an edit and a command, first the edit is ---executed and then the command. ---@field command? lsp.Command +--- ---A data entry field that is preserved on a code action between ---a `textDocument/codeAction` and a `codeAction/resolve` request. --- @@ -1165,10 +1371,11 @@ error('Cannot require a meta file') ---@field data? lsp.LSPAny ---Registration options for a {@link CodeActionRequest}. ----@class lsp.CodeActionRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.CodeActionRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.CodeActionOptions ---The parameters of a {@link WorkspaceSymbolRequest}. ----@class lsp.WorkspaceSymbolParams +---@class lsp.WorkspaceSymbolParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---A query string to filter symbols by. Clients may send an empty ---string here to request all symbols. ---@field query string @@ -1179,12 +1386,14 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.WorkspaceSymbol: lsp.BaseSymbolInformation +--- ---The location of the symbol. Whether a server is allowed to ---return a location without a range depends on the client ---capability `workspace.symbol.resolveSupport`. --- ---See SymbolInformation#location for more details. ----@field location lsp.Location|anonym5 +---@field location lsp.Location|lsp._anonym5.location +--- ---A data entry field that is preserved on a workspace symbol between a ---workspace symbol request and a workspace symbol resolve request. ---@field data? lsp.LSPAny @@ -1193,7 +1402,8 @@ error('Cannot require a meta file') ---@class lsp.WorkspaceSymbolRegistrationOptions: lsp.WorkspaceSymbolOptions ---The parameters of a {@link CodeLensRequest}. ----@class lsp.CodeLensParams +---@class lsp.CodeLensParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The document to request code lens for. ---@field textDocument lsp.TextDocumentIdentifier @@ -1203,29 +1413,36 @@ error('Cannot require a meta file') ---A code lens is _unresolved_ when no command is associated to it. For performance ---reasons the creation of a code lens and resolving should be done in two stages. ---@class lsp.CodeLens +--- ---The range in which this code lens is valid. Should only span a single line. ---@field range lsp.Range +--- ---The command this code lens represents. ---@field command? lsp.Command +--- ---A data entry field that is preserved on a code lens item between ---a {@link CodeLensRequest} and a {@link CodeLensResolveRequest} ---@field data? lsp.LSPAny ---Registration options for a {@link CodeLensRequest}. ----@class lsp.CodeLensRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.CodeLensRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.CodeLensOptions ---The parameters of a {@link DocumentLinkRequest}. ----@class lsp.DocumentLinkParams +---@class lsp.DocumentLinkParams: lsp.WorkDoneProgressParams, lsp.PartialResultParams +--- ---The document to provide document links for. ---@field textDocument lsp.TextDocumentIdentifier ---A document link is a range in a text document that links to an internal or external resource, like another ---text document or a web site. ---@class lsp.DocumentLink +--- ---The range this link applies to. ---@field range lsp.Range +--- ---The uri this link points to. If missing a resolve request is sent later. ---@field target? lsp.URI +--- ---The tooltip text when you hover over this link. --- ---If a tooltip is provided, is will be displayed in a string that includes instructions on how to @@ -1234,86 +1451,104 @@ error('Cannot require a meta file') --- ---@since 3.15.0 ---@field tooltip? string +--- ---A data entry field that is preserved on a document link between a ---DocumentLinkRequest and a DocumentLinkResolveRequest. ---@field data? lsp.LSPAny ---Registration options for a {@link DocumentLinkRequest}. ----@class lsp.DocumentLinkRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.DocumentLinkRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.DocumentLinkOptions ---The parameters of a {@link DocumentFormattingRequest}. ----@class lsp.DocumentFormattingParams +---@class lsp.DocumentFormattingParams: lsp.WorkDoneProgressParams +--- ---The document to format. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The format options. ---@field options lsp.FormattingOptions ---Registration options for a {@link DocumentFormattingRequest}. ----@class lsp.DocumentFormattingRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.DocumentFormattingRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.DocumentFormattingOptions ---The parameters of a {@link DocumentRangeFormattingRequest}. ----@class lsp.DocumentRangeFormattingParams +---@class lsp.DocumentRangeFormattingParams: lsp.WorkDoneProgressParams +--- ---The document to format. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The range to format ---@field range lsp.Range +--- ---The format options ---@field options lsp.FormattingOptions ---Registration options for a {@link DocumentRangeFormattingRequest}. ----@class lsp.DocumentRangeFormattingRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.DocumentRangeFormattingRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.DocumentRangeFormattingOptions ---The parameters of a {@link DocumentRangesFormattingRequest}. --- ---@since 3.18.0 ---@proposed ----@class lsp.DocumentRangesFormattingParams +---@class lsp.DocumentRangesFormattingParams: lsp.WorkDoneProgressParams +--- ---The document to format. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The ranges to format ---@field ranges lsp.Range[] +--- ---The format options ---@field options lsp.FormattingOptions ---The parameters of a {@link DocumentOnTypeFormattingRequest}. ---@class lsp.DocumentOnTypeFormattingParams +--- ---The document to format. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The position around which the on type formatting should happen. ---This is not necessarily the exact position where the character denoted ---by the property `ch` got typed. ---@field position lsp.Position +--- ---The character that has been typed that triggered the formatting ---on type request. That is not necessarily the last character that ---got inserted into the document since the client could auto insert ---characters as well (e.g. like automatic brace completion). ---@field ch string +--- ---The formatting options. ---@field options lsp.FormattingOptions ---Registration options for a {@link DocumentOnTypeFormattingRequest}. ----@class lsp.DocumentOnTypeFormattingRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.DocumentOnTypeFormattingRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.DocumentOnTypeFormattingOptions ---The parameters of a {@link RenameRequest}. ----@class lsp.RenameParams +---@class lsp.RenameParams: lsp.WorkDoneProgressParams +--- ---The document to rename. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The position at which this request was sent. ---@field position lsp.Position +--- ---The new name of the symbol. If the given name is not valid the ---request must return a {@link ResponseError} with an ---appropriate message set. ---@field newName string ---Registration options for a {@link RenameRequest}. ----@class lsp.RenameRegistrationOptions: lsp.TextDocumentRegistrationOptions +---@class lsp.RenameRegistrationOptions: lsp.TextDocumentRegistrationOptions, lsp.RenameOptions ---@class lsp.PrepareRenameParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams ---The parameters of a {@link ExecuteCommandRequest}. ----@class lsp.ExecuteCommandParams +---@class lsp.ExecuteCommandParams: lsp.WorkDoneProgressParams +--- ---The identifier of the actual command handler. ---@field command string +--- ---Arguments that the command should be invoked with. ---@field arguments? lsp.LSPAny[] @@ -1322,10 +1557,12 @@ error('Cannot require a meta file') ---The parameters passed via an apply workspace edit request. ---@class lsp.ApplyWorkspaceEditParams +--- ---An optional label of the workspace edit. This label is ---presented in the user interface for example on an undo ---stack to undo the workspace edit. ---@field label? string +--- ---The edits to apply. ---@field edit lsp.WorkspaceEdit @@ -1333,34 +1570,42 @@ error('Cannot require a meta file') --- ---@since 3.17 renamed from ApplyWorkspaceEditResponse ---@class lsp.ApplyWorkspaceEditResult +--- ---Indicates whether the edit was applied or not. ---@field applied boolean +--- ---An optional textual description for why the edit was not applied. ---This may be used by the server for diagnostic logging or to provide ---a suitable error for a request that triggered the edit. ---@field failureReason? string +--- ---Depending on the client's failure handling strategy `failedChange` might ---contain the index of the change that failed. This property is only available ---if the client signals a `failureHandlingStrategy` in its client capabilities. ---@field failedChange? uinteger ---@class lsp.WorkDoneProgressBegin +--- ---@field kind "begin" +--- ---Mandatory title of the progress operation. Used to briefly inform about ---the kind of operation being performed. --- ---Examples: "Indexing" or "Linking dependencies". ---@field title string +--- ---Controls if a cancel button should show to allow the user to cancel the ---long running operation. Clients that don't support cancellation are allowed ---to ignore the setting. ---@field cancellable? boolean +--- ---Optional, more detailed associated progress message. Contains ---complementary information to the `title`. --- ---Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". ---If unset, the previous progress message (if any) is still valid. ---@field message? string +--- ---Optional progress percentage to display (value 100 is considered 100%). ---If not provided infinite progress is assumed and clients are allowed ---to ignore the `percentage` value in subsequent in report notifications. @@ -1370,18 +1615,22 @@ error('Cannot require a meta file') ---@field percentage? uinteger ---@class lsp.WorkDoneProgressReport +--- ---@field kind "report" +--- ---Controls enablement state of a cancel button. --- ---Clients that don't support cancellation or don't support controlling the button's ---enablement state are allowed to ignore the property. ---@field cancellable? boolean +--- ---Optional, more detailed associated progress message. Contains ---complementary information to the `title`. --- ---Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". ---If unset, the previous progress message (if any) is still valid. ---@field message? string +--- ---Optional progress percentage to display (value 100 is considered 100%). ---If not provided infinite progress is assumed and clients are allowed ---to ignore the `percentage` value in subsequent in report notifications. @@ -1391,41 +1640,53 @@ error('Cannot require a meta file') ---@field percentage? uinteger ---@class lsp.WorkDoneProgressEnd +--- ---@field kind "end" +--- ---Optional, a final message indicating to for example indicate the outcome ---of the operation. ---@field message? string ---@class lsp.SetTraceParams +--- ---@field value lsp.TraceValues ---@class lsp.LogTraceParams +--- ---@field message string +--- ---@field verbose? string ---@class lsp.CancelParams +--- ---The request id to cancel. ---@field id integer|string ---@class lsp.ProgressParams +--- ---The progress token provided by the client or server. ---@field token lsp.ProgressToken +--- ---The progress data. ---@field value lsp.LSPAny ---A parameter literal used in requests to pass a text document and a position inside that ---document. ---@class lsp.TextDocumentPositionParams +--- ---The text document. ---@field textDocument lsp.TextDocumentIdentifier +--- ---The position inside the text document. ---@field position lsp.Position ---@class lsp.WorkDoneProgressParams +--- ---An optional token that a server can use to report work done progress. ---@field workDoneToken? lsp.ProgressToken ---@class lsp.PartialResultParams +--- ---An optional token that a server can use to report partial results (e.g. streaming) to ---the client. ---@field partialResultToken? lsp.ProgressToken @@ -1433,17 +1694,21 @@ error('Cannot require a meta file') ---Represents the connection of two locations. Provides additional metadata over normal {@link Location locations}, ---including an origin range. ---@class lsp.LocationLink +--- ---Span of the origin of this link. --- ---Used as the underlined span for mouse interaction. Defaults to the word range at ---the definition position. ---@field originSelectionRange? lsp.Range +--- ---The target resource identifier of this link. ---@field targetUri lsp.DocumentUri +--- ---The full target range of this link. If the target for example is a symbol then target range is the ---range enclosing this symbol not including leading/trailing whitespace but everything else ---like comments. This information is typically used to highlight the range in the editor. ---@field targetRange lsp.Range +--- ---The range that should be selected and revealed when this link is being followed, e.g the name of a function. ---Must be contained by the `targetRange`. See also `DocumentSymbol#range` ---@field targetSelectionRange lsp.Range @@ -1460,56 +1725,68 @@ error('Cannot require a meta file') ---} ---``` ---@class lsp.Range +--- ---The range's start position. ---@field start lsp.Position +--- ---The range's end position. ---@field end lsp.Position ----@class lsp.ImplementationOptions +---@class lsp.ImplementationOptions: lsp.WorkDoneProgressOptions ---Static registration options to be returned in the initialize ---request. ---@class lsp.StaticRegistrationOptions +--- ---The id used to register the request. The id can be used to deregister ---the request again. See also Registration#id. ---@field id? string ----@class lsp.TypeDefinitionOptions +---@class lsp.TypeDefinitionOptions: lsp.WorkDoneProgressOptions ---The workspace folder change event. ---@class lsp.WorkspaceFoldersChangeEvent +--- ---The array of added workspace folders ---@field added lsp.WorkspaceFolder[] +--- ---The array of the removed workspace folders ---@field removed lsp.WorkspaceFolder[] ---@class lsp.ConfigurationItem +--- ---The scope to get the configuration section for. ---@field scopeUri? lsp.URI +--- ---The configuration section asked for. ---@field section? string ---A literal to identify a text document in the client. ---@class lsp.TextDocumentIdentifier +--- ---The text document's uri. ---@field uri lsp.DocumentUri ---Represents a color in RGBA space. ---@class lsp.Color +--- ---The red component of this color in the range [0-1]. ---@field red decimal +--- ---The green component of this color in the range [0-1]. ---@field green decimal +--- ---The blue component of this color in the range [0-1]. ---@field blue decimal +--- ---The alpha component of this color in the range [0-1]. ---@field alpha decimal ----@class lsp.DocumentColorOptions +---@class lsp.DocumentColorOptions: lsp.WorkDoneProgressOptions ----@class lsp.FoldingRangeOptions +---@class lsp.FoldingRangeOptions: lsp.WorkDoneProgressOptions ----@class lsp.DeclarationOptions +---@class lsp.DeclarationOptions: lsp.WorkDoneProgressOptions ---Position in a text document expressed as zero-based line and character ---offset. Prior to 3.17 the offsets were always based on a UTF-16 string @@ -1539,11 +1816,13 @@ error('Cannot require a meta file') --- ---@since 3.17.0 - support for negotiated position encoding. ---@class lsp.Position +--- ---Line position in a document (zero-based). --- ---If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document. ---If a line number is negative, it defaults to 0. ---@field line uinteger +--- ---Character offset on a line in a document (zero-based). --- ---The meaning of this offset is determined by the negotiated @@ -1553,38 +1832,45 @@ error('Cannot require a meta file') ---line length. ---@field character uinteger ----@class lsp.SelectionRangeOptions +---@class lsp.SelectionRangeOptions: lsp.WorkDoneProgressOptions ---Call hierarchy options used during static registration. --- ---@since 3.16.0 ----@class lsp.CallHierarchyOptions +---@class lsp.CallHierarchyOptions: lsp.WorkDoneProgressOptions ---@since 3.16.0 ----@class lsp.SemanticTokensOptions +---@class lsp.SemanticTokensOptions: lsp.WorkDoneProgressOptions +--- ---The legend used by the server ---@field legend lsp.SemanticTokensLegend +--- ---Server supports providing semantic tokens for a specific range ---of a document. ----@field range? boolean|anonym6 +---@field range? boolean|lsp._anonym6.range +--- ---Server supports providing semantic tokens for a full document. ----@field full? boolean|anonym7 +---@field full? boolean|lsp._anonym7.full ---@since 3.16.0 ---@class lsp.SemanticTokensEdit +--- ---The start offset of the edit. ---@field start uinteger +--- ---The count of elements to remove. ---@field deleteCount uinteger +--- ---The elements to insert. ---@field data? uinteger[] ----@class lsp.LinkedEditingRangeOptions +---@class lsp.LinkedEditingRangeOptions: lsp.WorkDoneProgressOptions ---Represents information on a file/folder create. --- ---@since 3.16.0 ---@class lsp.FileCreate +--- ---A file:// URI for the location of the file/folder being created. ---@field uri string @@ -1593,8 +1879,10 @@ error('Cannot require a meta file') ---So the creator of a TextDocumentEdit doesn't need to sort the array of edits or do any ---kind of ordering. However the edits must be non overlapping. ---@class lsp.TextDocumentEdit +--- ---The text document to change. ---@field textDocument lsp.OptionalVersionedTextDocumentIdentifier +--- ---The edits to be applied. --- ---@since 3.16.0 - support for AnnotatedTextEdit. This is guarded using a @@ -1603,30 +1891,40 @@ error('Cannot require a meta file') ---Create file operation. ---@class lsp.CreateFile: lsp.ResourceOperation +--- ---A create ---@field kind "create" +--- ---The resource to create. ---@field uri lsp.DocumentUri +--- ---Additional options ---@field options? lsp.CreateFileOptions ---Rename file operation ---@class lsp.RenameFile: lsp.ResourceOperation +--- ---A rename ---@field kind "rename" +--- ---The old (existing) location. ---@field oldUri lsp.DocumentUri +--- ---The new location. ---@field newUri lsp.DocumentUri +--- ---Rename options. ---@field options? lsp.RenameFileOptions ---Delete file operation ---@class lsp.DeleteFile: lsp.ResourceOperation +--- ---A delete ---@field kind "delete" +--- ---The file to delete. ---@field uri lsp.DocumentUri +--- ---Delete options. ---@field options? lsp.DeleteFileOptions @@ -1634,12 +1932,15 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.ChangeAnnotation +--- ---A human-readable string describing the actual change. The string ---is rendered prominent in the user interface. ---@field label string +--- ---A flag which indicates that user confirmation is needed ---before applying the change. ---@field needsConfirmation? boolean +--- ---A human-readable string which is rendered less prominent in ---the user interface. ---@field description? string @@ -1649,8 +1950,10 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.FileOperationFilter +--- ---A Uri scheme like `file` or `untitled`. ---@field scheme? string +--- ---The actual file operation pattern. ---@field pattern lsp.FileOperationPattern @@ -1658,8 +1961,10 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.FileRename +--- ---A file:// URI for the original location of the file/folder being renamed. ---@field oldUri string +--- ---A file:// URI for the new location of the file/folder being renamed. ---@field newUri string @@ -1667,20 +1972,23 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.FileDelete +--- ---A file:// URI for the location of the file/folder being deleted. ---@field uri string ----@class lsp.MonikerOptions +---@class lsp.MonikerOptions: lsp.WorkDoneProgressOptions ---Type hierarchy options used during static registration. --- ---@since 3.17.0 ----@class lsp.TypeHierarchyOptions +---@class lsp.TypeHierarchyOptions: lsp.WorkDoneProgressOptions ---@since 3.17.0 ---@class lsp.InlineValueContext +--- ---The stack frame (as a DAP Id) where the execution has stopped. ---@field frameId integer +--- ---The document range where execution has stopped. ---Typically the end position of the range denotes the line where the inline values are shown. ---@field stoppedLocation lsp.Range @@ -1689,8 +1997,10 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.InlineValueText +--- ---The document range for which the inline value applies. ---@field range lsp.Range +--- ---The text of the inline value. ---@field text string @@ -1700,11 +2010,14 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.InlineValueVariableLookup +--- ---The document range for which the inline value applies. ---The range is used to extract the variable name from the underlying document. ---@field range lsp.Range +--- ---If specified the name of the variable to look up. ---@field variableName? string +--- ---How to perform the lookup. ---@field caseSensitiveLookup boolean @@ -1714,28 +2027,33 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.InlineValueEvaluatableExpression +--- ---The document range for which the inline value applies. ---The range is used to extract the evaluatable expression from the underlying document. ---@field range lsp.Range +--- ---If specified the expression overrides the extracted expression. ---@field expression? string ---Inline value options used during static registration. --- ---@since 3.17.0 ----@class lsp.InlineValueOptions +---@class lsp.InlineValueOptions: lsp.WorkDoneProgressOptions ---An inlay hint label part allows for interactive and composite labels ---of inlay hints. --- ---@since 3.17.0 ---@class lsp.InlayHintLabelPart +--- ---The value of this label part. ---@field value string +--- ---The tooltip text when you hover over this label part. Depending on ---the client capability `inlayHint.resolveSupport` clients might resolve ---this property late using the resolve request. ---@field tooltip? string|lsp.MarkupContent +--- ---An optional source code location that represents this ---label part. --- @@ -1748,6 +2066,7 @@ error('Cannot require a meta file') ---Depending on the client capability `inlayHint.resolveSupport` clients ---might resolve this property late using the resolve request. ---@field location? lsp.Location +--- ---An optional command for this label part. --- ---Depending on the client capability `inlayHint.resolveSupport` clients @@ -1777,15 +2096,18 @@ error('Cannot require a meta file') ---*Please Note* that clients might sanitize the return markdown. A client could decide to ---remove HTML from the markdown to avoid script execution. ---@class lsp.MarkupContent +--- ---The type of the Markup ---@field kind lsp.MarkupKind +--- ---The content itself ---@field value string ---Inlay hint options used during static registration. --- ---@since 3.17.0 ----@class lsp.InlayHintOptions +---@class lsp.InlayHintOptions: lsp.WorkDoneProgressOptions +--- ---The server provides support to resolve additional ---information for an inlay hint item. ---@field resolveProvider? boolean @@ -1794,6 +2116,7 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.RelatedFullDocumentDiagnosticReport: lsp.FullDocumentDiagnosticReport +--- ---Diagnostics of related documents. This information is useful ---in programming languages where code in a file A can generate ---diagnostics in a file B which A depends on. An example of @@ -1807,6 +2130,7 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.RelatedUnchangedDocumentDiagnosticReport: lsp.UnchangedDocumentDiagnosticReport +--- ---Diagnostics of related documents. This information is useful ---in programming languages where code in a file A can generate ---diagnostics in a file B which A depends on. An example of @@ -1820,12 +2144,15 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.FullDocumentDiagnosticReport +--- ---A full document diagnostic report. ---@field kind "full" +--- ---An optional result id. If provided it will ---be sent on the next diagnostic request for the ---same document. ---@field resultId? string +--- ---The actual items. ---@field items lsp.Diagnostic[] @@ -1834,11 +2161,13 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.UnchangedDocumentDiagnosticReport +--- ---A document diagnostic report indicating ---no changes to the last result. A server can ---only return `unchanged` if result ids are ---provided. ---@field kind "unchanged" +--- ---A result id which will be sent on the next ---diagnostic request for the same document. ---@field resultId string @@ -1846,15 +2175,18 @@ error('Cannot require a meta file') ---Diagnostic options. --- ---@since 3.17.0 ----@class lsp.DiagnosticOptions +---@class lsp.DiagnosticOptions: lsp.WorkDoneProgressOptions +--- ---An optional identifier under which the diagnostics are ---managed by the client. ---@field identifier? string +--- ---Whether the language has inter file dependencies meaning that ---editing code in one file can result in a different diagnostic ---set in another file. Inter file dependencies are common for ---most programming languages and typically uncommon for linters. ---@field interFileDependencies boolean +--- ---The server provides support for workspace diagnostics as well. ---@field workspaceDiagnostics boolean @@ -1862,9 +2194,11 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.PreviousResultId +--- ---The URI for which the client knowns a ---result id. ---@field uri lsp.DocumentUri +--- ---The value of the previous result id. ---@field value string @@ -1872,31 +2206,40 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.NotebookDocument +--- ---The notebook document's uri. ---@field uri lsp.URI +--- ---The type of the notebook. ---@field notebookType string +--- ---The version number of this document (it will increase after each ---change, including undo/redo). ---@field version integer +--- ---Additional metadata stored with the notebook ---document. --- ---Note: should always be an object literal (e.g. LSPObject) ---@field metadata? lsp.LSPObject +--- ---The cells of a notebook. ---@field cells lsp.NotebookCell[] ---An item to transfer a text document from the client to the ---server. ---@class lsp.TextDocumentItem +--- ---The text document's uri. ---@field uri lsp.DocumentUri +--- ---The text document's language identifier. ---@field languageId string +--- ---The version number of this document (it will increase after each ---change, including undo/redo). ---@field version integer +--- ---The content of the opened text document. ---@field text string @@ -1904,8 +2247,10 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.VersionedNotebookDocumentIdentifier +--- ---The version number of this notebook document. ---@field version integer +--- ---The notebook document's uri. ---@field uri lsp.URI @@ -1913,17 +2258,20 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.NotebookDocumentChangeEvent +--- ---The changed meta data if any. --- ---Note: should always be an object literal (e.g. LSPObject) ---@field metadata? lsp.LSPObject +--- ---Changes to cells ----@field cells? anonym10 +---@field cells? lsp._anonym8.cells ---A literal to identify a notebook document in the client. --- ---@since 3.17.0 ---@class lsp.NotebookDocumentIdentifier +--- ---The notebook document's uri. ---@field uri lsp.URI @@ -1932,8 +2280,10 @@ error('Cannot require a meta file') ---@since 3.18.0 ---@proposed ---@class lsp.InlineCompletionContext +--- ---Describes how the inline completion was triggered. ---@field triggerKind lsp.InlineCompletionTriggerKind +--- ---Provides information about the currently selected item in the autocomplete widget if it is visible. ---@field selectedCompletionInfo? lsp.SelectedCompletionInfo @@ -1948,8 +2298,10 @@ error('Cannot require a meta file') ---@since 3.18.0 ---@proposed ---@class lsp.StringValue +--- ---The kind of string value. ---@field kind "snippet" +--- ---The snippet string. ---@field value string @@ -1957,38 +2309,46 @@ error('Cannot require a meta file') --- ---@since 3.18.0 ---@proposed ----@class lsp.InlineCompletionOptions +---@class lsp.InlineCompletionOptions: lsp.WorkDoneProgressOptions ---General parameters to register for a notification or to register a provider. ---@class lsp.Registration +--- ---The id used to register the request. The id can be used to deregister ---the request again. ---@field id string +--- ---The method / capability to register for. ---@field method string +--- ---Options necessary for the registration. ---@field registerOptions? lsp.LSPAny ---General parameters to unregister a request or notification. ---@class lsp.Unregistration +--- ---The id used to unregister the request or notification. Usually an id ---provided during the register request. ---@field id string +--- ---The method to unregister for. ---@field method string ---The initialize parameters ----@class lsp._InitializeParams +---@class lsp._InitializeParams: lsp.WorkDoneProgressParams +--- ---The process Id of the parent process that started ---the server. --- ---Is `null` if the process has not been started by another process. ---If the parent process is not alive then the server should exit. ---@field processId integer|lsp.null +--- ---Information about the client --- ---@since 3.15.0 ----@field clientInfo? anonym11 +---@field clientInfo? lsp._anonym11.clientInfo +--- ---The locale the client is currently showing the user interface ---in. This must not necessarily be the locale of the operating ---system. @@ -1998,25 +2358,31 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@field locale? string +--- ---The rootPath of the workspace. Is null ---if no folder is open. --- ---@deprecated in favour of rootUri. ---@field rootPath? string|lsp.null +--- ---The rootUri of the workspace. Is null if no ---folder is open. If both `rootPath` and `rootUri` are set ---`rootUri` wins. --- ---@deprecated in favour of workspaceFolders. ---@field rootUri lsp.DocumentUri|lsp.null +--- ---The capabilities provided by the client (editor or tool) ---@field capabilities lsp.ClientCapabilities +--- ---User provided initialization options. ---@field initializationOptions? lsp.LSPAny +--- ---The initial trace setting. If omitted trace is disabled ('off'). ---@field trace? lsp.TraceValues ---@class lsp.WorkspaceFoldersInitializeParams +--- ---The workspace folders configured in the client when the server starts. --- ---This property is only available if the client supports workspace folders. @@ -2029,6 +2395,7 @@ error('Cannot require a meta file') ---Defines the capabilities provided by a language ---server. ---@class lsp.ServerCapabilities +--- ---The position encoding the server picked from the encodings offered ---by the client via the client capability `general.positionEncodings`. --- @@ -2039,126 +2406,167 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@field positionEncoding? lsp.PositionEncodingKind +--- ---Defines how text documents are synced. Is either a detailed structure ---defining each notification or for backwards compatibility the ---TextDocumentSyncKind number. ---@field textDocumentSync? lsp.TextDocumentSyncOptions|lsp.TextDocumentSyncKind +--- ---Defines how notebook documents are synced. --- ---@since 3.17.0 ---@field notebookDocumentSync? lsp.NotebookDocumentSyncOptions|lsp.NotebookDocumentSyncRegistrationOptions +--- ---The server provides completion support. ---@field completionProvider? lsp.CompletionOptions +--- ---The server provides hover support. ---@field hoverProvider? boolean|lsp.HoverOptions +--- ---The server provides signature help support. ---@field signatureHelpProvider? lsp.SignatureHelpOptions +--- ---The server provides Goto Declaration support. ---@field declarationProvider? boolean|lsp.DeclarationOptions|lsp.DeclarationRegistrationOptions +--- ---The server provides goto definition support. ---@field definitionProvider? boolean|lsp.DefinitionOptions +--- ---The server provides Goto Type Definition support. ---@field typeDefinitionProvider? boolean|lsp.TypeDefinitionOptions|lsp.TypeDefinitionRegistrationOptions +--- ---The server provides Goto Implementation support. ---@field implementationProvider? boolean|lsp.ImplementationOptions|lsp.ImplementationRegistrationOptions +--- ---The server provides find references support. ---@field referencesProvider? boolean|lsp.ReferenceOptions +--- ---The server provides document highlight support. ---@field documentHighlightProvider? boolean|lsp.DocumentHighlightOptions +--- ---The server provides document symbol support. ---@field documentSymbolProvider? boolean|lsp.DocumentSymbolOptions +--- ---The server provides code actions. CodeActionOptions may only be ---specified if the client states that it supports ---`codeActionLiteralSupport` in its initial `initialize` request. ---@field codeActionProvider? boolean|lsp.CodeActionOptions +--- ---The server provides code lens. ---@field codeLensProvider? lsp.CodeLensOptions +--- ---The server provides document link support. ---@field documentLinkProvider? lsp.DocumentLinkOptions +--- ---The server provides color provider support. ---@field colorProvider? boolean|lsp.DocumentColorOptions|lsp.DocumentColorRegistrationOptions +--- ---The server provides workspace symbol support. ---@field workspaceSymbolProvider? boolean|lsp.WorkspaceSymbolOptions +--- ---The server provides document formatting. ---@field documentFormattingProvider? boolean|lsp.DocumentFormattingOptions +--- ---The server provides document range formatting. ---@field documentRangeFormattingProvider? boolean|lsp.DocumentRangeFormattingOptions +--- ---The server provides document formatting on typing. ---@field documentOnTypeFormattingProvider? lsp.DocumentOnTypeFormattingOptions +--- ---The server provides rename support. RenameOptions may only be ---specified if the client states that it supports ---`prepareSupport` in its initial `initialize` request. ---@field renameProvider? boolean|lsp.RenameOptions +--- ---The server provides folding provider support. ---@field foldingRangeProvider? boolean|lsp.FoldingRangeOptions|lsp.FoldingRangeRegistrationOptions +--- ---The server provides selection range support. ---@field selectionRangeProvider? boolean|lsp.SelectionRangeOptions|lsp.SelectionRangeRegistrationOptions +--- ---The server provides execute command support. ---@field executeCommandProvider? lsp.ExecuteCommandOptions +--- ---The server provides call hierarchy support. --- ---@since 3.16.0 ---@field callHierarchyProvider? boolean|lsp.CallHierarchyOptions|lsp.CallHierarchyRegistrationOptions +--- ---The server provides linked editing range support. --- ---@since 3.16.0 ---@field linkedEditingRangeProvider? boolean|lsp.LinkedEditingRangeOptions|lsp.LinkedEditingRangeRegistrationOptions +--- ---The server provides semantic tokens support. --- ---@since 3.16.0 ---@field semanticTokensProvider? lsp.SemanticTokensOptions|lsp.SemanticTokensRegistrationOptions +--- ---The server provides moniker support. --- ---@since 3.16.0 ---@field monikerProvider? boolean|lsp.MonikerOptions|lsp.MonikerRegistrationOptions +--- ---The server provides type hierarchy support. --- ---@since 3.17.0 ---@field typeHierarchyProvider? boolean|lsp.TypeHierarchyOptions|lsp.TypeHierarchyRegistrationOptions +--- ---The server provides inline values. --- ---@since 3.17.0 ---@field inlineValueProvider? boolean|lsp.InlineValueOptions|lsp.InlineValueRegistrationOptions +--- ---The server provides inlay hints. --- ---@since 3.17.0 ---@field inlayHintProvider? boolean|lsp.InlayHintOptions|lsp.InlayHintRegistrationOptions +--- ---The server has support for pull model diagnostics. --- ---@since 3.17.0 ---@field diagnosticProvider? lsp.DiagnosticOptions|lsp.DiagnosticRegistrationOptions +--- ---Inline completion options used during static registration. --- ---@since 3.18.0 ---@proposed ---@field inlineCompletionProvider? boolean|lsp.InlineCompletionOptions +--- ---Workspace specific server capabilities. ----@field workspace? anonym12 +---@field workspace? lsp._anonym12.workspace +--- ---Experimental server capabilities. ---@field experimental? lsp.LSPAny ---A text document identifier to denote a specific version of a text document. ---@class lsp.VersionedTextDocumentIdentifier: lsp.TextDocumentIdentifier +--- ---The version number of this document. ---@field version integer ---Save options. ---@class lsp.SaveOptions +--- ---The client is supposed to include the content on save. ---@field includeText? boolean ---An event describing a file change. ---@class lsp.FileEvent +--- ---The file's uri. ---@field uri lsp.DocumentUri +--- ---The change type. ---@field type lsp.FileChangeType ---@class lsp.FileSystemWatcher +--- ---The glob pattern to watch. See {@link GlobPattern glob pattern} for more detail. --- ---@since 3.17.0 support for relative patterns. ---@field globPattern lsp.GlobPattern +--- ---The kind of events of interest. If omitted it defaults ---to WatchKind.Create | WatchKind.Change | WatchKind.Delete ---which is 7. @@ -2167,31 +2575,40 @@ error('Cannot require a meta file') ---Represents a diagnostic, such as a compiler error or warning. Diagnostic objects ---are only valid in the scope of a resource. ---@class lsp.Diagnostic +--- ---The range at which the message applies ---@field range lsp.Range +--- ---The diagnostic's severity. Can be omitted. If omitted it is up to the ---client to interpret diagnostics as error, warning, info or hint. ---@field severity? lsp.DiagnosticSeverity +--- ---The diagnostic's code, which usually appear in the user interface. ---@field code? integer|string +--- ---An optional property to describe the error code. ---Requires the code field (above) to be present/not null. --- ---@since 3.16.0 ---@field codeDescription? lsp.CodeDescription +--- ---A human-readable string describing the source of this ---diagnostic, e.g. 'typescript' or 'super lint'. It usually ---appears in the user interface. ---@field source? string +--- ---The diagnostic's message. It usually appears in the user interface ---@field message string +--- ---Additional metadata about the diagnostic. --- ---@since 3.15.0 ---@field tags? lsp.DiagnosticTag[] +--- ---An array of related diagnostic information, e.g. when symbol-names within ---a scope collide all definitions can be marked via this property. ---@field relatedInformation? lsp.DiagnosticRelatedInformation[] +--- ---A data entry field that is preserved between a `textDocument/publishDiagnostics` ---notification and `textDocument/codeAction` request. --- @@ -2200,8 +2617,10 @@ error('Cannot require a meta file') ---Contains additional information about the context in which a completion request is triggered. ---@class lsp.CompletionContext +--- ---How the completion was triggered. ---@field triggerKind lsp.CompletionTriggerKind +--- ---The trigger character (a single character) that has trigger code complete. ---Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` ---@field triggerCharacter? string @@ -2210,9 +2629,11 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.CompletionItemLabelDetails +--- ---An optional string which is rendered less prominently directly after {@link CompletionItem.label label}, ---without any spacing. Should be used for function signatures and type annotations. ---@field detail? string +--- ---An optional string which is rendered less prominently after {@link CompletionItem.detail}. Should be used ---for fully qualified names and file paths. ---@field description? string @@ -2221,15 +2642,19 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.InsertReplaceEdit +--- ---The string to be inserted. ---@field newText string +--- ---The range if the insert is requested ---@field insert lsp.Range +--- ---The range if the replace is requested. ---@field replace lsp.Range ---Completion options. ----@class lsp.CompletionOptions +---@class lsp.CompletionOptions: lsp.WorkDoneProgressOptions +--- ---Most tools trigger completion request automatically without explicitly requesting ---it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user ---starts to type an identifier. For example if the user types `c` in a JavaScript file @@ -2239,6 +2664,7 @@ error('Cannot require a meta file') ---If code complete should automatically be trigger on characters not being valid inside ---an identifier (for example `.` in JavaScript) list them in `triggerCharacters`. ---@field triggerCharacters? string[] +--- ---The list of all possible characters that commit a completion. This field can be used ---if clients don't support individual commit characters per completion item. See ---`ClientCapabilities.textDocument.completion.completionItem.commitCharactersSupport` @@ -2248,33 +2674,39 @@ error('Cannot require a meta file') --- ---@since 3.2.0 ---@field allCommitCharacters? string[] +--- ---The server provides support to resolve additional ---information for a completion item. ---@field resolveProvider? boolean +--- ---The server supports the following `CompletionItem` specific ---capabilities. --- ---@since 3.17.0 ----@field completionItem? anonym13 +---@field completionItem? lsp._anonym13.completionItem ---Hover options. ----@class lsp.HoverOptions +---@class lsp.HoverOptions: lsp.WorkDoneProgressOptions ---Additional information about the context in which a signature help request was triggered. --- ---@since 3.15.0 ---@class lsp.SignatureHelpContext +--- ---Action that caused signature help to be triggered. ---@field triggerKind lsp.SignatureHelpTriggerKind +--- ---Character that caused signature help to be triggered. --- ---This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter` ---@field triggerCharacter? string +--- ---`true` if signature help was already showing when it was triggered. --- ---Retriggers occurs when the signature help is already active and can be caused by actions such as ---typing a trigger character, a cursor move, or document content changes. ---@field isRetrigger boolean +--- ---The currently active `SignatureHelp`. --- ---The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on @@ -2285,14 +2717,18 @@ error('Cannot require a meta file') ---can have a label, like a function-name, a doc-comment, and ---a set of parameters. ---@class lsp.SignatureInformation +--- ---The label of this signature. Will be shown in ---the UI. ---@field label string +--- ---The human-readable doc-comment of this signature. Will be shown ---in the UI but can be omitted. ---@field documentation? string|lsp.MarkupContent +--- ---The parameters of this signature. ---@field parameters? lsp.ParameterInformation[] +--- ---The index of the active parameter. --- ---If `null`, no parameter of the signature is active (for example a named @@ -2307,9 +2743,11 @@ error('Cannot require a meta file') ---@field activeParameter? uinteger|lsp.null ---Server Capabilities for a {@link SignatureHelpRequest}. ----@class lsp.SignatureHelpOptions +---@class lsp.SignatureHelpOptions: lsp.WorkDoneProgressOptions +--- ---List of characters that trigger signature help automatically. ---@field triggerCharacters? string[] +--- ---List of characters that re-trigger signature help. --- ---These trigger characters are only active when signature help is already showing. All trigger characters @@ -2319,30 +2757,35 @@ error('Cannot require a meta file') ---@field retriggerCharacters? string[] ---Server Capabilities for a {@link DefinitionRequest}. ----@class lsp.DefinitionOptions +---@class lsp.DefinitionOptions: lsp.WorkDoneProgressOptions ---Value-object that contains additional information when ---requesting references. ---@class lsp.ReferenceContext +--- ---Include the declaration of the current symbol. ---@field includeDeclaration boolean ---Reference options. ----@class lsp.ReferenceOptions +---@class lsp.ReferenceOptions: lsp.WorkDoneProgressOptions ---Provider options for a {@link DocumentHighlightRequest}. ----@class lsp.DocumentHighlightOptions +---@class lsp.DocumentHighlightOptions: lsp.WorkDoneProgressOptions ---A base for all symbol information. ---@class lsp.BaseSymbolInformation +--- ---The name of this symbol. ---@field name string +--- ---The kind of this symbol. ---@field kind lsp.SymbolKind +--- ---Tags for this symbol. --- ---@since 3.16.0 ---@field tags? lsp.SymbolTag[] +--- ---The name of the symbol containing this symbol. This information is for ---user interface purposes (e.g. to render a qualifier in the user interface ---if necessary). It can't be used to re-infer a hierarchy for the document @@ -2350,7 +2793,8 @@ error('Cannot require a meta file') ---@field containerName? string ---Provider options for a {@link DocumentSymbolRequest}. ----@class lsp.DocumentSymbolOptions +---@class lsp.DocumentSymbolOptions: lsp.WorkDoneProgressOptions +--- ---A human-readable string that is shown when multiple outlines trees ---are shown for the same document. --- @@ -2360,29 +2804,34 @@ error('Cannot require a meta file') ---Contains additional diagnostic information about the context in which ---a {@link CodeActionProvider.provideCodeActions code action} is run. ---@class lsp.CodeActionContext +--- ---An array of diagnostics known on the client side overlapping the range provided to the ---`textDocument/codeAction` request. They are provided so that the server knows which ---errors are currently presented to the user for the given range. There is no guarantee ---that these accurately reflect the error state of the resource. The primary parameter ---to compute code actions is the provided range. ---@field diagnostics lsp.Diagnostic[] +--- ---Requested kind of actions to return. --- ---Actions not of this kind are filtered out by the client before being shown. So servers ---can omit computing them. ---@field only? lsp.CodeActionKind[] +--- ---The reason why code actions were requested. --- ---@since 3.17.0 ---@field triggerKind? lsp.CodeActionTriggerKind ---Provider options for a {@link CodeActionRequest}. ----@class lsp.CodeActionOptions +---@class lsp.CodeActionOptions: lsp.WorkDoneProgressOptions +--- ---CodeActionKinds that this server may return. --- ---The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server ---may list out every specific kind they provide. ---@field codeActionKinds? lsp.CodeActionKind[] +--- ---The server provides support to resolve additional ---information for a code action. --- @@ -2390,7 +2839,8 @@ error('Cannot require a meta file') ---@field resolveProvider? boolean ---Server capabilities for a {@link WorkspaceSymbolRequest}. ----@class lsp.WorkspaceSymbolOptions +---@class lsp.WorkspaceSymbolOptions: lsp.WorkDoneProgressOptions +--- ---The server provides support to resolve additional ---information for a workspace symbol. --- @@ -2398,39 +2848,47 @@ error('Cannot require a meta file') ---@field resolveProvider? boolean ---Code Lens provider options of a {@link CodeLensRequest}. ----@class lsp.CodeLensOptions +---@class lsp.CodeLensOptions: lsp.WorkDoneProgressOptions +--- ---Code lens has a resolve provider as well. ---@field resolveProvider? boolean ---Provider options for a {@link DocumentLinkRequest}. ----@class lsp.DocumentLinkOptions +---@class lsp.DocumentLinkOptions: lsp.WorkDoneProgressOptions +--- ---Document links have a resolve provider as well. ---@field resolveProvider? boolean ---Value-object describing what options formatting should use. ---@class lsp.FormattingOptions +--- ---Size of a tab in spaces. ---@field tabSize uinteger +--- ---Prefer spaces over tabs. ---@field insertSpaces boolean +--- ---Trim trailing whitespace on a line. --- ---@since 3.15.0 ---@field trimTrailingWhitespace? boolean +--- ---Insert a newline character at the end of the file if one does not exist. --- ---@since 3.15.0 ---@field insertFinalNewline? boolean +--- ---Trim all newlines after the final newline at the end of the file. --- ---@since 3.15.0 ---@field trimFinalNewlines? boolean ---Provider options for a {@link DocumentFormattingRequest}. ----@class lsp.DocumentFormattingOptions +---@class lsp.DocumentFormattingOptions: lsp.WorkDoneProgressOptions ---Provider options for a {@link DocumentRangeFormattingRequest}. ----@class lsp.DocumentRangeFormattingOptions +---@class lsp.DocumentRangeFormattingOptions: lsp.WorkDoneProgressOptions +--- ---Whether the server supports formatting multiple ranges at once. --- ---@since 3.18.0 @@ -2439,32 +2897,39 @@ error('Cannot require a meta file') ---Provider options for a {@link DocumentOnTypeFormattingRequest}. ---@class lsp.DocumentOnTypeFormattingOptions +--- ---A character on which formatting should be triggered, like `{`. ---@field firstTriggerCharacter string +--- ---More trigger characters. ---@field moreTriggerCharacter? string[] ---Provider options for a {@link RenameRequest}. ----@class lsp.RenameOptions +---@class lsp.RenameOptions: lsp.WorkDoneProgressOptions +--- ---Renames should be checked and tested before being executed. --- ---@since version 3.12.0 ---@field prepareProvider? boolean ---The server capabilities of a {@link ExecuteCommandRequest}. ----@class lsp.ExecuteCommandOptions +---@class lsp.ExecuteCommandOptions: lsp.WorkDoneProgressOptions +--- ---The commands to be executed on the server ---@field commands string[] ---@since 3.16.0 ---@class lsp.SemanticTokensLegend +--- ---The token types a server uses. ---@field tokenTypes string[] +--- ---The token modifiers a server uses. ---@field tokenModifiers string[] ---A text document identifier to optionally denote a specific version of a text document. ---@class lsp.OptionalVersionedTextDocumentIdentifier: lsp.TextDocumentIdentifier +--- ---The version number of this document. If a versioned text document identifier ---is sent from the server to the client and the file is not open in the editor ---(the server has not received an open notification before) the server can send @@ -2476,13 +2941,16 @@ error('Cannot require a meta file') --- ---@since 3.16.0. ---@class lsp.AnnotatedTextEdit: lsp.TextEdit +--- ---The actual identifier of the change annotation ---@field annotationId lsp.ChangeAnnotationIdentifier ---A generic resource operation. ---@class lsp.ResourceOperation +--- ---The resource operation kind. ---@field kind string +--- ---An optional annotation identifier describing the operation. --- ---@since 3.16.0 @@ -2490,22 +2958,28 @@ error('Cannot require a meta file') ---Options to create a file. ---@class lsp.CreateFileOptions +--- ---Overwrite existing file. Overwrite wins over `ignoreIfExists` ---@field overwrite? boolean +--- ---Ignore if exists. ---@field ignoreIfExists? boolean ---Rename file options ---@class lsp.RenameFileOptions +--- ---Overwrite target if existing. Overwrite wins over `ignoreIfExists` ---@field overwrite? boolean +--- ---Ignores if target exists. ---@field ignoreIfExists? boolean ---Delete file options ---@class lsp.DeleteFileOptions +--- ---Delete the content recursively if a folder is denoted. ---@field recursive? boolean +--- ---Ignore the operation if the file doesn't exist. ---@field ignoreIfNotExists? boolean @@ -2514,18 +2988,21 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.FileOperationPattern +--- ---The glob pattern to match. Glob patterns can have the following syntax: ---- `*` to match one or more characters in a path segment ---- `?` to match on one character in a path segment ---- `**` to match any number of path segments, including none ----- `{}` to group sub patterns into an OR expression. (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files) +---- `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) ---- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) ---- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) ---@field glob string +--- ---Whether to match files or folders with this pattern. --- ---Matches both if undefined. ---@field matches? lsp.FileOperationPatternKind +--- ---Additional options used during matching. ---@field options? lsp.FileOperationPatternOptions @@ -2533,8 +3010,10 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.WorkspaceFullDocumentDiagnosticReport: lsp.FullDocumentDiagnosticReport +--- ---The URI for which diagnostic information is reported. ---@field uri lsp.DocumentUri +--- ---The version number for which the diagnostics are reported. ---If the document is not marked as open `null` can be provided. ---@field version integer|lsp.null @@ -2543,8 +3022,10 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.WorkspaceUnchangedDocumentDiagnosticReport: lsp.UnchangedDocumentDiagnosticReport +--- ---The URI for which diagnostic information is reported. ---@field uri lsp.DocumentUri +--- ---The version number for which the diagnostics are reported. ---If the document is not marked as open `null` can be provided. ---@field version integer|lsp.null @@ -2557,15 +3038,19 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.NotebookCell +--- ---The cell's kind ---@field kind lsp.NotebookCellKind +--- ---The URI of the cell's text document ---content. ---@field document lsp.DocumentUri +--- ---Additional metadata stored with the cell. --- ---Note: should always be an object literal (e.g. LSPObject) ---@field metadata? lsp.LSPObject +--- ---Additional execution summary information ---if supported by the client. ---@field executionSummary? lsp.ExecutionSummary @@ -2575,10 +3060,13 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.NotebookCellArrayChange +--- ---The start oftest of the cell that changed. ---@field start uinteger +--- ---The deleted cells ---@field deleteCount uinteger +--- ---The new cells, if any ---@field cells? lsp.NotebookCell[] @@ -2587,43 +3075,56 @@ error('Cannot require a meta file') ---@since 3.18.0 ---@proposed ---@class lsp.SelectedCompletionInfo +--- ---The range that will be replaced if this completion item is accepted. ---@field range lsp.Range +--- ---The text the range will be replaced with if this completion is accepted. ---@field text string ---Defines the capabilities provided by the client. ---@class lsp.ClientCapabilities +--- ---Workspace specific client capabilities. ---@field workspace? lsp.WorkspaceClientCapabilities +--- ---Text document specific client capabilities. ---@field textDocument? lsp.TextDocumentClientCapabilities +--- ---Capabilities specific to the notebook document support. --- ---@since 3.17.0 ---@field notebookDocument? lsp.NotebookDocumentClientCapabilities +--- ---Window specific client capabilities. ---@field window? lsp.WindowClientCapabilities +--- ---General client capabilities. --- ---@since 3.16.0 ---@field general? lsp.GeneralClientCapabilities +--- ---Experimental client capabilities. ---@field experimental? lsp.LSPAny ---@class lsp.TextDocumentSyncOptions +--- ---Open and close notifications are sent to the server. If omitted open close notification should not ---be sent. ---@field openClose? boolean +--- ---Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full ---and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None. ---@field change? lsp.TextDocumentSyncKind +--- ---If present will save notifications are sent to the server. If omitted the notification should not be ---sent. ---@field willSave? boolean +--- ---If present will save wait until requests are sent to the server. If omitted the request should not be ---sent. ---@field willSaveWaitUntil? boolean +--- ---If present save notifications are sent to the server. If omitted the notification should not be ---sent. ---@field save? boolean|lsp.SaveOptions @@ -2642,8 +3143,10 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.NotebookDocumentSyncOptions +--- ---The notebooks to be synced ----@field notebookSelector anonym15|anonym17[] +---@field notebookSelector lsp._anonym14.notebookSelector|lsp._anonym16.notebookSelector[] +--- ---Whether save notification should be forwarded to ---the server. Will only be honored if mode === `notebook`. ---@field save? boolean @@ -2654,8 +3157,10 @@ error('Cannot require a meta file') ---@class lsp.NotebookDocumentSyncRegistrationOptions: lsp.NotebookDocumentSyncOptions, lsp.StaticRegistrationOptions ---@class lsp.WorkspaceFoldersServerCapabilities +--- ---The server has support for workspace folders ---@field supported? boolean +--- ---Whether the server wants to receive workspace folder ---change notifications. --- @@ -2669,16 +3174,22 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.FileOperationOptions +--- ---The server is interested in receiving didCreateFiles notifications. ---@field didCreate? lsp.FileOperationRegistrationOptions +--- ---The server is interested in receiving willCreateFiles requests. ---@field willCreate? lsp.FileOperationRegistrationOptions +--- ---The server is interested in receiving didRenameFiles notifications. ---@field didRename? lsp.FileOperationRegistrationOptions +--- ---The server is interested in receiving willRenameFiles requests. ---@field willRename? lsp.FileOperationRegistrationOptions +--- ---The server is interested in receiving didDeleteFiles file notifications. ---@field didDelete? lsp.FileOperationRegistrationOptions +--- ---The server is interested in receiving willDeleteFiles file requests. ---@field willDelete? lsp.FileOperationRegistrationOptions @@ -2686,6 +3197,7 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.CodeDescription +--- ---An URI to open with more information about the diagnostic error. ---@field href lsp.URI @@ -2693,14 +3205,17 @@ error('Cannot require a meta file') ---used to point to code locations that cause or related to a diagnostics, e.g when duplicating ---a symbol in a scope. ---@class lsp.DiagnosticRelatedInformation +--- ---The location of this related diagnostic information. ---@field location lsp.Location +--- ---The message of this related diagnostic information. ---@field message string ---Represents a parameter of a callable-signature. A parameter can ---have a label and a doc-comment. ---@class lsp.ParameterInformation +--- ---The label of this parameter information. --- ---Either a string or an inclusive start and exclusive end offsets within its containing @@ -2710,6 +3225,7 @@ error('Cannot require a meta file') ---*Note*: a label of type string should be a substring of its containing signature label. ---Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`. ---@field label string|{ [1]: uinteger, [2]: uinteger } +--- ---The human-readable doc-comment of this parameter. Will be shown ---in the UI but can be omitted. ---@field documentation? string|lsp.MarkupContent @@ -2719,11 +3235,13 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.NotebookCellTextDocumentFilter +--- ---A filter that matches against the notebook ---containing the notebook cell. If a string ---value is provided it matches against the ---notebook type. '*' matches every notebook. ---@field notebook string|lsp.NotebookDocumentFilter +--- ---A language id like `python`. --- ---Will be matched against the language id of the @@ -2734,71 +3252,89 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.FileOperationPatternOptions +--- ---The pattern should be matched ignoring casing. ---@field ignoreCase? boolean ---@class lsp.ExecutionSummary +--- ---A strict monotonically increasing value ---indicating the execution order of a cell ---inside a notebook. ---@field executionOrder uinteger +--- ---Whether the execution was successful or ---not if known by the client. ---@field success? boolean ---Workspace specific client capabilities. ---@class lsp.WorkspaceClientCapabilities +--- ---The client supports applying batch edits ---to the workspace by supporting the request ---'workspace/applyEdit' ---@field applyEdit? boolean +--- ---Capabilities specific to `WorkspaceEdit`s. ---@field workspaceEdit? lsp.WorkspaceEditClientCapabilities +--- ---Capabilities specific to the `workspace/didChangeConfiguration` notification. ---@field didChangeConfiguration? lsp.DidChangeConfigurationClientCapabilities +--- ---Capabilities specific to the `workspace/didChangeWatchedFiles` notification. ---@field didChangeWatchedFiles? lsp.DidChangeWatchedFilesClientCapabilities +--- ---Capabilities specific to the `workspace/symbol` request. ---@field symbol? lsp.WorkspaceSymbolClientCapabilities +--- ---Capabilities specific to the `workspace/executeCommand` request. ---@field executeCommand? lsp.ExecuteCommandClientCapabilities +--- ---The client has support for workspace folders. --- ---@since 3.6.0 ---@field workspaceFolders? boolean +--- ---The client supports `workspace/configuration` requests. --- ---@since 3.6.0 ---@field configuration? boolean +--- ---Capabilities specific to the semantic token requests scoped to the ---workspace. --- ---@since 3.16.0. ---@field semanticTokens? lsp.SemanticTokensWorkspaceClientCapabilities +--- ---Capabilities specific to the code lens requests scoped to the ---workspace. --- ---@since 3.16.0. ---@field codeLens? lsp.CodeLensWorkspaceClientCapabilities +--- ---The client has support for file notifications/requests for user operations on files. --- ---Since 3.16.0 ---@field fileOperations? lsp.FileOperationClientCapabilities +--- ---Capabilities specific to the inline values requests scoped to the ---workspace. --- ---@since 3.17.0. ---@field inlineValue? lsp.InlineValueWorkspaceClientCapabilities +--- ---Capabilities specific to the inlay hint requests scoped to the ---workspace. --- ---@since 3.17.0. ---@field inlayHint? lsp.InlayHintWorkspaceClientCapabilities +--- ---Capabilities specific to the diagnostic requests scoped to the ---workspace. --- ---@since 3.17.0. ---@field diagnostics? lsp.DiagnosticWorkspaceClientCapabilities +--- ---Capabilities specific to the folding range requests scoped to the workspace. --- ---@since 3.18.0 @@ -2807,95 +3343,126 @@ error('Cannot require a meta file') ---Text document specific client capabilities. ---@class lsp.TextDocumentClientCapabilities +--- ---Defines which synchronization capabilities the client supports. ---@field synchronization? lsp.TextDocumentSyncClientCapabilities +--- ---Capabilities specific to the `textDocument/completion` request. ---@field completion? lsp.CompletionClientCapabilities +--- ---Capabilities specific to the `textDocument/hover` request. ---@field hover? lsp.HoverClientCapabilities +--- ---Capabilities specific to the `textDocument/signatureHelp` request. ---@field signatureHelp? lsp.SignatureHelpClientCapabilities +--- ---Capabilities specific to the `textDocument/declaration` request. --- ---@since 3.14.0 ---@field declaration? lsp.DeclarationClientCapabilities +--- ---Capabilities specific to the `textDocument/definition` request. ---@field definition? lsp.DefinitionClientCapabilities +--- ---Capabilities specific to the `textDocument/typeDefinition` request. --- ---@since 3.6.0 ---@field typeDefinition? lsp.TypeDefinitionClientCapabilities +--- ---Capabilities specific to the `textDocument/implementation` request. --- ---@since 3.6.0 ---@field implementation? lsp.ImplementationClientCapabilities +--- ---Capabilities specific to the `textDocument/references` request. ---@field references? lsp.ReferenceClientCapabilities +--- ---Capabilities specific to the `textDocument/documentHighlight` request. ---@field documentHighlight? lsp.DocumentHighlightClientCapabilities +--- ---Capabilities specific to the `textDocument/documentSymbol` request. ---@field documentSymbol? lsp.DocumentSymbolClientCapabilities +--- ---Capabilities specific to the `textDocument/codeAction` request. ---@field codeAction? lsp.CodeActionClientCapabilities +--- ---Capabilities specific to the `textDocument/codeLens` request. ---@field codeLens? lsp.CodeLensClientCapabilities +--- ---Capabilities specific to the `textDocument/documentLink` request. ---@field documentLink? lsp.DocumentLinkClientCapabilities +--- ---Capabilities specific to the `textDocument/documentColor` and the ---`textDocument/colorPresentation` request. --- ---@since 3.6.0 ---@field colorProvider? lsp.DocumentColorClientCapabilities +--- ---Capabilities specific to the `textDocument/formatting` request. ---@field formatting? lsp.DocumentFormattingClientCapabilities +--- ---Capabilities specific to the `textDocument/rangeFormatting` request. ---@field rangeFormatting? lsp.DocumentRangeFormattingClientCapabilities +--- ---Capabilities specific to the `textDocument/onTypeFormatting` request. ---@field onTypeFormatting? lsp.DocumentOnTypeFormattingClientCapabilities +--- ---Capabilities specific to the `textDocument/rename` request. ---@field rename? lsp.RenameClientCapabilities +--- ---Capabilities specific to the `textDocument/foldingRange` request. --- ---@since 3.10.0 ---@field foldingRange? lsp.FoldingRangeClientCapabilities +--- ---Capabilities specific to the `textDocument/selectionRange` request. --- ---@since 3.15.0 ---@field selectionRange? lsp.SelectionRangeClientCapabilities +--- ---Capabilities specific to the `textDocument/publishDiagnostics` notification. ---@field publishDiagnostics? lsp.PublishDiagnosticsClientCapabilities +--- ---Capabilities specific to the various call hierarchy requests. --- ---@since 3.16.0 ---@field callHierarchy? lsp.CallHierarchyClientCapabilities +--- ---Capabilities specific to the various semantic token request. --- ---@since 3.16.0 ---@field semanticTokens? lsp.SemanticTokensClientCapabilities +--- ---Capabilities specific to the `textDocument/linkedEditingRange` request. --- ---@since 3.16.0 ---@field linkedEditingRange? lsp.LinkedEditingRangeClientCapabilities +--- ---Client capabilities specific to the `textDocument/moniker` request. --- ---@since 3.16.0 ---@field moniker? lsp.MonikerClientCapabilities +--- ---Capabilities specific to the various type hierarchy requests. --- ---@since 3.17.0 ---@field typeHierarchy? lsp.TypeHierarchyClientCapabilities +--- ---Capabilities specific to the `textDocument/inlineValue` request. --- ---@since 3.17.0 ---@field inlineValue? lsp.InlineValueClientCapabilities +--- ---Capabilities specific to the `textDocument/inlayHint` request. --- ---@since 3.17.0 ---@field inlayHint? lsp.InlayHintClientCapabilities +--- ---Capabilities specific to the diagnostic pull model. --- ---@since 3.17.0 ---@field diagnostic? lsp.DiagnosticClientCapabilities +--- ---Client capabilities specific to inline completions. --- ---@since 3.18.0 @@ -2906,12 +3473,14 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.NotebookDocumentClientCapabilities +--- ---Capabilities specific to notebook document synchronization --- ---@since 3.17.0 ---@field synchronization lsp.NotebookDocumentSyncClientCapabilities ---@class lsp.WindowClientCapabilities +--- ---It indicates whether the client supports server initiated ---progress using the `window/workDoneProgress/create` request. --- @@ -2922,10 +3491,12 @@ error('Cannot require a meta file') --- ---@since 3.15.0 ---@field workDoneProgress? boolean +--- ---Capabilities specific to the showMessage request. --- ---@since 3.16.0 ---@field showMessage? lsp.ShowMessageRequestClientCapabilities +--- ---Capabilities specific to the showDocument request. --- ---@since 3.16.0 @@ -2935,21 +3506,25 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.GeneralClientCapabilities +--- ---Client capability that signals how the client ---handles stale requests (e.g. a request ---for which the client will not process the response ---anymore since the information is outdated). --- ---@since 3.17.0 ----@field staleRequestSupport? anonym18 +---@field staleRequestSupport? lsp._anonym18.staleRequestSupport +--- ---Client capabilities specific to regular expressions. --- ---@since 3.16.0 ---@field regularExpressions? lsp.RegularExpressionsClientCapabilities +--- ---Client capabilities specific to the client's markdown parser. --- ---@since 3.16.0 ---@field markdown? lsp.MarkdownClientCapabilities +--- ---The position encodings supported by the client. Client and server ---have to agree on the same position encoding to ensure that offsets ---(e.g. character position in a line) are interpreted the same on both @@ -2976,25 +3551,31 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.RelativePattern +--- ---A workspace folder or a base URI to which this pattern will be matched ---against relatively. ---@field baseUri lsp.WorkspaceFolder|lsp.URI +--- ---The actual glob pattern; ---@field pattern lsp.Pattern ---@class lsp.WorkspaceEditClientCapabilities +--- ---The client supports versioned document changes in `WorkspaceEdit`s ---@field documentChanges? boolean +--- ---The resource operations the client supports. Clients should at least ---support 'create', 'rename' and 'delete' files and folders. --- ---@since 3.13.0 ---@field resourceOperations? lsp.ResourceOperationKind[] +--- ---The failure handling strategy of a client if applying the workspace edit ---fails. --- ---@since 3.13.0 ---@field failureHandling? lsp.FailureHandlingKind +--- ---Whether the client normalizes line endings to the client specific ---setting. ---If set to `true` the client will normalize line ending characters @@ -3003,21 +3584,25 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@field normalizesLineEndings? boolean +--- ---Whether the client in general supports change annotations on text edits, ---create file, rename file and delete file changes. --- ---@since 3.16.0 ----@field changeAnnotationSupport? anonym19 +---@field changeAnnotationSupport? lsp._anonym19.changeAnnotationSupport ---@class lsp.DidChangeConfigurationClientCapabilities +--- ---Did change configuration notification supports dynamic registration. ---@field dynamicRegistration? boolean ---@class lsp.DidChangeWatchedFilesClientCapabilities +--- ---Did change watched files notification supports dynamic registration. Please note ---that the current protocol doesn't support static configuration for file changes ---from the server side. ---@field dynamicRegistration? boolean +--- ---Whether the client has support for {@link RelativePattern relative pattern} ---or not. --- @@ -3026,29 +3611,35 @@ error('Cannot require a meta file') ---Client capabilities for a {@link WorkspaceSymbolRequest}. ---@class lsp.WorkspaceSymbolClientCapabilities +--- ---Symbol request supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. ----@field symbolKind? anonym20 +---@field symbolKind? lsp._anonym20.symbolKind +--- ---The client supports tags on `SymbolInformation`. ---Clients supporting tags have to handle unknown tags gracefully. --- ---@since 3.16.0 ----@field tagSupport? anonym21 +---@field tagSupport? lsp._anonym21.tagSupport +--- ---The client support partial workspace symbols. The client will send the ---request `workspaceSymbol/resolve` to the server to resolve additional ---properties. --- ---@since 3.17.0 ----@field resolveSupport? anonym22 +---@field resolveSupport? lsp._anonym22.resolveSupport ---The client capabilities of a {@link ExecuteCommandRequest}. ---@class lsp.ExecuteCommandClientCapabilities +--- ---Execute command supports dynamic registration. ---@field dynamicRegistration? boolean ---@since 3.16.0 ---@class lsp.SemanticTokensWorkspaceClientCapabilities +--- ---Whether the client implementation supports a refresh request sent from ---the server to the client. --- @@ -3060,6 +3651,7 @@ error('Cannot require a meta file') ---@since 3.16.0 ---@class lsp.CodeLensWorkspaceClientCapabilities +--- ---Whether the client implementation supports a refresh request sent from the ---server to the client. --- @@ -3076,18 +3668,25 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.FileOperationClientCapabilities +--- ---Whether the client supports dynamic registration for file requests/notifications. ---@field dynamicRegistration? boolean +--- ---The client has support for sending didCreateFiles notifications. ---@field didCreate? boolean +--- ---The client has support for sending willCreateFiles requests. ---@field willCreate? boolean +--- ---The client has support for sending didRenameFiles notifications. ---@field didRename? boolean +--- ---The client has support for sending willRenameFiles requests. ---@field willRename? boolean +--- ---The client has support for sending didDeleteFiles notifications. ---@field didDelete? boolean +--- ---The client has support for sending willDeleteFiles requests. ---@field willDelete? boolean @@ -3095,6 +3694,7 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.InlineValueWorkspaceClientCapabilities +--- ---Whether the client implementation supports a refresh request sent from the ---server to the client. --- @@ -3108,6 +3708,7 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.InlayHintWorkspaceClientCapabilities +--- ---Whether the client implementation supports a refresh request sent from ---the server to the client. --- @@ -3121,6 +3722,7 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.DiagnosticWorkspaceClientCapabilities +--- ---Whether the client implementation supports a refresh request sent from ---the server to the client. --- @@ -3135,6 +3737,7 @@ error('Cannot require a meta file') ---@since 3.18.0 ---@proposed ---@class lsp.FoldingRangeWorkspaceClientCapabilities +--- ---Whether the client implementation supports a refresh request sent from the ---server to the client. --- @@ -3148,54 +3751,69 @@ error('Cannot require a meta file') ---@field refreshSupport? boolean ---@class lsp.TextDocumentSyncClientCapabilities +--- ---Whether text document synchronization supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---The client supports sending will save notifications. ---@field willSave? boolean +--- ---The client supports sending a will save request and ---waits for a response providing text edits which will ---be applied to the document before it is saved. ---@field willSaveWaitUntil? boolean +--- ---The client supports did save notifications. ---@field didSave? boolean ---Completion client capabilities ---@class lsp.CompletionClientCapabilities +--- ---Whether completion supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---The client supports the following `CompletionItem` specific ---capabilities. ----@field completionItem? anonym26 ----@field completionItemKind? anonym27 +---@field completionItem? lsp._anonym23.completionItem +--- +---@field completionItemKind? lsp._anonym27.completionItemKind +--- ---Defines how the client handles whitespace and indentation ---when accepting a completion item that uses multi line ---text in either `insertText` or `textEdit`. --- ---@since 3.17.0 ---@field insertTextMode? lsp.InsertTextMode +--- ---The client supports to send additional context information for a ---`textDocument/completion` request. ---@field contextSupport? boolean +--- ---The client supports the following `CompletionList` specific ---capabilities. --- ---@since 3.17.0 ----@field completionList? anonym28 +---@field completionList? lsp._anonym28.completionList ---@class lsp.HoverClientCapabilities +--- ---Whether hover supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---Client supports the following content formats for the content ---property. The order describes the preferred format of the client. ---@field contentFormat? lsp.MarkupKind[] ---Client Capabilities for a {@link SignatureHelpRequest}. ---@class lsp.SignatureHelpClientCapabilities +--- ---Whether signature help supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---The client supports the following `SignatureInformation` ---specific properties. ----@field signatureInformation? anonym30 +---@field signatureInformation? lsp._anonym29.signatureInformation +--- ---The client supports to send additional context information for a ---`textDocument/signatureHelp` request. A client that opts into ---contextSupport will also support the `retriggerCharacters` on @@ -3206,17 +3824,21 @@ error('Cannot require a meta file') ---@since 3.14.0 ---@class lsp.DeclarationClientCapabilities +--- ---Whether declaration supports dynamic registration. If this is set to `true` ---the client supports the new `DeclarationRegistrationOptions` return value ---for the corresponding server capability as well. ---@field dynamicRegistration? boolean +--- ---The client supports additional metadata in the form of declaration links. ---@field linkSupport? boolean ---Client Capabilities for a {@link DefinitionRequest}. ---@class lsp.DefinitionClientCapabilities +--- ---Whether definition supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---The client supports additional metadata in the form of definition links. --- ---@since 3.14.0 @@ -3224,10 +3846,12 @@ error('Cannot require a meta file') ---Since 3.6.0 ---@class lsp.TypeDefinitionClientCapabilities +--- ---Whether implementation supports dynamic registration. If this is set to `true` ---the client supports the new `TypeDefinitionRegistrationOptions` return value ---for the corresponding server capability as well. ---@field dynamicRegistration? boolean +--- ---The client supports additional metadata in the form of definition links. --- ---Since 3.14.0 @@ -3235,10 +3859,12 @@ error('Cannot require a meta file') ---@since 3.6.0 ---@class lsp.ImplementationClientCapabilities +--- ---Whether implementation supports dynamic registration. If this is set to `true` ---the client supports the new `ImplementationRegistrationOptions` return value ---for the corresponding server capability as well. ---@field dynamicRegistration? boolean +--- ---The client supports additional metadata in the form of definition links. --- ---@since 3.14.0 @@ -3246,29 +3872,36 @@ error('Cannot require a meta file') ---Client Capabilities for a {@link ReferencesRequest}. ---@class lsp.ReferenceClientCapabilities +--- ---Whether references supports dynamic registration. ---@field dynamicRegistration? boolean ---Client Capabilities for a {@link DocumentHighlightRequest}. ---@class lsp.DocumentHighlightClientCapabilities +--- ---Whether document highlight supports dynamic registration. ---@field dynamicRegistration? boolean ---Client Capabilities for a {@link DocumentSymbolRequest}. ---@class lsp.DocumentSymbolClientCapabilities +--- ---Whether document symbol supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---Specific capabilities for the `SymbolKind` in the ---`textDocument/documentSymbol` request. ----@field symbolKind? anonym31 +---@field symbolKind? lsp._anonym31.symbolKind +--- ---The client supports hierarchical document symbols. ---@field hierarchicalDocumentSymbolSupport? boolean +--- ---The client supports tags on `SymbolInformation`. Tags are supported on ---`DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true. ---Clients supporting tags have to handle unknown tags gracefully. --- ---@since 3.16.0 ----@field tagSupport? anonym32 +---@field tagSupport? lsp._anonym32.tagSupport +--- ---The client supports an additional label presented in the UI when ---registering a document symbol provider. --- @@ -3277,33 +3910,40 @@ error('Cannot require a meta file') ---The Client Capabilities of a {@link CodeActionRequest}. ---@class lsp.CodeActionClientCapabilities +--- ---Whether code action supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---The client support code action literals of type `CodeAction` as a valid ---response of the `textDocument/codeAction` request. If the property is not ---set the request can only return `Command` literals. --- ---@since 3.8.0 ----@field codeActionLiteralSupport? anonym34 +---@field codeActionLiteralSupport? lsp._anonym33.codeActionLiteralSupport +--- ---Whether code action supports the `isPreferred` property. --- ---@since 3.15.0 ---@field isPreferredSupport? boolean +--- ---Whether code action supports the `disabled` property. --- ---@since 3.16.0 ---@field disabledSupport? boolean +--- ---Whether code action supports the `data` property which is ---preserved between a `textDocument/codeAction` and a ---`codeAction/resolve` request. --- ---@since 3.16.0 ---@field dataSupport? boolean +--- ---Whether the client supports resolving additional code action ---properties via a separate `codeAction/resolve` request. --- ---@since 3.16.0 ----@field resolveSupport? anonym35 +---@field resolveSupport? lsp._anonym35.resolveSupport +--- ---Whether the client honors the change annotations in ---text edits and resource operations returned via the ---`CodeAction#edit` property by for example presenting @@ -3315,19 +3955,23 @@ error('Cannot require a meta file') ---The client capabilities of a {@link CodeLensRequest}. ---@class lsp.CodeLensClientCapabilities +--- ---Whether code lens supports dynamic registration. ---@field dynamicRegistration? boolean ---The client capabilities of a {@link DocumentLinkRequest}. ---@class lsp.DocumentLinkClientCapabilities +--- ---Whether document link supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---Whether the client supports the `tooltip` property on `DocumentLink`. --- ---@since 3.15.0 ---@field tooltipSupport? boolean ---@class lsp.DocumentColorClientCapabilities +--- ---Whether implementation supports dynamic registration. If this is set to `true` ---the client supports the new `DocumentColorRegistrationOptions` return value ---for the corresponding server capability as well. @@ -3335,13 +3979,16 @@ error('Cannot require a meta file') ---Client capabilities of a {@link DocumentFormattingRequest}. ---@class lsp.DocumentFormattingClientCapabilities +--- ---Whether formatting supports dynamic registration. ---@field dynamicRegistration? boolean ---Client capabilities of a {@link DocumentRangeFormattingRequest}. ---@class lsp.DocumentRangeFormattingClientCapabilities +--- ---Whether range formatting supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---Whether the client supports formatting multiple ranges at once. --- ---@since 3.18.0 @@ -3350,17 +3997,21 @@ error('Cannot require a meta file') ---Client capabilities of a {@link DocumentOnTypeFormattingRequest}. ---@class lsp.DocumentOnTypeFormattingClientCapabilities +--- ---Whether on type formatting supports dynamic registration. ---@field dynamicRegistration? boolean ---@class lsp.RenameClientCapabilities +--- ---Whether rename supports dynamic registration. ---@field dynamicRegistration? boolean +--- ---Client supports testing for validity of rename operations ---before execution. --- ---@since 3.12.0 ---@field prepareSupport? boolean +--- ---Client supports the default behavior result. --- ---The value indicates the default behavior used by the @@ -3368,6 +4019,7 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@field prepareSupportDefaultBehavior? lsp.PrepareSupportDefaultBehavior +--- ---Whether the client honors the change annotations in ---text edits and resource operations returned via the ---rename request's workspace edit by for example presenting @@ -3378,29 +4030,35 @@ error('Cannot require a meta file') ---@field honorsChangeAnnotations? boolean ---@class lsp.FoldingRangeClientCapabilities +--- ---Whether implementation supports dynamic registration for folding range ---providers. If this is set to `true` the client supports the new ---`FoldingRangeRegistrationOptions` return value for the corresponding ---server capability as well. ---@field dynamicRegistration? boolean +--- ---The maximum number of folding ranges that the client prefers to receive ---per document. The value serves as a hint, servers are free to follow the ---limit. ---@field rangeLimit? uinteger +--- ---If set, the client signals that it only supports folding complete lines. ---If set, client will ignore specified `startCharacter` and `endCharacter` ---properties in a FoldingRange. ---@field lineFoldingOnly? boolean +--- ---Specific options for the folding range kind. --- ---@since 3.17.0 ----@field foldingRangeKind? anonym36 +---@field foldingRangeKind? lsp._anonym36.foldingRangeKind +--- ---Specific options for the folding range. --- ---@since 3.17.0 ----@field foldingRange? anonym37 +---@field foldingRange? lsp._anonym37.foldingRange ---@class lsp.SelectionRangeClientCapabilities +--- ---Whether implementation supports dynamic registration for selection range providers. If this is set to `true` ---the client supports the new `SelectionRangeRegistrationOptions` return value for the corresponding server ---capability as well. @@ -3408,22 +4066,27 @@ error('Cannot require a meta file') ---The publish diagnostic client capabilities. ---@class lsp.PublishDiagnosticsClientCapabilities +--- ---Whether the clients accepts diagnostics with related information. ---@field relatedInformation? boolean +--- ---Client supports the tag property to provide meta data about a diagnostic. ---Clients supporting tags have to handle unknown tags gracefully. --- ---@since 3.15.0 ----@field tagSupport? anonym38 +---@field tagSupport? lsp._anonym38.tagSupport +--- ---Whether the client interprets the version property of the ---`textDocument/publishDiagnostics` notification's parameter. --- ---@since 3.15.0 ---@field versionSupport? boolean +--- ---Client supports a codeDescription property --- ---@since 3.16.0 ---@field codeDescriptionSupport? boolean +--- ---Whether code action supports the `data` property which is ---preserved between a `textDocument/publishDiagnostics` and ---`textDocument/codeAction` request. @@ -3433,6 +4096,7 @@ error('Cannot require a meta file') ---@since 3.16.0 ---@class lsp.CallHierarchyClientCapabilities +--- ---Whether implementation supports dynamic registration. If this is set to `true` ---the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` ---return value for the corresponding server capability as well. @@ -3440,10 +4104,12 @@ error('Cannot require a meta file') ---@since 3.16.0 ---@class lsp.SemanticTokensClientCapabilities +--- ---Whether implementation supports dynamic registration. If this is set to `true` ---the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` ---return value for the corresponding server capability as well. ---@field dynamicRegistration? boolean +--- ---Which requests the client supports and might send to the server ---depending on the server's capability. Please note that clients might not ---show semantic tokens or degrade some of the user experience if a range @@ -3452,17 +4118,23 @@ error('Cannot require a meta file') ---`request.range` are both set to true but the server only provides a ---range provider the client might not render a minimap correctly or might ---even decide to not show any semantic tokens at all. ----@field requests anonym41 +---@field requests lsp._anonym39.requests +--- ---The token types that the client supports. ---@field tokenTypes string[] +--- ---The token modifiers that the client supports. ---@field tokenModifiers string[] +--- ---The token formats the clients supports. ---@field formats lsp.TokenFormat[] +--- ---Whether the client supports tokens that can overlap each other. ---@field overlappingTokenSupport? boolean +--- ---Whether the client supports tokens that can span multiple lines. ---@field multilineTokenSupport? boolean +--- ---Whether the client allows the server to actively cancel a ---semantic token request, e.g. supports returning ---LSPErrorCodes.ServerCancelled. If a server does the client @@ -3470,6 +4142,7 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@field serverCancelSupport? boolean +--- ---Whether the client uses semantic tokens to augment existing ---syntax tokens. If set to `true` client side created syntax ---tokens and semantic tokens are both used for colorization. If @@ -3486,6 +4159,7 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.LinkedEditingRangeClientCapabilities +--- ---Whether implementation supports dynamic registration. If this is set to `true` ---the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` ---return value for the corresponding server capability as well. @@ -3495,6 +4169,7 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.MonikerClientCapabilities +--- ---Whether moniker supports dynamic registration. If this is set to `true` ---the client supports the new `MonikerRegistrationOptions` return value ---for the corresponding server capability as well. @@ -3502,6 +4177,7 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@class lsp.TypeHierarchyClientCapabilities +--- ---Whether implementation supports dynamic registration. If this is set to `true` ---the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` ---return value for the corresponding server capability as well. @@ -3511,6 +4187,7 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.InlineValueClientCapabilities +--- ---Whether implementation supports dynamic registration for inline value providers. ---@field dynamicRegistration? boolean @@ -3518,20 +4195,24 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.InlayHintClientCapabilities +--- ---Whether inlay hints support dynamic registration. ---@field dynamicRegistration? boolean +--- ---Indicates which properties a client can resolve lazily on an inlay ---hint. ----@field resolveSupport? anonym42 +---@field resolveSupport? lsp._anonym42.resolveSupport ---Client capabilities specific to diagnostic pull requests. --- ---@since 3.17.0 ---@class lsp.DiagnosticClientCapabilities +--- ---Whether implementation supports dynamic registration. If this is set to `true` ---the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` ---return value for the corresponding server capability as well. ---@field dynamicRegistration? boolean +--- ---Whether the clients supports related documents for document diagnostic pulls. ---@field relatedDocumentSupport? boolean @@ -3540,6 +4221,7 @@ error('Cannot require a meta file') ---@since 3.18.0 ---@proposed ---@class lsp.InlineCompletionClientCapabilities +--- ---Whether implementation supports dynamic registration for inline completion providers. ---@field dynamicRegistration? boolean @@ -3547,23 +4229,27 @@ error('Cannot require a meta file') --- ---@since 3.17.0 ---@class lsp.NotebookDocumentSyncClientCapabilities +--- ---Whether implementation supports dynamic registration. If this is ---set to `true` the client supports the new ---`(TextDocumentRegistrationOptions & StaticRegistrationOptions)` ---return value for the corresponding server capability as well. ---@field dynamicRegistration? boolean +--- ---The client supports sending execution summary data per cell. ---@field executionSummarySupport? boolean ---Show message request client capabilities ---@class lsp.ShowMessageRequestClientCapabilities +--- ---Capabilities specific to the `MessageActionItem` type. ----@field messageActionItem? anonym43 +---@field messageActionItem? lsp._anonym43.messageActionItem ---Client capabilities for the showDocument request. --- ---@since 3.16.0 ---@class lsp.ShowDocumentClientCapabilities +--- ---The client has support for the showDocument ---request. ---@field support boolean @@ -3572,8 +4258,10 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.RegularExpressionsClientCapabilities +--- ---The engine's name. ---@field engine string +--- ---The engine's version. ---@field version? string @@ -3581,10 +4269,13 @@ error('Cannot require a meta file') --- ---@since 3.16.0 ---@class lsp.MarkdownClientCapabilities +--- ---The name of the parser. ---@field parser string +--- ---The version of the parser. ---@field version? string +--- ---A list of HTML tags that the client allows / supports in ---Markdown. --- @@ -3979,11 +4670,11 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@alias lsp.DocumentDiagnosticReport lsp.RelatedFullDocumentDiagnosticReport|lsp.RelatedUnchangedDocumentDiagnosticReport ----@alias lsp.PrepareRenameResult lsp.Range|anonym44|anonym45 +---@alias lsp.PrepareRenameResult lsp.Range|lsp._anonym44.PrepareRenameResult|lsp._anonym45.PrepareRenameResult ---A document selector is the combination of one or many document filters. --- ----@sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`; +---\@sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`; --- ---The use of a string as a document filter is deprecated @since 3.16.0. ---@alias lsp.DocumentSelector lsp.DocumentFilter[] @@ -4000,7 +4691,7 @@ error('Cannot require a meta file') ---An event describing a change to a text document. If only a text is provided ---it is considered to be the full content of the document. ----@alias lsp.TextDocumentContentChangeEvent anonym46|anonym47 +---@alias lsp.TextDocumentContentChangeEvent lsp._anonym46.TextDocumentContentChangeEvent|lsp._anonym47.TextDocumentContentChangeEvent ---MarkedString can be used to render human readable text. It is either a markdown string ---or a code-block that provides a language and a code snippet. The language identifier @@ -4014,7 +4705,7 @@ error('Cannot require a meta file') --- ---Note that markdown strings will be sanitized - that means html will be escaped. ---@deprecated use MarkupContent instead. ----@alias lsp.MarkedString string|anonym48 +---@alias lsp.MarkedString string|lsp._anonym48.MarkedString ---A document filter describes a top level text document or ---a notebook cell document. @@ -4039,120 +4730,145 @@ error('Cannot require a meta file') ---- `*` to match one or more characters in a path segment ---- `?` to match on one character in a path segment ---- `**` to match any number of path segments, including none ----- `{}` to group sub patterns into an OR expression. (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files) +---- `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) ---- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) ---- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) --- ----@sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` ----@sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` +---\@sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` +---\@sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` --- ---@since 3.17.0 ----@alias lsp.TextDocumentFilter anonym49|anonym50|anonym51 +---@alias lsp.TextDocumentFilter lsp._anonym49.TextDocumentFilter|lsp._anonym50.TextDocumentFilter|lsp._anonym51.TextDocumentFilter ---A notebook document filter denotes a notebook document by ---different properties. The properties will be match ---against the notebook's URI (same as with documents) --- ---@since 3.17.0 ----@alias lsp.NotebookDocumentFilter anonym52|anonym53|anonym54 +---@alias lsp.NotebookDocumentFilter lsp._anonym52.NotebookDocumentFilter|lsp._anonym53.NotebookDocumentFilter|lsp._anonym54.NotebookDocumentFilter ---The glob pattern to watch relative to the base path. Glob patterns can have the following syntax: ---- `*` to match one or more characters in a path segment ---- `?` to match on one character in a path segment ---- `**` to match any number of path segments, including none ----- `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files) +---- `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) ---- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) ---- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) --- ---@since 3.17.0 ---@alias lsp.Pattern string ----@class anonym1 +---@class lsp._anonym1.serverInfo +--- ---The name of the server as defined by the server. ---@field name string +--- ---The server's version as defined by the server. ---@field version? string ----@class anonym3 +---@class lsp._anonym3.itemDefaults.editRange +--- ---@field insert lsp.Range +--- ---@field replace lsp.Range ----@class anonym2 +---@class lsp._anonym2.itemDefaults +--- ---A default commit character set. --- ---@since 3.17.0 ---@field commitCharacters? string[] +--- ---A default edit range. --- ---@since 3.17.0 ----@field editRange? lsp.Range|anonym3 +---@field editRange? lsp.Range|lsp._anonym3.itemDefaults.editRange +--- ---A default insert text format. --- ---@since 3.17.0 ---@field insertTextFormat? lsp.InsertTextFormat +--- ---A default insert text mode. --- ---@since 3.17.0 ---@field insertTextMode? lsp.InsertTextMode +--- ---A default data value. --- ---@since 3.17.0 ---@field data? lsp.LSPAny ----@class anonym4 +---@class lsp._anonym4.disabled +--- ---Human readable description of why the code action is currently disabled. --- ---This is displayed in the code actions UI. ---@field reason string ----@class anonym5 +---@class lsp._anonym5.location +--- ---@field uri lsp.DocumentUri ----@class anonym6 +---@class lsp._anonym6.range ----@class anonym7 +---@class lsp._anonym7.full +--- ---The server supports deltas for full documents. ---@field delta? boolean ----@class anonym9 +---@class lsp._anonym9.cells.structure +--- ---The change to the cell array. ---@field array lsp.NotebookCellArrayChange +--- ---Additional opened cell text documents. ---@field didOpen? lsp.TextDocumentItem[] +--- ---Additional closed cell text documents. ---@field didClose? lsp.TextDocumentIdentifier[] ----@class anonym10 +---@class lsp._anonym10.cells.textContent +--- ---@field document lsp.VersionedTextDocumentIdentifier +--- ---@field changes lsp.TextDocumentContentChangeEvent[] ----@class anonym8 +---@class lsp._anonym8.cells +--- ---Changes to the cell structure to add or ---remove cells. ----@field structure? anonym9 +---@field structure? lsp._anonym9.cells.structure +--- ---Changes to notebook cells properties like its ---kind, execution summary or metadata. ---@field data? lsp.NotebookCell[] +--- ---Changes to the text content of notebook cells. ----@field textContent? anonym10[] +---@field textContent? lsp._anonym10.cells.textContent[] ----@class anonym11 +---@class lsp._anonym11.clientInfo +--- ---The name of the client as defined by the client. ---@field name string +--- ---The client's version as defined by the client. ---@field version? string ----@class anonym12 +---@class lsp._anonym12.workspace +--- ---The server supports workspace folder. --- ---@since 3.6.0 ---@field workspaceFolders? lsp.WorkspaceFoldersServerCapabilities +--- ---The server is interested in notifications/requests for operations on files. --- ---@since 3.16.0 ---@field fileOperations? lsp.FileOperationOptions ----@class anonym13 +---@class lsp._anonym13.completionItem +--- ---The server has support for completion item label ---details (see also `CompletionItemLabelDetails`) when ---receiving a completion item in a resolve call. @@ -4160,43 +4876,53 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@field labelDetailsSupport? boolean ----@class anonym15 +---@class lsp._anonym15.notebookSelector.cells +--- ---@field language string ----@class anonym14 +---@class lsp._anonym14.notebookSelector +--- ---The notebook to be synced If a string ---value is provided it matches against the ---notebook type. '*' matches every notebook. ---@field notebook string|lsp.NotebookDocumentFilter +--- ---The cells of the matching notebook to be synced. ----@field cells? anonym15[] +---@field cells? lsp._anonym15.notebookSelector.cells[] ----@class anonym17 +---@class lsp._anonym17.notebookSelector.cells +--- ---@field language string ----@class anonym16 +---@class lsp._anonym16.notebookSelector +--- ---The notebook to be synced If a string ---value is provided it matches against the ---notebook type. '*' matches every notebook. ---@field notebook? string|lsp.NotebookDocumentFilter +--- ---The cells of the matching notebook to be synced. ----@field cells anonym17[] +---@field cells lsp._anonym17.notebookSelector.cells[] ----@class anonym18 +---@class lsp._anonym18.staleRequestSupport +--- ---The client will actively cancel the request. ---@field cancel boolean +--- ---The list of requests for which the client ---will retry the request if it receives a ---response with error code `ContentModified` ---@field retryOnContentModified string[] ----@class anonym19 +---@class lsp._anonym19.changeAnnotationSupport +--- ---Whether the client groups edits with equal labels into tree nodes, ---for instance all edits labelled with "Changes in Strings" would ---be a tree node. ---@field groupsOnLabel? boolean ----@class anonym20 +---@class lsp._anonym20.symbolKind +--- ---The symbol kind values the client supports. When this ---property exists the client also guarantees that it will ---handle values outside its set gracefully and falls back @@ -4207,27 +4933,33 @@ error('Cannot require a meta file') ---the initial version of the protocol. ---@field valueSet? lsp.SymbolKind[] ----@class anonym21 +---@class lsp._anonym21.tagSupport +--- ---The tags supported by the client. ---@field valueSet lsp.SymbolTag[] ----@class anonym22 +---@class lsp._anonym22.resolveSupport +--- ---The properties that a client can resolve lazily. Usually ---`location.range` ---@field properties string[] ----@class anonym24 +---@class lsp._anonym24.completionItem.tagSupport +--- ---The tags supported by the client. ---@field valueSet lsp.CompletionItemTag[] ----@class anonym25 +---@class lsp._anonym25.completionItem.resolveSupport +--- ---The properties that a client can resolve lazily. ---@field properties string[] ----@class anonym26 +---@class lsp._anonym26.completionItem.insertTextModeSupport +--- ---@field valueSet lsp.InsertTextMode[] ----@class anonym23 +---@class lsp._anonym23.completionItem +--- ---Client supports snippets as insert text. --- ---A snippet can define tab stops and placeholders with `$1`, `$2` @@ -4235,46 +4967,56 @@ error('Cannot require a meta file') ---the end of the snippet. Placeholders with equal identifiers are linked, ---that is typing in one will update others too. ---@field snippetSupport? boolean +--- ---Client supports commit characters on a completion item. ---@field commitCharactersSupport? boolean +--- ---Client supports the following content formats for the documentation ---property. The order describes the preferred format of the client. ---@field documentationFormat? lsp.MarkupKind[] +--- ---Client supports the deprecated property on a completion item. ---@field deprecatedSupport? boolean +--- ---Client supports the preselect property on a completion item. ---@field preselectSupport? boolean +--- ---Client supports the tag property on a completion item. Clients supporting ---tags have to handle unknown tags gracefully. Clients especially need to ---preserve unknown tags when sending a completion item back to the server in ---a resolve call. --- ---@since 3.15.0 ----@field tagSupport? anonym24 +---@field tagSupport? lsp._anonym24.completionItem.tagSupport +--- ---Client support insert replace edit to control different behavior if a ---completion item is inserted in the text or should replace text. --- ---@since 3.16.0 ---@field insertReplaceSupport? boolean +--- ---Indicates which properties a client can resolve lazily on a completion ---item. Before version 3.16.0 only the predefined properties `documentation` ---and `details` could be resolved lazily. --- ---@since 3.16.0 ----@field resolveSupport? anonym25 +---@field resolveSupport? lsp._anonym25.completionItem.resolveSupport +--- ---The client supports the `insertTextMode` property on ---a completion item to override the whitespace handling mode ---as defined by the client (see `insertTextMode`). --- ---@since 3.16.0 ----@field insertTextModeSupport? anonym26 +---@field insertTextModeSupport? lsp._anonym26.completionItem.insertTextModeSupport +--- ---The client has support for completion item label ---details (see also `CompletionItemLabelDetails`). --- ---@since 3.17.0 ---@field labelDetailsSupport? boolean ----@class anonym27 +---@class lsp._anonym27.completionItemKind +--- ---The completion item kind values the client supports. When this ---property exists the client also guarantees that it will ---handle values outside its set gracefully and falls back @@ -4285,7 +5027,8 @@ error('Cannot require a meta file') ---the initial version of the protocol. ---@field valueSet? lsp.CompletionItemKind[] ----@class anonym28 +---@class lsp._anonym28.completionList +--- ---The client supports the following itemDefaults on ---a completion list. --- @@ -4296,24 +5039,29 @@ error('Cannot require a meta file') ---@since 3.17.0 ---@field itemDefaults? string[] ----@class anonym30 +---@class lsp._anonym30.signatureInformation.parameterInformation +--- ---The client supports processing label offsets instead of a ---simple label string. --- ---@since 3.14.0 ---@field labelOffsetSupport? boolean ----@class anonym29 +---@class lsp._anonym29.signatureInformation +--- ---Client supports the following content formats for the documentation ---property. The order describes the preferred format of the client. ---@field documentationFormat? lsp.MarkupKind[] +--- ---Client capabilities specific to parameter information. ----@field parameterInformation? anonym30 +---@field parameterInformation? lsp._anonym30.signatureInformation.parameterInformation +--- ---The client supports the `activeParameter` property on `SignatureInformation` ---literal. --- ---@since 3.16.0 ---@field activeParameterSupport? boolean +--- ---The client supports the `activeParameter` property on ---`SignatureInformation` being set to `null` to indicate that no ---parameter should be active. @@ -4321,7 +5069,8 @@ error('Cannot require a meta file') ---@since 3.18.0 ---@field noActiveParameterSupport? boolean ----@class anonym31 +---@class lsp._anonym31.symbolKind +--- ---The symbol kind values the client supports. When this ---property exists the client also guarantees that it will ---handle values outside its set gracefully and falls back @@ -4332,138 +5081,177 @@ error('Cannot require a meta file') ---the initial version of the protocol. ---@field valueSet? lsp.SymbolKind[] ----@class anonym32 +---@class lsp._anonym32.tagSupport +--- ---The tags supported by the client. ---@field valueSet lsp.SymbolTag[] ----@class anonym34 +---@class lsp._anonym34.codeActionLiteralSupport.codeActionKind +--- ---The code action kind values the client supports. When this ---property exists the client also guarantees that it will ---handle values outside its set gracefully and falls back ---to a default value when unknown. ---@field valueSet lsp.CodeActionKind[] ----@class anonym33 +---@class lsp._anonym33.codeActionLiteralSupport +--- ---The code action kind is support with the following value ---set. ----@field codeActionKind anonym34 +---@field codeActionKind lsp._anonym34.codeActionLiteralSupport.codeActionKind ----@class anonym35 +---@class lsp._anonym35.resolveSupport +--- ---The properties that a client can resolve lazily. ---@field properties string[] ----@class anonym36 +---@class lsp._anonym36.foldingRangeKind +--- ---The folding range kind values the client supports. When this ---property exists the client also guarantees that it will ---handle values outside its set gracefully and falls back ---to a default value when unknown. ---@field valueSet? lsp.FoldingRangeKind[] ----@class anonym37 +---@class lsp._anonym37.foldingRange +--- ---If set, the client signals that it supports setting collapsedText on ---folding ranges to display custom labels instead of the default text. --- ---@since 3.17.0 ---@field collapsedText? boolean ----@class anonym38 +---@class lsp._anonym38.tagSupport +--- ---The tags supported by the client. ---@field valueSet lsp.DiagnosticTag[] ----@class anonym40 +---@class lsp._anonym40.requests.range ----@class anonym41 +---@class lsp._anonym41.requests.full +--- ---The client will send the `textDocument/semanticTokens/full/delta` request if ---the server provides a corresponding handler. ---@field delta? boolean ----@class anonym39 +---@class lsp._anonym39.requests +--- ---The client will send the `textDocument/semanticTokens/range` request if ---the server provides a corresponding handler. ----@field range? boolean|anonym40 +---@field range? boolean|lsp._anonym40.requests.range +--- ---The client will send the `textDocument/semanticTokens/full` request if ---the server provides a corresponding handler. ----@field full? boolean|anonym41 +---@field full? boolean|lsp._anonym41.requests.full ----@class anonym42 +---@class lsp._anonym42.resolveSupport +--- ---The properties that a client can resolve lazily. ---@field properties string[] ----@class anonym43 +---@class lsp._anonym43.messageActionItem +--- ---Whether the client supports additional attributes which ---are preserved and send back to the server in the ---request's response. ---@field additionalPropertiesSupport? boolean ----@class anonym44 +---@class lsp._anonym44.PrepareRenameResult +--- ---@field range lsp.Range +--- ---@field placeholder string ----@class anonym45 +---@class lsp._anonym45.PrepareRenameResult +--- ---@field defaultBehavior boolean ----@class anonym46 +---@class lsp._anonym46.TextDocumentContentChangeEvent +--- ---The range of the document that changed. ---@field range lsp.Range +--- ---The optional length of the range that got replaced. --- ---@deprecated use range instead. ---@field rangeLength? uinteger +--- ---The new text for the provided range. ---@field text string ----@class anonym47 +---@class lsp._anonym47.TextDocumentContentChangeEvent +--- ---The new text of the whole document. ---@field text string ----@class anonym48 +---@class lsp._anonym48.MarkedString +--- ---@field language string +--- ---@field value string ----@class anonym49 +---@class lsp._anonym49.TextDocumentFilter +--- ---A language id, like `typescript`. ---@field language string +--- ---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ---@field scheme? string ----A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. +--- +---A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. ---@field pattern? string ----@class anonym50 +---@class lsp._anonym50.TextDocumentFilter +--- ---A language id, like `typescript`. ---@field language? string +--- ---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ---@field scheme string ----A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. +--- +---A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. ---@field pattern? string ----@class anonym51 +---@class lsp._anonym51.TextDocumentFilter +--- ---A language id, like `typescript`. ---@field language? string +--- ---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ---@field scheme? string ----A glob pattern, like **​/*.{ts,js}. See TextDocumentFilter for examples. +--- +---A glob pattern, like **/*.{ts,js}. See TextDocumentFilter for examples. ---@field pattern string ----@class anonym52 +---@class lsp._anonym52.NotebookDocumentFilter +--- ---The type of the enclosing notebook. ---@field notebookType string +--- ---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ---@field scheme? string +--- ---A glob pattern. ---@field pattern? string ----@class anonym53 +---@class lsp._anonym53.NotebookDocumentFilter +--- ---The type of the enclosing notebook. ---@field notebookType? string +--- ---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ---@field scheme string +--- ---A glob pattern. ---@field pattern? string ----@class anonym54 +---@class lsp._anonym54.NotebookDocumentFilter +--- ---The type of the enclosing notebook. ---@field notebookType? string +--- ---A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. ---@field scheme? string +--- ---A glob pattern. ---@field pattern string -- cgit From e0eb4188bfabefac54dd7cdcfe57fbb6ddb724b5 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Wed, 27 Dec 2023 09:42:30 +0100 Subject: revert: "fix: correct versions in deprecation warnings" This reverts commit 5cb906e91cb56302d0737aa80e2d890dde452029. They were intentionally fast-tracked. - `parse_snippet()` because of limited scope, and given that it's kinda semi-broken (arbitrary formatting rules, not that useful for what it was used for) - `extract_completion_items()` doesn't work if we want to add the LSP completionlist capability - `text_document_completion_list_to_complete_items()` also doesn't work for completionlist --- runtime/lua/vim/lsp/util.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 90e2f28ef4..ba7ce3c2b6 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -553,7 +553,7 @@ end ---@return lsp.CompletionItem[] List of completion items ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion function M.extract_completion_items(result) - vim.deprecate('vim.lsp.util.extract_completion_items()', nil, '0.12') + vim.deprecate('vim.lsp.util.extract_completion_items()', nil, '0.11') if type(result) == 'table' and result.items then -- result is a `CompletionList` return result.items @@ -613,7 +613,7 @@ end ---@param input string unparsed snippet ---@return string parsed snippet function M.parse_snippet(input) - vim.deprecate('vim.lsp.util.parse_snippet()', nil, '0.12') + vim.deprecate('vim.lsp.util.parse_snippet()', nil, '0.11') local ok, parsed = pcall(function() return snippet.parse(input) end) @@ -635,7 +635,7 @@ end ---@return table[] items ---@see complete-items function M.text_document_completion_list_to_complete_items(result, prefix) - vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.12') + vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.11') return require('vim.lsp._completion')._lsp_to_complete_items(result, prefix) end -- cgit From d51b6157473c4830313b566116aa3ad38dc97412 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Wed, 13 Dec 2023 14:04:24 +0100 Subject: refactor: fix luals warnings --- runtime/lua/vim/lsp/buf.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 051b9d4550..d67b2ac8ea 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -46,7 +46,7 @@ function M.hover() end local function request_with_options(name, params, options) - local req_handler + local req_handler --- @type function? if options then req_handler = function(err, result, ctx, config) local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) -- cgit From 3f788e73b34521f093846d362bf51e68bc9a3827 Mon Sep 17 00:00:00 2001 From: TheLeoP <53507599+TheLeoP@users.noreply.github.com> Date: Tue, 2 Jan 2024 04:08:36 -0500 Subject: feat(lsp): support connect via named pipes/unix domain sockets (#26032) Closes https://github.com/neovim/neovim/issues/26031 Co-authored-by: Mathias Fussenegger --- runtime/lua/vim/lsp/rpc.lua | 253 ++++++++++++++++++++++++++++++++------------ 1 file changed, 186 insertions(+), 67 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 61ad1e479c..b0d98829a6 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -5,8 +5,31 @@ local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedu local is_win = uv.os_uname().version:find('Windows') +---@alias vim.lsp.rpc.Dispatcher fun(method: string, params: table):nil, vim.lsp.rpc.Error? +---@alias vim.lsp.rpc.on_error fun(code: integer, ...: any) +---@alias vim.lsp.rpc.on_exit fun(code: integer, signal: integer) + +---@class vim.lsp.rpc.Dispatchers +---@field notification vim.lsp.rpc.Dispatcher +---@field server_request vim.lsp.rpc.Dispatcher +---@field on_exit vim.lsp.rpc.on_error +---@field on_error vim.lsp.rpc.on_exit + +---@class vim.lsp.rpc.PublicClient +---@field request fun(method: string, params?: table, callback: fun(err: lsp.ResponseError | nil, result: any), notify_reply_callback:function?) +---@field notify fun(method: string, params: any) +---@field is_closing fun(): boolean +---@field terminate fun(): nil + +---@class vim.lsp.rpc.Client +---@field message_index integer +---@field message_callbacks table dict of message_id to callback +---@field notify_reply_callbacks table dict of message_id to callback +---@field transport vim.lsp.rpc.Transport +---@field dispatchers vim.lsp.rpc.Dispatchers + --- Checks whether a given path exists and is a directory. ----@param filename (string) path to check +---@param filename string path to check ---@return boolean local function is_dir(filename) local stat = uv.fs_stat(filename) @@ -15,14 +38,14 @@ end --- Embeds the given string into a table and correctly computes `Content-Length`. --- ----@param encoded_message (string) ----@return string containing encoded message and `Content-Length` attribute -local function format_message_with_content_length(encoded_message) +---@param message string +---@return string message with `Content-Length` attribute +local function format_message_with_content_length(message) return table.concat({ 'Content-Length: ', - tostring(#encoded_message), + tostring(#message), '\r\n\r\n', - encoded_message, + message, }) end @@ -44,13 +67,17 @@ local function log_debug(...) end end +---@class vim.lsp.rpc.Headers: {string: any} +---@field content_length integer + --- Parses an LSP Message's header --- ----@param header string: The header to parse. ----@return table # parsed headers +---@param header string The header to parse. +---@return vim.lsp.rpc.Headers#parsed headers local function parse_headers(header) assert(type(header) == 'string', 'header must be a string') - local headers = {} --- @type table + --- @type vim.lsp.rpc.Headers + local headers = {} for line in vim.gsplit(header, '\r\n', { plain = true }) do if line == '' then break @@ -92,15 +119,25 @@ local function request_parser_loop() -- be searching for. -- TODO(ashkan) I'd like to remove this, but it seems permanent :( local buffer_start = buffer:find(header_start_pattern) + if not buffer_start then + error( + string.format( + "Headers were expected, a different response was received. The server response was '%s'.", + buffer + ) + ) + end local headers = parse_headers(buffer:sub(buffer_start, start - 1)) local content_length = headers.content_length -- Use table instead of just string to buffer the message. It prevents -- a ton of strings allocating. -- ref. http://www.lua.org/pil/11.6.html + ---@type string[] local body_chunks = { buffer:sub(finish + 1) } local body_length = #body_chunks[1] -- Keep waiting for data until we have enough. while body_length < content_length do + ---@type string local chunk = coroutine.yield() or error('Expected more data for the body. The server may have died.') -- TODO hmm. table.insert(body_chunks, chunk) @@ -148,8 +185,8 @@ M.client_errors = vim.tbl_add_reverse_lookup(M.client_errors) --- Constructs an error message from an LSP error object. --- ----@param err (table) The error object ----@returns (string) The formatted error message +---@param err table The error object +---@return string#The formatted error message function M.format_rpc_error(err) validate({ err = { err, 't' }, @@ -176,11 +213,17 @@ function M.format_rpc_error(err) return table.concat(message_parts, ' ') end +---@class vim.lsp.rpc.Error +---@field code integer RPC error code defined by JSON RPC, see `vim.lsp.protocol.ErrorCodes` +---@field message? string arbitrary message to send to server +---@field data? any arbitrary data to send to server + --- Creates an RPC response object/table. --- ----@param code integer RPC error code defined in `vim.lsp.protocol.ErrorCodes` ----@param message string|nil arbitrary message to send to server ----@param data any|nil arbitrary data to send to server +---@param code integer RPC error code defined by JSON RPC +---@param message? string arbitrary message to send to server +---@param data? any arbitrary data to send to server +---@return vim.lsp.rpc.Error function M.rpc_response_error(code, message, data) -- TODO should this error or just pick a sane error (like InternalError)? local code_name = assert(protocol.ErrorCodes[code], 'Invalid RPC error code') @@ -204,7 +247,7 @@ local default_dispatchers = { --- Default dispatcher for notifications sent to an LSP server. --- ---@param method (string) The invoked LSP method - ---@param params (table): Parameters for the invoked LSP method + ---@param params (table) Parameters for the invoked LSP method notification = function(method, params) log_debug('notification', method, params) end, @@ -212,9 +255,9 @@ local default_dispatchers = { --- Default dispatcher for requests sent to an LSP server. --- ---@param method (string) The invoked LSP method - ---@param params (table): Parameters for the invoked LSP method + ---@param params (table) Parameters for the invoked LSP method ---@return nil - ---@return table, `vim.lsp.protocol.ErrorCodes.MethodNotFound` + ---@return vim.lsp.rpc.Error#`vim.lsp.protocol.ErrorCodes.MethodNotFound` server_request = function(method, params) log_debug('server_request', method, params) return nil, M.rpc_response_error(protocol.ErrorCodes.MethodNotFound) @@ -222,8 +265,8 @@ local default_dispatchers = { --- Default dispatcher for when a client exits. --- - ---@param code (integer): Exit code - ---@param signal (integer): Number describing the signal used to terminate (if + ---@param code (integer) Exit code + ---@param signal (integer) Number describing the signal used to terminate (if ---any) on_exit = function(code, signal) log_info('client_exit', { code = code, signal = signal }) @@ -231,17 +274,19 @@ local default_dispatchers = { --- Default dispatcher for client errors. --- - ---@param code (integer): Error code - ---@param err (any): Details about the error + ---@param code (integer) Error code + ---@param err (any) Details about the error ---any) on_error = function(code, err) log_error('client_error:', M.client_errors[code], err) end, } +---@cast default_dispatchers vim.lsp.rpc.Dispatchers + ---@private function M.create_read_loop(handle_body, on_no_chunk, on_error) - local parse_chunk = coroutine.wrap(request_parser_loop) + local parse_chunk = coroutine.wrap(request_parser_loop) --[[@as fun(chunk: string?): vim.lsp.rpc.Headers?, string?]] parse_chunk() return function(err, chunk) if err then @@ -268,14 +313,7 @@ function M.create_read_loop(handle_body, on_no_chunk, on_error) end end ----@class RpcClient ----@field message_index integer ----@field message_callbacks table ----@field notify_reply_callbacks table ----@field transport table ----@field dispatchers table - ----@class RpcClient +---@class vim.lsp.rpc.Client local Client = {} ---@private @@ -284,15 +322,18 @@ function Client:encode_and_send(payload) if self.transport.is_closing() then return false end - local encoded = vim.json.encode(payload) - self.transport.write(format_message_with_content_length(encoded)) + local jsonstr = assert( + vim.json.encode(payload), + string.format("Couldn't encode payload '%s'", vim.inspect(payload)) + ) + self.transport.write(format_message_with_content_length(jsonstr)) return true end ---@package --- Sends a notification to the LSP server. ----@param method (string) The invoked LSP method ----@param params (any): Parameters for the invoked LSP method +---@param method string The invoked LSP method +---@param params any Parameters for the invoked LSP method ---@return boolean `true` if notification could be sent, `false` if not function Client:notify(method, params) return self:encode_and_send({ @@ -316,10 +357,10 @@ end ---@package --- Sends a request to the LSP server and runs {callback} upon response. --- ----@param method (string) The invoked LSP method ----@param params (table|nil) Parameters for the invoked LSP method ----@param callback fun(err: lsp.ResponseError|nil, result: any) Callback to invoke ----@param notify_reply_callback (function|nil) Callback to invoke as soon as a request is no longer pending +---@param method string The invoked LSP method +---@param params? table Parameters for the invoked LSP method +---@param callback fun(err?: lsp.ResponseError, result: any) Callback to invoke +---@param notify_reply_callback? function Callback to invoke as soon as a request is no longer pending ---@return boolean success, integer|nil request_id true, request_id if request could be sent, `false` if not function Client:request(method, params, callback, notify_reply_callback) validate({ @@ -352,6 +393,8 @@ function Client:request(method, params, callback, notify_reply_callback) end ---@package +---@param errkind integer +---@param ... any function Client:on_error(errkind, ...) assert(M.client_errors[errkind]) -- TODO what to do if this fails? @@ -359,6 +402,13 @@ function Client:on_error(errkind, ...) end ---@private +---@param errkind integer +---@param status boolean +---@param head any +---@param ... any +---@return boolean status +---@return any head +---@return any|nil ... function Client:pcall_handler(errkind, status, head, ...) if not status then self:on_error(errkind, head, ...) @@ -368,6 +418,12 @@ function Client:pcall_handler(errkind, status, head, ...) end ---@private +---@param errkind integer +---@param fn function +---@param ... any +---@return boolean status +---@return any head +---@return any|nil ... function Client:try_call(errkind, fn, ...) return self:pcall_handler(errkind, pcall(fn, ...)) end @@ -386,7 +442,7 @@ function Client:handle_body(body) log_debug('rpc.receive', decoded) if type(decoded.method) == 'string' and decoded.id then - local err --- @type table? + local err --- @type vim.lsp.rpc.Error? -- Schedule here so that the users functions don't trigger an error and -- we can still use the result. schedule(function() @@ -412,6 +468,7 @@ function Client:handle_body(body) ) end if err then + ---@cast err vim.lsp.rpc.Error assert( type(err) == 'table', 'err must be a table. Use rpc_response_error to help format errors.' @@ -504,7 +561,14 @@ function Client:handle_body(body) end end ----@return RpcClient +---@class vim.lsp.rpc.Transport +---@field write fun(msg: string): nil +---@field is_closing fun(): boolean|nil +---@field terminate fun(): nil + +---@param dispatchers vim.lsp.rpc.Dispatchers +---@param transport vim.lsp.rpc.Transport +---@return vim.lsp.rpc.Client local function new_client(dispatchers, transport) local state = { message_index = 0, @@ -516,14 +580,8 @@ local function new_client(dispatchers, transport) return setmetatable(state, { __index = Client }) end ---- @class RpcClientPublic ---- @field is_closing fun(): boolean ---- @field terminate fun() ---- @field request fun(method: string, params: table?, callback: function, notify_reply_callbacks?: function) ---- @field notify fun(methid: string, params: table?): boolean - ----@param client RpcClient ----@return RpcClientPublic +---@param client vim.lsp.rpc.Client +---@return vim.lsp.rpc.PublicClient local function public_client(client) local result = {} @@ -540,9 +598,9 @@ local function public_client(client) --- Sends a request to the LSP server and runs {callback} upon response. --- ---@param method (string) The invoked LSP method - ---@param params (table|nil) Parameters for the invoked LSP method + ---@param params (table?) Parameters for the invoked LSP method ---@param callback fun(err: lsp.ResponseError | nil, result: any) Callback to invoke - ---@param notify_reply_callback (function|nil) Callback to invoke as soon as a request is no longer pending + ---@param notify_reply_callback (function?) Callback to invoke as soon as a request is no longer pending ---@return boolean success, integer|nil request_id true, message_id if request could be sent, `false` if not function result.request(method, params, callback, notify_reply_callback) return client:request(method, params, callback, notify_reply_callback) @@ -550,7 +608,7 @@ local function public_client(client) --- Sends a notification to the LSP server. ---@param method (string) The invoked LSP method - ---@param params (table|nil): Parameters for the invoked LSP method + ---@param params (table?) Parameters for the invoked LSP method ---@return boolean `true` if notification could be sent, `false` if not function result.notify(method, params) return client:notify(method, params) @@ -559,13 +617,15 @@ local function public_client(client) return result end ---- @param dispatchers vim.rpc.Dispatchers? ---- @return vim.rpc.Dispatchers +---@param dispatchers? vim.lsp.rpc.Dispatchers +---@return vim.lsp.rpc.Dispatchers local function merge_dispatchers(dispatchers) if dispatchers then local user_dispatchers = dispatchers dispatchers = {} for dispatch_name, default_dispatch in pairs(default_dispatchers) do + ---@cast dispatch_name string + ---@cast default_dispatch function local user_dispatcher = user_dispatchers[dispatch_name] --- @type function if user_dispatcher then if type(user_dispatcher) ~= 'function' then @@ -593,9 +653,9 @@ end --- Create a LSP RPC client factory that connects via TCP to the given host --- and port --- ----@param host string ----@param port integer ----@return function +---@param host string host to connect to +---@param port integer port to connect to +---@return fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient # function intended to be passed to |vim.lsp.start_client()| or |vim.lsp.start()| on the field cmd function M.connect(host, port) return function(dispatchers) dispatchers = merge_dispatchers(dispatchers) @@ -640,23 +700,82 @@ function M.connect(host, port) end end +--- Create a LSP RPC client factory that connects via named pipes (Windows) +--- or unix domain sockets (Unix) to the given pipe_path (file path on +--- Unix and name on Windows) +--- +---@param pipe_path string file path of the domain socket (Unix) or name of the named pipe (Windows) to connect to +---@return fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient#function intended to be passed to |vim.lsp.start_client()| or |vim.lsp.start()| on the field cmd +function M.domain_socket_connect(pipe_path) + return function(dispatchers) + dispatchers = merge_dispatchers(dispatchers) + local pipe = + assert(uv.new_pipe(false), string.format('pipe with name %s could not be opened.', pipe_path)) + local closing = false + local transport = { + write = vim.schedule_wrap(function(msg) + pipe:write(msg) + end), + is_closing = function() + return closing + end, + terminate = function() + if not closing then + closing = true + pipe:shutdown() + pipe:close() + dispatchers.on_exit(0, 0) + end + end, + } + local client = new_client(dispatchers, transport) + pipe:connect(pipe_path, function(err) + if err then + vim.schedule(function() + vim.notify( + string.format('Could not connect to :%s, reason: %s', pipe_path, vim.inspect(err)), + vim.log.levels.WARN + ) + end) + return + end + local handle_body = function(body) + client:handle_body(body) + end + pipe:read_start(M.create_read_loop(handle_body, transport.terminate, function(read_err) + client:on_error(M.client_errors.READ_ERROR, read_err) + end)) + end) + + return public_client(client) + end +end + +---@class vim.lsp.rpc.ExtraSpawnParams +---@field cwd? string Working directory for the LSP server process +---@field detached? boolean Detach the LSP server process from the current process +---@field env? table Additional environment variables for LSP server process. See |vim.system| + --- Starts an LSP server process and create an LSP RPC client object to --- interact with it. Communication with the spawned process happens via stdio. For --- communication via TCP, spawn a process manually and use |vim.lsp.rpc.connect()| --- ----@param cmd (string) Command to start the LSP server. ----@param cmd_args (table) List of additional string arguments to pass to {cmd}. ----@param dispatchers table|nil Dispatchers for LSP message types. Valid ----dispatcher names are: ---- - `"notification"` ---- - `"server_request"` ---- - `"on_error"` ---- - `"on_exit"` ----@param extra_spawn_params table|nil Additional context for the LSP +---@param cmd string Command to start the LSP server. +---@param cmd_args string[] List of additional string arguments to pass to {cmd}. +--- +---@param dispatchers? vim.lsp.rpc.Dispatchers (table|nil) Dispatchers for LSP message types. +--- Valid dispatcher names are: +--- - `"notification"` +--- - `"server_request"` +--- - `"on_error"` +--- - `"on_exit"` +--- +---@param extra_spawn_params? vim.lsp.rpc.ExtraSpawnParams (table|nil) Additional context for the LSP --- server process. May contain: --- - {cwd} (string) Working directory for the LSP server process ---- - {env} (table) Additional environment variables for LSP server process ----@return RpcClientPublic|nil Client RPC object, with these methods: +--- - {detached?} (boolean) Detach the LSP server process from the current process. Defaults to false on Windows and true otherwise. +--- - {env?} (table) Additional environment variables for LSP server process +---@return vim.lsp.rpc.PublicClient? (table|nil) client RPC object, with these methods: --- - `notify()` |vim.lsp.rpc.notify()| --- - `request()` |vim.lsp.rpc.request()| --- - `is_closing()` returns a boolean indicating if the RPC is closing. -- cgit From e0112aa1d21aa01eca867f28f77bcca28aae3b39 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Tue, 2 Jan 2024 10:19:22 +0100 Subject: refactor(lsp): fix remaining luals warnings in lsp.rpc --- runtime/lua/vim/lsp/rpc.lua | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index b0d98829a6..51d6bf4f9f 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -226,6 +226,7 @@ end ---@return vim.lsp.rpc.Error function M.rpc_response_error(code, message, data) -- TODO should this error or just pick a sane error (like InternalError)? + ---@type string local code_name = assert(protocol.ErrorCodes[code], 'Invalid RPC error code') return setmetatable({ code = code, @@ -473,6 +474,7 @@ function Client:handle_body(body) type(err) == 'table', 'err must be a table. Use rpc_response_error to help format errors.' ) + ---@type string local code_name = assert( protocol.ErrorCodes[err.code], 'Errors must use protocol.ErrorCodes. Use rpc_response_error to help format errors.' @@ -620,34 +622,24 @@ end ---@param dispatchers? vim.lsp.rpc.Dispatchers ---@return vim.lsp.rpc.Dispatchers local function merge_dispatchers(dispatchers) - if dispatchers then - local user_dispatchers = dispatchers - dispatchers = {} - for dispatch_name, default_dispatch in pairs(default_dispatchers) do - ---@cast dispatch_name string - ---@cast default_dispatch function - local user_dispatcher = user_dispatchers[dispatch_name] --- @type function - if user_dispatcher then - if type(user_dispatcher) ~= 'function' then - error(string.format('dispatcher.%s must be a function', dispatch_name)) - end - -- server_request is wrapped elsewhere. - if - not (dispatch_name == 'server_request' or dispatch_name == 'on_exit') -- TODO this blocks the loop exiting for some reason. - then - user_dispatcher = schedule_wrap(user_dispatcher) - end - --- @diagnostic disable-next-line:no-unknown - dispatchers[dispatch_name] = user_dispatcher - else - --- @diagnostic disable-next-line:no-unknown - dispatchers[dispatch_name] = default_dispatch - end + if not dispatchers then + return default_dispatchers + end + ---@diagnostic disable-next-line: no-unknown + for name, fn in pairs(dispatchers) do + if type(fn) ~= 'function' then + error(string.format('dispatcher.%s must be a function', name)) end - else - dispatchers = default_dispatchers end - return dispatchers + return { + notification = dispatchers.notification and vim.schedule_wrap(dispatchers.notification) + or default_dispatchers.notification, + on_error = dispatchers.on_error and vim.schedule_wrap(dispatchers.on_error) + or default_dispatchers.on_error, + + on_exit = dispatchers.on_exit or default_dispatchers.on_exit, + server_request = dispatchers.server_request or default_dispatchers.server_request, + } end --- Create a LSP RPC client factory that connects via TCP to the given host -- cgit From 67f53323446d45bad7a22e92493f6402316a8ba1 Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Thu, 28 Dec 2023 18:00:30 -0500 Subject: fix(docs): clean up non-docstring comments for vimdoc gen These non-docstring comments can be included into doxygen's brief description and then appear in the succeeding function documentation. --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index ba7ce3c2b6..44465f6cff 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1069,7 +1069,7 @@ function M.show_document(location, offset_encoding, opts) -- location may be Location or LocationLink local range = location.range or location.targetSelectionRange if range then - --- Jump to new location (adjusting for encoding of characters) + -- Jump to new location (adjusting for encoding of characters) local row = range.start.line local col = get_line_byte_from_position(bufnr, range.start, offset_encoding) api.nvim_win_set_cursor(win, { row + 1, col }) -- cgit From 3734519e3b4ba1bf19ca772104170b0ef776be46 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 2 Jan 2024 15:47:55 +0000 Subject: feat(lua): add noref to deepcopy Problem: Currently `deepcopy` hashes every single tables it copies so it can be reused. For tables of mostly unique items that are non recursive, this hashing is unnecessarily expensive Solution: Port the `noref` argument from Vimscripts `deepcopy()`. The below benchmark demonstrates the results for two extreme cases of tables of different sizes. One table that uses the same table lots of times and one with all unique tables. | test | `noref=false` (ms) | `noref=true` (ms) | | -------------------- | ------------------ | ----------------- | | unique tables (50) | 6.59 | 2.62 | | shared tables (50) | 3.24 | 6.40 | | unique tables (2000) | 23381.48 | 2884.53 | | shared tables (2000) | 3505.54 | 14038.80 | The results are basically the inverse of each other where `noref` is much more performance on tables with unique fields, and `not noref` is more performant on tables that reuse fields. --- runtime/lua/vim/lsp/protocol.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index df12c36396..35eb0305d7 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -314,7 +314,7 @@ local constants = { } for k, v in pairs(constants) do - local tbl = vim.deepcopy(v) + local tbl = vim.deepcopy(v, true) vim.tbl_add_reverse_lookup(tbl) protocol[k] = tbl end -- cgit From 2f9ee9b6cfc61a0504fc0bc22bdf481828e2ea91 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 9 Jan 2024 17:36:46 +0000 Subject: fix(doc): improve doc generation of types using lpeg Added a lpeg grammar for LuaCATS and use it in lua2dox.lua --- runtime/lua/vim/lsp/handlers.lua | 2 +- runtime/lua/vim/lsp/util.lua | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index c03a17fa59..daf09b6430 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -516,7 +516,7 @@ end --- --- Displays call hierarchy in the quickfix window. --- ----@param direction `"from"` for incoming calls and `"to"` for outgoing calls +---@param direction 'from'|'to' `"from"` for incoming calls and `"to"` for outgoing calls ---@return function --- `CallHierarchyIncomingCall[]` if {direction} is `"from"`, --- `CallHierarchyOutgoingCall[]` if {direction} is `"to"`, diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 44465f6cff..a2cc81781a 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -790,7 +790,7 @@ end --- Note that if the input is of type `MarkupContent` and its kind is `plaintext`, --- then the corresponding value is returned without further modifications. --- ----@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`) +---@param input (lsp.MarkedString | lsp.MarkedString[] | lsp.MarkupContent) ---@param contents (table|nil) List of strings to extend with converted lines. Defaults to {}. ---@return string[] extended with lines of converted markdown. ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover @@ -2115,8 +2115,8 @@ end --- Returns the UTF-32 and UTF-16 offsets for a position in a certain buffer. --- ---@param buf integer buffer number (0 for current) ----@param row 0-indexed line ----@param col 0-indexed byte offset in line +---@param row integer 0-indexed line +---@param col integer 0-indexed byte offset in line ---@param offset_encoding string utf-8|utf-16|utf-32 defaults to `offset_encoding` of first client of `buf` ---@return integer `offset_encoding` index of the character in line {row} column {col} in buffer {buf} function M.character_offset(buf, row, col, offset_encoding) -- cgit From ce4ea638c703275aedadb3794efc56dcb782c908 Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Tue, 9 Jan 2024 18:04:27 -0500 Subject: fix(lsp): fix incorrect typing and doc for `vim.lsp.rpc` Typings introduced in #26032 and #26552 have a few conflicts, so we merge and clean them up. We also fix some incorrect type annotation in the `vim.lsp.rpc` package. See the associated PR for more details. Summary: - vim.rpc.Dispatchers -> vim.lsp.rpc.Dispatchers - vim.lsp.rpc.Error -> lsp.ResponseError - Revise docs --- runtime/lua/vim/lsp/rpc.lua | 172 ++++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 86 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 51d6bf4f9f..660b126ce4 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -5,29 +5,6 @@ local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedu local is_win = uv.os_uname().version:find('Windows') ----@alias vim.lsp.rpc.Dispatcher fun(method: string, params: table):nil, vim.lsp.rpc.Error? ----@alias vim.lsp.rpc.on_error fun(code: integer, ...: any) ----@alias vim.lsp.rpc.on_exit fun(code: integer, signal: integer) - ----@class vim.lsp.rpc.Dispatchers ----@field notification vim.lsp.rpc.Dispatcher ----@field server_request vim.lsp.rpc.Dispatcher ----@field on_exit vim.lsp.rpc.on_error ----@field on_error vim.lsp.rpc.on_exit - ----@class vim.lsp.rpc.PublicClient ----@field request fun(method: string, params?: table, callback: fun(err: lsp.ResponseError | nil, result: any), notify_reply_callback:function?) ----@field notify fun(method: string, params: any) ----@field is_closing fun(): boolean ----@field terminate fun(): nil - ----@class vim.lsp.rpc.Client ----@field message_index integer ----@field message_callbacks table dict of message_id to callback ----@field notify_reply_callbacks table dict of message_id to callback ----@field transport vim.lsp.rpc.Transport ----@field dispatchers vim.lsp.rpc.Dispatchers - --- Checks whether a given path exists and is a directory. ---@param filename string path to check ---@return boolean @@ -186,7 +163,7 @@ M.client_errors = vim.tbl_add_reverse_lookup(M.client_errors) --- Constructs an error message from an LSP error object. --- ---@param err table The error object ----@return string#The formatted error message +---@return string error_message The formatted error message function M.format_rpc_error(err) validate({ err = { err, 't' }, @@ -213,17 +190,14 @@ function M.format_rpc_error(err) return table.concat(message_parts, ' ') end ----@class vim.lsp.rpc.Error ----@field code integer RPC error code defined by JSON RPC, see `vim.lsp.protocol.ErrorCodes` ----@field message? string arbitrary message to send to server ----@field data? any arbitrary data to send to server - ---- Creates an RPC response object/table. +--- Creates an RPC response table `error` to be sent to the LSP response. --- ----@param code integer RPC error code defined by JSON RPC +---@param code integer RPC error code defined, see `vim.lsp.protocol.ErrorCodes` ---@param message? string arbitrary message to send to server ---@param data? any arbitrary data to send to server ----@return vim.lsp.rpc.Error +--- +---@see lsp.ErrorCodes See `vim.lsp.protocol.ErrorCodes` +---@return lsp.ResponseError function M.rpc_response_error(code, message, data) -- TODO should this error or just pick a sane error (like InternalError)? ---@type string @@ -237,28 +211,28 @@ function M.rpc_response_error(code, message, data) }) end ---- @class vim.rpc.Dispatchers +--- @class vim.lsp.rpc.Dispatchers --- @field notification fun(method: string, params: table) ---- @field server_request fun(method: string, params: table): any?, string? +--- @field server_request fun(method: string, params: table): any?, lsp.ResponseError? --- @field on_exit fun(code: integer, signal: integer) --- @field on_error fun(code: integer, err: any) ---- @type vim.rpc.Dispatchers +--- @type vim.lsp.rpc.Dispatchers local default_dispatchers = { --- Default dispatcher for notifications sent to an LSP server. --- - ---@param method (string) The invoked LSP method - ---@param params (table) Parameters for the invoked LSP method + ---@param method string The invoked LSP method + ---@param params table Parameters for the invoked LSP method notification = function(method, params) log_debug('notification', method, params) end, --- Default dispatcher for requests sent to an LSP server. --- - ---@param method (string) The invoked LSP method - ---@param params (table) Parameters for the invoked LSP method - ---@return nil - ---@return vim.lsp.rpc.Error#`vim.lsp.protocol.ErrorCodes.MethodNotFound` + ---@param method string The invoked LSP method + ---@param params table Parameters for the invoked LSP method + ---@return any result (always nil for the default dispatchers) + ---@return lsp.ResponseError error `vim.lsp.protocol.ErrorCodes.MethodNotFound` server_request = function(method, params) log_debug('server_request', method, params) return nil, M.rpc_response_error(protocol.ErrorCodes.MethodNotFound) @@ -266,25 +240,21 @@ local default_dispatchers = { --- Default dispatcher for when a client exits. --- - ---@param code (integer) Exit code - ---@param signal (integer) Number describing the signal used to terminate (if - ---any) + ---@param code integer Exit code + ---@param signal integer Number describing the signal used to terminate (if any) on_exit = function(code, signal) log_info('client_exit', { code = code, signal = signal }) end, --- Default dispatcher for client errors. --- - ---@param code (integer) Error code - ---@param err (any) Details about the error - ---any) + ---@param code integer Error code + ---@param err any Details about the error on_error = function(code, err) log_error('client_error:', M.client_errors[code], err) end, } ----@cast default_dispatchers vim.lsp.rpc.Dispatchers - ---@private function M.create_read_loop(handle_body, on_no_chunk, on_error) local parse_chunk = coroutine.wrap(request_parser_loop) --[[@as fun(chunk: string?): vim.lsp.rpc.Headers?, string?]] @@ -314,6 +284,14 @@ function M.create_read_loop(handle_body, on_no_chunk, on_error) end end +---@private +---@class vim.lsp.rpc.Client +---@field message_index integer +---@field message_callbacks table dict of message_id to callback +---@field notify_reply_callbacks table dict of message_id to callback +---@field transport vim.lsp.rpc.Transport +---@field dispatchers vim.lsp.rpc.Dispatchers + ---@class vim.lsp.rpc.Client local Client = {} @@ -356,13 +334,14 @@ function Client:send_response(request_id, err, result) end ---@package ---- Sends a request to the LSP server and runs {callback} upon response. +--- Sends a request to the LSP server and runs {callback} upon response. |vim.lsp.rpc.request()| --- ---@param method string The invoked LSP method ----@param params? table Parameters for the invoked LSP method +---@param params table? Parameters for the invoked LSP method ---@param callback fun(err?: lsp.ResponseError, result: any) Callback to invoke ----@param notify_reply_callback? function Callback to invoke as soon as a request is no longer pending ----@return boolean success, integer|nil request_id true, request_id if request could be sent, `false` if not +---@param notify_reply_callback fun(message_id: integer)|nil Callback to invoke as soon as a request is no longer pending +---@return boolean success `true` if request could be sent, `false` if not +---@return integer? message_id if request could be sent, `nil` if not function Client:request(method, params, callback, notify_reply_callback) validate({ callback = { callback, 'f' }, @@ -382,14 +361,14 @@ function Client:request(method, params, callback, notify_reply_callback) if message_callbacks then message_callbacks[message_id] = schedule_wrap(callback) else - return false + return false, nil end if notify_reply_callback and notify_reply_callbacks then notify_reply_callbacks[message_id] = schedule_wrap(notify_reply_callback) end return result, message_id else - return false + return false, nil end end @@ -443,7 +422,7 @@ function Client:handle_body(body) log_debug('rpc.receive', decoded) if type(decoded.method) == 'string' and decoded.id then - local err --- @type vim.lsp.rpc.Error? + local err --- @type lsp.ResponseError|nil -- Schedule here so that the users functions don't trigger an error and -- we can still use the result. schedule(function() @@ -469,7 +448,7 @@ function Client:handle_body(body) ) end if err then - ---@cast err vim.lsp.rpc.Error + ---@cast err lsp.ResponseError assert( type(err) == 'table', 'err must be a table. Use rpc_response_error to help format errors.' @@ -564,9 +543,9 @@ function Client:handle_body(body) end ---@class vim.lsp.rpc.Transport ----@field write fun(msg: string): nil ----@field is_closing fun(): boolean|nil ----@field terminate fun(): nil +---@field write fun(msg: string) +---@field is_closing fun(): boolean +---@field terminate fun() ---@param dispatchers vim.lsp.rpc.Dispatchers ---@param transport vim.lsp.rpc.Transport @@ -582,9 +561,17 @@ local function new_client(dispatchers, transport) return setmetatable(state, { __index = Client }) end +---@class vim.lsp.rpc.PublicClient +---@field request fun(method: string, params: table?, callback: fun(err: lsp.ResponseError|nil, result: any), notify_reply_callback: fun(integer)|nil):boolean,integer? see |vim.lsp.rpc.request()| +---@field notify fun(method: string, params: any):boolean see |vim.lsp.rpc.notify()| +---@field is_closing fun(): boolean +---@field terminate fun() + ---@param client vim.lsp.rpc.Client ---@return vim.lsp.rpc.PublicClient local function public_client(client) + ---@type vim.lsp.rpc.PublicClient + ---@diagnostic disable-next-line: missing-fields local result = {} ---@private @@ -601,9 +588,10 @@ local function public_client(client) --- ---@param method (string) The invoked LSP method ---@param params (table?) Parameters for the invoked LSP method - ---@param callback fun(err: lsp.ResponseError | nil, result: any) Callback to invoke - ---@param notify_reply_callback (function?) Callback to invoke as soon as a request is no longer pending - ---@return boolean success, integer|nil request_id true, message_id if request could be sent, `false` if not + ---@param callback fun(err: lsp.ResponseError|nil, result: any) Callback to invoke + ---@param notify_reply_callback fun(message_id: integer)|nil Callback to invoke as soon as a request is no longer pending + ---@return boolean success `true` if request could be sent, `false` if not + ---@return integer? message_id if request could be sent, `nil` if not function result.request(method, params, callback, notify_reply_callback) return client:request(method, params, callback, notify_reply_callback) end @@ -619,7 +607,7 @@ local function public_client(client) return result end ----@param dispatchers? vim.lsp.rpc.Dispatchers +---@param dispatchers vim.lsp.rpc.Dispatchers? ---@return vim.lsp.rpc.Dispatchers local function merge_dispatchers(dispatchers) if not dispatchers then @@ -631,23 +619,30 @@ local function merge_dispatchers(dispatchers) error(string.format('dispatcher.%s must be a function', name)) end end - return { - notification = dispatchers.notification and vim.schedule_wrap(dispatchers.notification) - or default_dispatchers.notification, - on_error = dispatchers.on_error and vim.schedule_wrap(dispatchers.on_error) - or default_dispatchers.on_error, - + ---@type vim.lsp.rpc.Dispatchers + local merged = { + notification = ( + dispatchers.notification and vim.schedule_wrap(dispatchers.notification) + or default_dispatchers.notification + ), + on_error = ( + dispatchers.on_error and vim.schedule_wrap(dispatchers.on_error) + or default_dispatchers.on_error + ), on_exit = dispatchers.on_exit or default_dispatchers.on_exit, server_request = dispatchers.server_request or default_dispatchers.server_request, } + return merged end ---- Create a LSP RPC client factory that connects via TCP to the given host ---- and port +--- Create a LSP RPC client factory that connects via TCP to the given host and port. +--- +--- Return a function that can be passed to the `cmd` field for +--- |vim.lsp.start_client()| or |vim.lsp.start()|. --- ---@param host string host to connect to ---@param port integer port to connect to ----@return fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient # function intended to be passed to |vim.lsp.start_client()| or |vim.lsp.start()| on the field cmd +---@return fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient function M.connect(host, port) return function(dispatchers) dispatchers = merge_dispatchers(dispatchers) @@ -694,10 +689,13 @@ end --- Create a LSP RPC client factory that connects via named pipes (Windows) --- or unix domain sockets (Unix) to the given pipe_path (file path on ---- Unix and name on Windows) +--- Unix and name on Windows). +--- +--- Return a function that can be passed to the `cmd` field for +--- |vim.lsp.start_client()| or |vim.lsp.start()|. --- ---@param pipe_path string file path of the domain socket (Unix) or name of the named pipe (Windows) to connect to ----@return fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient#function intended to be passed to |vim.lsp.start_client()| or |vim.lsp.start()| on the field cmd +---@return fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient function M.domain_socket_connect(pipe_path) return function(dispatchers) dispatchers = merge_dispatchers(dispatchers) @@ -755,23 +753,25 @@ end ---@param cmd string Command to start the LSP server. ---@param cmd_args string[] List of additional string arguments to pass to {cmd}. --- ----@param dispatchers? vim.lsp.rpc.Dispatchers (table|nil) Dispatchers for LSP message types. +---@param dispatchers? vim.lsp.rpc.Dispatchers Dispatchers for LSP message types. --- Valid dispatcher names are: --- - `"notification"` --- - `"server_request"` --- - `"on_error"` --- - `"on_exit"` --- ----@param extra_spawn_params? vim.lsp.rpc.ExtraSpawnParams (table|nil) Additional context for the LSP +---@param extra_spawn_params? vim.lsp.rpc.ExtraSpawnParams Additional context for the LSP --- server process. May contain: ---- - {cwd} (string) Working directory for the LSP server process ---- - {detached?} (boolean) Detach the LSP server process from the current process. Defaults to false on Windows and true otherwise. ---- - {env?} (table) Additional environment variables for LSP server process ----@return vim.lsp.rpc.PublicClient? (table|nil) client RPC object, with these methods: ---- - `notify()` |vim.lsp.rpc.notify()| ---- - `request()` |vim.lsp.rpc.request()| ---- - `is_closing()` returns a boolean indicating if the RPC is closing. ---- - `terminate()` terminates the RPC client. +--- - {cwd} (string) Working directory for the LSP server process +--- - {detached?} (boolean) Detach the LSP server process from the current process. +--- Defaults to false on Windows and true otherwise. +--- - {env?} (table) Additional environment variables for LSP server process +--- +---@return vim.lsp.rpc.PublicClient? Client RPC object, with these methods: +--- - `notify()` |vim.lsp.rpc.notify()| +--- - `request()` |vim.lsp.rpc.request()| +--- - `is_closing()` returns a boolean indicating if the RPC is closing. +--- - `terminate()` terminates the RPC client. function M.start(cmd, cmd_args, dispatchers, extra_spawn_params) log_info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params }) @@ -846,7 +846,7 @@ function M.start(cmd, cmd_args, dispatchers, extra_spawn_params) end local msg = string.format('Spawning language server with cmd: `%s` failed%s', cmd, sfx) vim.notify(msg, vim.log.levels.WARN) - return + return nil end sysobj = sysobj_or_err --[[@as vim.SystemObj]] -- cgit From 4d91604c8868b7afaf429cc16b72192ce89ea698 Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Sun, 14 Jan 2024 22:37:07 -0500 Subject: docs: add lua typing for `vim.NIL` --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index a2cc81781a..50890e37ce 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -2139,7 +2139,7 @@ end --- ---@param settings table language server settings ---@param section string indicating the field of the settings table ----@return table|string The value of settings accessed via section +---@return table|string|vim.NIL The value of settings accessed via section. `vim.NIL` if not found. function M.lookup_section(settings, section) for part in vim.gsplit(section, '.', { plain = true }) do settings = settings[part] -- cgit From 3973a5e40505422c7ac42692eaecc1ff84f89e7f Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Sun, 14 Jan 2024 23:12:54 -0500 Subject: refactor(lsp): deprecate `vim.lsp.util.lookup_section` This function is used only in the `workspace/configuration` handler, and does not warrant a public API because of its confusing return types. The only caller `vim.lsp.handlers["workspace.configuration"]` is also refactored to use `vim.tbl_get()` instead. --- runtime/lua/vim/lsp/handlers.lua | 17 ++++++++++++++--- runtime/lua/vim/lsp/util.lua | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index daf09b6430..6ed8e1d40f 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -170,6 +170,14 @@ M[ms.workspace_applyEdit] = function(_, workspace_edit, ctx) } end +---@param table table e.g., { foo = { bar = "z" } } +---@param section string indicating the field of the table, e.g., "foo.bar" +---@return any|nil setting value read from the table, or `nil` not found +local function lookup_section(table, section) + local keys = vim.split(section, '.', { plain = true }) --- @type string[] + return vim.tbl_get(table, unpack(keys)) +end + --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration M[ms.workspace_configuration] = function(_, result, ctx) local client_id = ctx.client_id @@ -189,10 +197,13 @@ M[ms.workspace_configuration] = function(_, result, ctx) local response = {} for _, item in ipairs(result.items) do if item.section then - local value = util.lookup_section(client.config.settings, item.section) + local value = lookup_section(client.config.settings, item.section) -- For empty sections with no explicit '' key, return settings as is - if value == vim.NIL and item.section == '' then - value = client.config.settings or vim.NIL + if value == nil and item.section == '' then + value = client.config.settings + end + if value == nil then + value = vim.NIL end table.insert(response, value) end diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 50890e37ce..cee09d85e0 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -2140,7 +2140,9 @@ end ---@param settings table language server settings ---@param section string indicating the field of the settings table ---@return table|string|vim.NIL The value of settings accessed via section. `vim.NIL` if not found. +---@deprecated function M.lookup_section(settings, section) + vim.deprecate('vim.lsp.util.lookup_section()', 'vim.tbl_get() with `vim.split`', '0.12') for part in vim.gsplit(section, '.', { plain = true }) do settings = settings[part] if settings == nil then -- cgit From 95cbedaa1798a7c1489b68dd60380a41443ed34b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 18 Jan 2024 00:14:48 -0800 Subject: docs: various #25289 Co-authored-by: Jongwook Choi Co-authored-by: Oliver Marriott Co-authored-by: Benoit de Chezelles Co-authored-by: Jongwook Choi --- runtime/lua/vim/lsp/inlay_hint.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index ce1680549e..4816b873ba 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -368,7 +368,13 @@ function M.is_enabled(bufnr) return bufstates[bufnr] and bufstates[bufnr].enabled or false end ---- Enable/disable/toggle inlay hints for a buffer +--- Enables or disables inlay hints for a buffer. +--- +--- To "toggle", pass the inverse of `is_enabled()`: +--- +--- ```lua +--- vim.lsp.inlay_hint.enable(0, not vim.lsp.inlay_hint.is_enabled()) +--- ``` --- --- @param bufnr (integer|nil) Buffer handle, or 0 or nil for current --- @param enable (boolean|nil) true/nil to enable, false to disable -- cgit From fa9a85ae468b9df30ae9e5c05a08c0f124e267df Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Tue, 16 Jan 2024 19:19:21 -0500 Subject: fix(lsp): clean up duplicate and unused meta type annotations --- runtime/lua/vim/lsp/_meta.lua | 7 ------- runtime/lua/vim/lsp/_meta/protocol.lua | 13 +++++++------ 2 files changed, 7 insertions(+), 13 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_meta.lua b/runtime/lua/vim/lsp/_meta.lua index 559939c236..be3222828d 100644 --- a/runtime/lua/vim/lsp/_meta.lua +++ b/runtime/lua/vim/lsp/_meta.lua @@ -14,10 +14,3 @@ error('Cannot require a meta file') ---@field code integer ---@field message string ---@field data string|number|boolean|table[]|table|nil - ---- @class lsp.DocumentFilter ---- @field language? string ---- @field scheme? string ---- @field pattern? string - ---- @alias lsp.RegisterOptions any | lsp.StaticRegistrationOptions | lsp.TextDocumentRegistrationOptions diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua index 4c053cb57e..b897b6bba5 100644 --- a/runtime/lua/vim/lsp/_meta/protocol.lua +++ b/runtime/lua/vim/lsp/_meta/protocol.lua @@ -1,7 +1,11 @@ --[[ -This file is autogenerated from scripts/gen_lsp.lua +THIS FILE IS GENERATED by scripts/gen_lsp.lua +DO NOT EDIT MANUALLY + +Based on LSP protocol 3.18 + Regenerate: -nvim -l scripts/gen_lsp.lua gen --version 3.18 --out runtime/lua/vim/lsp/_meta/protocol.lua +nvim -l scripts/gen_lsp.lua gen --version 3.18 --]] ---@meta @@ -9,12 +13,9 @@ error('Cannot require a meta file') ---@alias lsp.null nil ---@alias uinteger integer ----@alias lsp.decimal number +---@alias decimal number ---@alias lsp.DocumentUri string ---@alias lsp.URI string ----@alias lsp.LSPObject table ----@alias lsp.LSPArray lsp.LSPAny[] ----@alias lsp.LSPAny lsp.LSPObject|lsp.LSPArray|string|number|boolean|nil ---@class lsp.ImplementationParams: lsp.TextDocumentPositionParams, lsp.WorkDoneProgressParams, lsp.PartialResultParams -- cgit From eee52d3427e2c97c0e9a9347bafdd55d49830ec7 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 28 Jan 2024 18:38:36 -0800 Subject: refactor(lsp): client_hints typo #27250 --- runtime/lua/vim/lsp/inlay_hint.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index 4816b873ba..62138c0edf 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -6,7 +6,7 @@ local M = {} ---@class lsp.inlay_hint.bufstate ---@field version? integer ----@field client_hint? table> client_id -> (lnum -> hints) +---@field client_hints? table> client_id -> (lnum -> hints) ---@field applied table Last version of hints applied to this line ---@field enabled boolean Whether inlay hints are enabled for this buffer ---@type table @@ -39,11 +39,11 @@ function M.on_inlayhint(err, result, ctx, _) if not bufstate or not bufstate.enabled then return end - if not (bufstate.client_hint and bufstate.version) then - bufstate.client_hint = vim.defaulttable() + if not (bufstate.client_hints and bufstate.version) then + bufstate.client_hints = vim.defaulttable() bufstate.version = ctx.version end - local hints_by_client = bufstate.client_hint + local hints_by_client = bufstate.client_hints local client = assert(vim.lsp.get_client_by_id(client_id)) local new_hints_by_lnum = vim.defaulttable() @@ -162,7 +162,7 @@ function M.get(filter) end local bufstate = bufstates[bufnr] - if not (bufstate and bufstate.client_hint) then + if not (bufstate and bufstate.client_hints) then return {} end @@ -185,7 +185,7 @@ function M.get(filter) --- @type vim.lsp.inlay_hint.get.ret[] local hints = {} for _, client in pairs(clients) do - local hints_by_lnum = bufstate.client_hint[client.id] + local hints_by_lnum = bufstate.client_hints[client.id] if hints_by_lnum then for lnum = range.start.line, range['end'].line do local line_hints = hints_by_lnum[lnum] or {} @@ -218,11 +218,11 @@ local function clear(bufnr) return end local bufstate = bufstates[bufnr] - local client_lens = (bufstate or {}).client_hint or {} + local client_lens = (bufstate or {}).client_hints or {} local client_ids = vim.tbl_keys(client_lens) --- @type integer[] for _, iter_client_id in ipairs(client_ids) do if bufstate then - bufstate.client_hint[iter_client_id] = {} + bufstate.client_hints[iter_client_id] = {} end end api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1) @@ -319,7 +319,7 @@ api.nvim_set_decoration_provider(namespace, { if bufstate.version ~= util.buf_versions[bufnr] then return end - local hints_by_client = assert(bufstate.client_hint) + local hints_by_client = assert(bufstate.client_hints) for lnum = topline, botline do if bufstate.applied[lnum] ~= bufstate.version then -- cgit From 2e982f1aad9f1a03562b7a451d642f76b04c37cb Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 22 Jan 2024 18:23:28 +0100 Subject: refactor: create function for deferred loading The benefit of this is that users only pay for what they use. If e.g. only `vim.lsp.buf_get_clients()` is called then they don't need to load all modules under `vim.lsp` which could lead to significant startuptime saving. Also `vim.lsp.module` is a bit nicer to user compared to `require("vim.lsp.module")`. This isn't used for some nested modules such as `filetype` as it breaks tests with error messages such as "attempt to index field 'detect'". It's not entirely certain the reason for this, but it is likely it is due to filetype being precompiled which would imply deferred loading isn't needed for performance reasons. --- runtime/lua/vim/lsp/_completion.lua | 4 ++-- runtime/lua/vim/lsp/_dynamic.lua | 2 +- runtime/lua/vim/lsp/_watchfiles.lua | 4 ++-- runtime/lua/vim/lsp/diagnostic.lua | 6 ++---- runtime/lua/vim/lsp/handlers.lua | 14 +++++++------- runtime/lua/vim/lsp/health.lua | 2 +- runtime/lua/vim/lsp/util.lua | 4 ++-- 7 files changed, 17 insertions(+), 19 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_completion.lua b/runtime/lua/vim/lsp/_completion.lua index 7a607d6c13..84dbf9083e 100644 --- a/runtime/lua/vim/lsp/_completion.lua +++ b/runtime/lua/vim/lsp/_completion.lua @@ -8,7 +8,7 @@ local ms = protocol.Methods ---@return string parsed snippet local function parse_snippet(input) local ok, parsed = pcall(function() - return require('vim.lsp._snippet_grammar').parse(input) + return vim.lsp._snippet_grammar.parse(input) end) return ok and tostring(parsed) or input end @@ -206,7 +206,7 @@ function M.omnifunc(findstart, base) local params = util.make_position_params(win, client.offset_encoding) client.request(ms.textDocument_completion, params, function(err, result) if err then - require('vim.lsp.log').warn(err.message) + vim.lsp.log.warn(err.message) end if result and vim.fn.mode() == 'i' then local matches diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua index 5edb27b498..3c9dee2c69 100644 --- a/runtime/lua/vim/lsp/_dynamic.lua +++ b/runtime/lua/vim/lsp/_dynamic.lua @@ -1,4 +1,4 @@ -local glob = require('vim.glob') +local glob = vim.glob --- @class lsp.DynamicCapabilities --- @field capabilities table diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua index af4cc65f71..59b8c38166 100644 --- a/runtime/lua/vim/lsp/_watchfiles.lua +++ b/runtime/lua/vim/lsp/_watchfiles.lua @@ -1,6 +1,6 @@ local bit = require('bit') -local glob = require('vim.glob') -local watch = require('vim._watch') +local glob = vim.glob +local watch = vim._watch local protocol = require('vim.lsp.protocol') local ms = protocol.Methods local lpeg = vim.lpeg diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index cba5b66672..46dda01e3f 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -1,8 +1,6 @@ ---@brief lsp-diagnostic -local util = require('vim.lsp.util') local protocol = require('vim.lsp.protocol') -local log = require('vim.lsp.log') local ms = protocol.Methods local api = vim.api @@ -95,7 +93,7 @@ local function tags_lsp_to_vim(diagnostic, client_id) tags = tags or {} tags.deprecated = true else - log.info(string.format('Unknown DiagnosticTag %d from LSP client %d', tag, client_id)) + vim.lsp.log.info(string.format('Unknown DiagnosticTag %d from LSP client %d', tag, client_id)) end end return tags @@ -425,7 +423,7 @@ end local function _refresh(bufnr, opts) opts = opts or {} opts['bufnr'] = bufnr - util._refresh(ms.textDocument_diagnostic, opts) + vim.lsp.util._refresh(ms.textDocument_diagnostic, opts) end --- Enable pull diagnostics for a buffer diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 6ed8e1d40f..26a71487e2 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -120,7 +120,7 @@ M[ms.client_registerCapability] = function(_, result, ctx) local unsupported = {} for _, reg in ipairs(result.registrations) do if reg.method == ms.workspace_didChangeWatchedFiles then - require('vim.lsp._watchfiles').register(reg, ctx) + vim.lsp._watchfiles.register(reg, ctx) elseif not client.dynamic_capabilities:supports_registration(reg.method) then unsupported[#unsupported + 1] = reg.method end @@ -144,7 +144,7 @@ M[ms.client_unregisterCapability] = function(_, result, ctx) for _, unreg in ipairs(result.unregisterations) do if unreg.method == ms.workspace_didChangeWatchedFiles then - require('vim.lsp._watchfiles').unregister(unreg, ctx) + vim.lsp._watchfiles.unregister(unreg, ctx) end end return vim.NIL @@ -223,19 +223,19 @@ M[ms.workspace_workspaceFolders] = function(_, _, ctx) end M[ms.textDocument_publishDiagnostics] = function(...) - return require('vim.lsp.diagnostic').on_publish_diagnostics(...) + return vim.lsp.diagnostic.on_publish_diagnostics(...) end M[ms.textDocument_diagnostic] = function(...) - return require('vim.lsp.diagnostic').on_diagnostic(...) + return vim.lsp.diagnostic.on_diagnostic(...) end M[ms.textDocument_codeLens] = function(...) - return require('vim.lsp.codelens').on_codelens(...) + return vim.lsp.codelens.on_codelens(...) end M[ms.textDocument_inlayHint] = function(...) - return require('vim.lsp.inlay_hint').on_inlayhint(...) + return vim.lsp.inlay_hint.on_inlayhint(...) end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references @@ -643,7 +643,7 @@ end ---@see https://microsoft.github.io/language-server-protocol/specification/#workspace_inlayHint_refresh M[ms.workspace_inlayHint_refresh] = function(err, result, ctx, config) - return require('vim.lsp.inlay_hint').on_refresh(err, result, ctx, config) + return vim.lsp.inlay_hint.on_refresh(err, result, ctx, config) end -- Add boilerplate error validation and logging for all of these. diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index fe06006108..9c989e5246 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -5,7 +5,7 @@ function M.check() local report_info = vim.health.info local report_warn = vim.health.warn - local log = require('vim.lsp.log') + local log = vim.lsp.log local current_log_level = log.get_level() local log_level_string = log.levels[current_log_level] report_info(string.format('LSP log level : %s', log_level_string)) diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index cee09d85e0..b5e15e135c 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -3,7 +3,7 @@ local snippet = require('vim.lsp._snippet_grammar') local validate = vim.validate local api = vim.api local list_extend = vim.list_extend -local highlight = require('vim.highlight') +local highlight = vim.highlight local uv = vim.uv local npcall = vim.F.npcall @@ -636,7 +636,7 @@ end ---@see complete-items function M.text_document_completion_list_to_complete_items(result, prefix) vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.11') - return require('vim.lsp._completion')._lsp_to_complete_items(result, prefix) + return vim.lsp._completion._lsp_to_complete_items(result, prefix) end --- Like vim.fn.bufwinid except it works across tabpages. -- cgit From f487e5af019c7cd0f15ab9beb522c9358e8013e2 Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Sat, 3 Feb 2024 17:47:56 -0500 Subject: fix(lsp): fix infinite loop on vim.lsp.tagfunc Problem: vim.lsp.tagfunc() causes an infinite loop. This is a bug happened while introducing deferred loading. Solution: Rename the private module to `vim.lsp._tagfunc`. --- runtime/lua/vim/lsp/_tagfunc.lua | 83 ++++++++++++++++++++++++++++++++++++++++ runtime/lua/vim/lsp/tagfunc.lua | 83 ---------------------------------------- 2 files changed, 83 insertions(+), 83 deletions(-) create mode 100644 runtime/lua/vim/lsp/_tagfunc.lua delete mode 100644 runtime/lua/vim/lsp/tagfunc.lua (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_tagfunc.lua b/runtime/lua/vim/lsp/_tagfunc.lua new file mode 100644 index 0000000000..4ad50e4a58 --- /dev/null +++ b/runtime/lua/vim/lsp/_tagfunc.lua @@ -0,0 +1,83 @@ +local lsp = vim.lsp +local util = lsp.util +local ms = lsp.protocol.Methods + +---@param name string +---@param range lsp.Range +---@param uri string +---@param offset_encoding string +---@return {name: string, filename: string, cmd: string, kind?: string} +local function mk_tag_item(name, range, uri, offset_encoding) + local bufnr = vim.uri_to_bufnr(uri) + -- This is get_line_byte_from_position is 0-indexed, call cursor expects a 1-indexed position + local byte = util._get_line_byte_from_position(bufnr, range.start, offset_encoding) + 1 + return { + name = name, + filename = vim.uri_to_fname(uri), + cmd = string.format([[/\%%%dl\%%%dc/]], range.start.line + 1, byte), + } +end + +---@param pattern string +---@return table[] +local function query_definition(pattern) + local params = util.make_position_params() + local results_by_client, err = lsp.buf_request_sync(0, ms.textDocument_definition, params, 1000) + if err then + return {} + end + local results = {} + local add = function(range, uri, offset_encoding) + table.insert(results, mk_tag_item(pattern, range, uri, offset_encoding)) + end + for client_id, lsp_results in pairs(assert(results_by_client)) do + local client = lsp.get_client_by_id(client_id) + local offset_encoding = client and client.offset_encoding or 'utf-16' + local result = lsp_results.result or {} + if result.range then -- Location + add(result.range, result.uri) + else + result = result --[[@as (lsp.Location[]|lsp.LocationLink[])]] + for _, item in pairs(result) do + if item.range then -- Location + add(item.range, item.uri, offset_encoding) + else -- LocationLink + add(item.targetSelectionRange, item.targetUri, offset_encoding) + end + end + end + end + return results +end + +---@param pattern string +---@return table[] +local function query_workspace_symbols(pattern) + local results_by_client, err = + lsp.buf_request_sync(0, ms.workspace_symbol, { query = pattern }, 1000) + if err then + return {} + end + local results = {} + for client_id, responses in pairs(assert(results_by_client)) do + local client = lsp.get_client_by_id(client_id) + local offset_encoding = client and client.offset_encoding or 'utf-16' + local symbols = responses.result --[[@as lsp.SymbolInformation[]|nil]] + for _, symbol in pairs(symbols or {}) do + local loc = symbol.location + local item = mk_tag_item(symbol.name, loc.range, loc.uri, offset_encoding) + item.kind = lsp.protocol.SymbolKind[symbol.kind] or 'Unknown' + table.insert(results, item) + end + end + return results +end + +local function tagfunc(pattern, flags) + local matches = string.match(flags, 'c') and query_definition(pattern) + or query_workspace_symbols(pattern) + -- fall back to tags if no matches + return #matches > 0 and matches or vim.NIL +end + +return tagfunc diff --git a/runtime/lua/vim/lsp/tagfunc.lua b/runtime/lua/vim/lsp/tagfunc.lua deleted file mode 100644 index 4ad50e4a58..0000000000 --- a/runtime/lua/vim/lsp/tagfunc.lua +++ /dev/null @@ -1,83 +0,0 @@ -local lsp = vim.lsp -local util = lsp.util -local ms = lsp.protocol.Methods - ----@param name string ----@param range lsp.Range ----@param uri string ----@param offset_encoding string ----@return {name: string, filename: string, cmd: string, kind?: string} -local function mk_tag_item(name, range, uri, offset_encoding) - local bufnr = vim.uri_to_bufnr(uri) - -- This is get_line_byte_from_position is 0-indexed, call cursor expects a 1-indexed position - local byte = util._get_line_byte_from_position(bufnr, range.start, offset_encoding) + 1 - return { - name = name, - filename = vim.uri_to_fname(uri), - cmd = string.format([[/\%%%dl\%%%dc/]], range.start.line + 1, byte), - } -end - ----@param pattern string ----@return table[] -local function query_definition(pattern) - local params = util.make_position_params() - local results_by_client, err = lsp.buf_request_sync(0, ms.textDocument_definition, params, 1000) - if err then - return {} - end - local results = {} - local add = function(range, uri, offset_encoding) - table.insert(results, mk_tag_item(pattern, range, uri, offset_encoding)) - end - for client_id, lsp_results in pairs(assert(results_by_client)) do - local client = lsp.get_client_by_id(client_id) - local offset_encoding = client and client.offset_encoding or 'utf-16' - local result = lsp_results.result or {} - if result.range then -- Location - add(result.range, result.uri) - else - result = result --[[@as (lsp.Location[]|lsp.LocationLink[])]] - for _, item in pairs(result) do - if item.range then -- Location - add(item.range, item.uri, offset_encoding) - else -- LocationLink - add(item.targetSelectionRange, item.targetUri, offset_encoding) - end - end - end - end - return results -end - ----@param pattern string ----@return table[] -local function query_workspace_symbols(pattern) - local results_by_client, err = - lsp.buf_request_sync(0, ms.workspace_symbol, { query = pattern }, 1000) - if err then - return {} - end - local results = {} - for client_id, responses in pairs(assert(results_by_client)) do - local client = lsp.get_client_by_id(client_id) - local offset_encoding = client and client.offset_encoding or 'utf-16' - local symbols = responses.result --[[@as lsp.SymbolInformation[]|nil]] - for _, symbol in pairs(symbols or {}) do - local loc = symbol.location - local item = mk_tag_item(symbol.name, loc.range, loc.uri, offset_encoding) - item.kind = lsp.protocol.SymbolKind[symbol.kind] or 'Unknown' - table.insert(results, item) - end - end - return results -end - -local function tagfunc(pattern, flags) - local matches = string.match(flags, 'c') and query_definition(pattern) - or query_workspace_symbols(pattern) - -- fall back to tags if no matches - return #matches > 0 and matches or vim.NIL -end - -return tagfunc -- cgit From 3be2536ca039fb0f0de4ed2858db5a6d13baeba3 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 6 Feb 2024 12:34:04 +0000 Subject: fix(lsp): send back diagnostic tags to the server Fixes: #27318 --- runtime/lua/vim/lsp/diagnostic.lua | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 46dda01e3f..036b0e6151 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -102,16 +102,17 @@ end ---@param diagnostics lsp.Diagnostic[] ---@param bufnr integer ---@param client_id integer ----@return Diagnostic[] +---@return vim.Diagnostic[] local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) local buf_lines = get_buf_lines(bufnr) local client = vim.lsp.get_client_by_id(client_id) local offset_encoding = client and client.offset_encoding or 'utf-16' - ---@diagnostic disable-next-line:no-unknown + --- @param diagnostic lsp.Diagnostic + --- @return vim.Diagnostic return vim.tbl_map(function(diagnostic) - ---@cast diagnostic lsp.Diagnostic local start = diagnostic.range.start local _end = diagnostic.range['end'] + --- @type vim.Diagnostic return { lnum = start.line, col = line_byte_from_position(buf_lines, start.line, start.character, offset_encoding), @@ -135,12 +136,29 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) end, diagnostics) end ---- @param diagnostics Diagnostic[] +--- @param diagnostic vim.Diagnostic +--- @return lsp.DiagnosticTag[]? +local function tags_vim_to_vim(diagnostic) + if not diagnostic._tags then + return + end + + local tags = {} --- @type lsp.DiagnosticTag[] + if diagnostic._tags.unnecessary then + tags[#tags + 1] = protocol.DiagnosticTag.Unnecessary + end + if diagnostic._tags.deprecated then + tags[#tags + 1] = protocol.DiagnosticTag.Deprecated + end + return tags +end + +--- @param diagnostics vim.Diagnostic[] --- @return lsp.Diagnostic[] local function diagnostic_vim_to_lsp(diagnostics) - ---@diagnostic disable-next-line:no-unknown + ---@param diagnostic vim.Diagnostic + ---@return lsp.Diagnostic return vim.tbl_map(function(diagnostic) - ---@cast diagnostic Diagnostic return vim.tbl_extend('keep', { -- "keep" the below fields over any duplicate fields in diagnostic.user_data.lsp range = { @@ -157,6 +175,7 @@ local function diagnostic_vim_to_lsp(diagnostics) message = diagnostic.message, source = diagnostic.source, code = diagnostic.code, + tags = tags_vim_to_vim(diagnostics), }, diagnostic.user_data and (diagnostic.user_data.lsp or {}) or {}) end, diagnostics) end -- cgit From 59cf827f99d53ec8dbb90e48a7561c0cb8b8ca6f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 7 Feb 2024 17:22:03 +0000 Subject: refactor(lsp): move client code to a regular Lua class Problem: The LSP client code is implemented as a complicated closure-class (class defined in a single function). Solution: Move LSP client code to a more conventional Lua class and move to a separate file. --- runtime/lua/vim/lsp/_dynamic.lua | 5 +- runtime/lua/vim/lsp/buf.lua | 2 +- runtime/lua/vim/lsp/client.lua | 663 +++++++++++++++++++++++++++++++++++++++ runtime/lua/vim/lsp/codelens.lua | 2 +- 4 files changed, 668 insertions(+), 4 deletions(-) create mode 100644 runtime/lua/vim/lsp/client.lua (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua index 3c9dee2c69..8b8f3bdc38 100644 --- a/runtime/lua/vim/lsp/_dynamic.lua +++ b/runtime/lua/vim/lsp/_dynamic.lua @@ -6,6 +6,7 @@ local glob = vim.glob local M = {} --- @param client_id number +--- @return lsp.DynamicCapabilities function M.new(client_id) return setmetatable({ capabilities = {}, @@ -37,7 +38,7 @@ function M:register(registrations) end --- @param unregisterations lsp.Unregistration[] ---- @private +--- @package function M:unregister(unregisterations) for _, unreg in ipairs(unregisterations) do local method = unreg.method @@ -77,7 +78,7 @@ end --- @param method string --- @param opts? {bufnr: integer?} ---- @private +--- @package function M:supports(method, opts) return self:get(method, opts) ~= nil end diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index d67b2ac8ea..7fc5286a78 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -652,7 +652,7 @@ local function on_code_action_results(results, opts) end if action.command then local command = type(action.command) == 'table' and action.command or action - client._exec_cmd(command, ctx) + client:_exec_cmd(command, ctx) end end diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua new file mode 100644 index 0000000000..2daf564f63 --- /dev/null +++ b/runtime/lua/vim/lsp/client.lua @@ -0,0 +1,663 @@ +local uv = vim.uv +local api = vim.api +local lsp = vim.lsp +local log = lsp.log +local ms = lsp.protocol.Methods +local changetracking = lsp._changetracking + +--- @class lsp.Client.Progress: vim.Ringbuf<{token: integer|string, value: any}> +--- @field pending table + +--- @class lsp.Client +--- +--- The id allocated to the client. +--- @field id integer +--- +--- If a name is specified on creation, that will be used. Otherwise it is just +--- the client id. This is used for logs and messages. +--- @field name string +--- +--- RPC client object, for low level interaction with the client. +--- See |vim.lsp.rpc.start()|. +--- @field rpc vim.lsp.rpc.PublicClient +--- +--- The encoding used for communicating with the server. You can modify this in +--- the `config`'s `on_init` method before text is sent to the server. +--- @field offset_encoding string +--- +--- The handlers used by the client as described in |lsp-handler|. +--- @field handlers table +--- +--- The current pending requests in flight to the server. Entries are key-value +--- pairs with the key being the request ID while the value is a table with +--- `type`, `bufnr`, and `method` key-value pairs. `type` is either "pending" +--- for an active request, or "cancel" for a cancel request. It will be +--- "complete" ephemerally while executing |LspRequest| autocmds when replies +--- are received from the server. +--- @field requests table +--- +--- copy of the table that was passed by the user +--- to |vim.lsp.start_client()|. +--- @field config lsp.ClientConfig +--- +--- Response from the server sent on +--- initialize` describing the server's capabilities. +--- @field server_capabilities lsp.ServerCapabilities +--- +--- A ring buffer (|vim.ringbuf()|) containing progress messages +--- sent by the server. +--- @field progress lsp.Client.Progress +--- +--- @field initialized true? +--- @field workspace_folders lsp.WorkspaceFolder[]? +--- @field attached_buffers table +--- @field commands table +--- @field private _log_prefix string +--- Track this so that we can escalate automatically if we've already tried a +--- graceful shutdown +--- @field private _graceful_shutdown_failed true? +--- +--- @field dynamic_capabilities lsp.DynamicCapabilities +--- +--- Sends a request to the server. +--- This is a thin wrapper around {client.rpc.request} with some additional +--- checking. +--- If {handler} is not specified, If one is not found there, then an error +--- will occur. Returns: {status}, {[client_id]}. {status} is a boolean +--- indicating if the notification was successful. If it is `false`, then it +--- will always be `false` (the client has shutdown). +--- If {status} is `true`, the function returns {request_id} as the second +--- result. You can use this with `client.cancel_request(request_id)` to cancel +--- the request. +--- @field request fun(method: string, params: table?, handler: lsp.Handler?, bufnr: integer): boolean, integer? +--- +--- Sends a request to the server and synchronously waits for the response. +--- This is a wrapper around {client.request} +--- Returns: { err=err, result=result }, a dictionary, where `err` and `result` +--- come from the |lsp-handler|. On timeout, cancel or error, returns `(nil, +--- err)` where `err` is a string describing the failure reason. If the request +--- was unsuccessful returns `nil`. +--- @field request_sync fun(method: string, params: table?, timeout_ms: integer?, bufnr: integer): {err: lsp.ResponseError|nil, result:any}|nil, string|nil err # a dictionary, where +--- +--- Sends a notification to an LSP server. +--- Returns: a boolean to indicate if the notification was successful. If +--- it is false, then it will always be false (the client has shutdown). +--- @field notify fun(method: string, params: table?): boolean +--- +--- Cancels a request with a given request id. +--- Returns: same as `notify()`. +--- @field cancel_request fun(id: integer): boolean +--- +--- Stops a client, optionally with force. +--- By default, it will just ask the server to shutdown without force. +--- If you request to stop a client which has previously been requested to +--- shutdown, it will automatically escalate and force shutdown. +--- @field stop fun(force?: boolean) +--- +--- Runs the on_attach function from the client's config if it was defined. +--- Useful for buffer-local setup. +--- @field on_attach fun(bufnr: integer) +--- +--- Checks if a client supports a given method. +--- Always returns true for unknown off-spec methods. +--- [opts] is a optional `{bufnr?: integer}` table. +--- Some language server capabilities can be file specific. +--- @field supports_method fun(method: string, opts?: {bufnr: integer?}): boolean +--- +--- Checks whether a client is stopped. +--- Returns: true if the client is fully stopped. +--- @field is_stopped fun(): boolean +local Client = {} +Client.__index = Client + +--- @param cls table +--- @param meth any +--- @return function +local function method_wrapper(cls, meth) + return function(...) + return meth(cls, ...) + end +end + +--- @package +--- @param id integer +--- @param rpc vim.lsp.rpc.PublicClient +--- @param handlers table +--- @param offset_encoding string +--- @param config lsp.ClientConfig +--- @return lsp.Client +function Client.new(id, rpc, handlers, offset_encoding, config) + local name = config.name + + --- @class lsp.Client + local self = { + id = id, + config = config, + handlers = handlers, + rpc = rpc, + offset_encoding = offset_encoding, + name = name, + _log_prefix = string.format('LSP[%s]', name), + requests = {}, + commands = config.commands or {}, + attached_buffers = {}, + server_capabilities = {}, + dynamic_capabilities = vim.lsp._dynamic.new(id), + + --- Contains $/progress report messages. + --- They have the format {token: integer|string, value: any} + --- For "work done progress", value will be one of: + --- - lsp.WorkDoneProgressBegin, + --- - lsp.WorkDoneProgressReport (extended with title from Begin) + --- - lsp.WorkDoneProgressEnd (extended with title from Begin) + progress = vim.ringbuf(50) --[[@as lsp.Client.Progress]], + + --- @deprecated use client.progress instead + messages = { name = name, messages = {}, progress = {}, status = {} }, + } + + self.request = method_wrapper(self, Client._request) + self.request_sync = method_wrapper(self, Client._request_sync) + self.notify = method_wrapper(self, Client._notify) + self.cancel_request = method_wrapper(self, Client._cancel_request) + self.stop = method_wrapper(self, Client._stop) + self.is_stopped = method_wrapper(self, Client._is_stopped) + self.on_attach = method_wrapper(self, Client._on_attach) + self.supports_method = method_wrapper(self, Client._supports_method) + + ---@type table title of unfinished progress sequences by token + self.progress.pending = {} + + return setmetatable(self, Client) +end + +--- @private +--- @param cb fun() +function Client:initialize(cb) + local valid_traces = { + off = 'off', + messages = 'messages', + verbose = 'verbose', + } + + local config = self.config + + local workspace_folders --- @type lsp.WorkspaceFolder[]? + local root_uri --- @type string? + local root_path --- @type string? + if config.workspace_folders or config.root_dir then + if config.root_dir and not config.workspace_folders then + workspace_folders = { + { + uri = vim.uri_from_fname(config.root_dir), + name = string.format('%s', config.root_dir), + }, + } + else + workspace_folders = config.workspace_folders + end + root_uri = workspace_folders[1].uri + root_path = vim.uri_to_fname(root_uri) + else + workspace_folders = nil + root_uri = nil + root_path = nil + end + + local initialize_params = { + -- The process Id of the parent process that started the server. Is null if + -- the process has not been started by another process. If the parent + -- process is not alive then the server should exit (see exit notification) + -- its process. + processId = uv.os_getpid(), + -- Information about the client + -- since 3.15.0 + clientInfo = { + name = 'Neovim', + version = tostring(vim.version()), + }, + -- The rootPath of the workspace. Is null if no folder is open. + -- + -- @deprecated in favour of rootUri. + rootPath = root_path or vim.NIL, + -- The rootUri of the workspace. Is null if no folder is open. If both + -- `rootPath` and `rootUri` are set `rootUri` wins. + rootUri = root_uri or vim.NIL, + -- The workspace folders configured in the client when the server starts. + -- This property is only available if the client supports workspace folders. + -- It can be `null` if the client supports workspace folders but none are + -- configured. + workspaceFolders = workspace_folders or vim.NIL, + -- User provided initialization options. + initializationOptions = config.init_options, + -- The capabilities provided by the client (editor or tool) + capabilities = config.capabilities, + -- The initial trace setting. If omitted trace is disabled ("off"). + -- trace = "off" | "messages" | "verbose"; + trace = valid_traces[config.trace] or 'off', + } + if config.before_init then + --- @type boolean, string? + local status, err = pcall(config.before_init, initialize_params, config) + if not status then + self:write_error(lsp.client_errors.BEFORE_INIT_CALLBACK_ERROR, err) + end + end + + if log.trace() then + log.trace(self._log_prefix, 'initialize_params', initialize_params) + end + + local rpc = self.rpc + + rpc.request('initialize', initialize_params, function(init_err, result) + assert(not init_err, tostring(init_err)) + assert(result, 'server sent empty result') + rpc.notify('initialized', vim.empty_dict()) + self.initialized = true + self.workspace_folders = workspace_folders + + -- These are the cleaned up capabilities we use for dynamically deciding + -- when to send certain events to clients. + self.server_capabilities = + assert(result.capabilities, "initialize result doesn't contain capabilities") + self.server_capabilities = assert(lsp.protocol.resolve_capabilities(self.server_capabilities)) + + if self.server_capabilities.positionEncoding then + self.offset_encoding = self.server_capabilities.positionEncoding + end + + if next(config.settings) then + self:_notify(ms.workspace_didChangeConfiguration, { settings = config.settings }) + end + + if config.on_init then + --- @type boolean, string? + local status, err = pcall(config.on_init, self, result) + if not status then + self:write_error(lsp.client_errors.ON_INIT_CALLBACK_ERROR, err) + end + end + if log.info() then + log.info( + self._log_prefix, + 'server_capabilities', + { server_capabilities = self.server_capabilities } + ) + end + + cb() + end) +end + +--- @private +--- Returns the handler associated with an LSP method. +--- Returns the default handler if the user hasn't set a custom one. +--- +--- @param method (string) LSP method name +--- @return lsp.Handler|nil handler for the given method, if defined, or the default from |vim.lsp.handlers| +function Client:_resolve_handler(method) + return self.handlers[method] or lsp.handlers[method] +end + +--- Returns the buffer number for the given {bufnr}. +--- +--- @param bufnr (integer|nil) Buffer number to resolve. Defaults to current buffer +--- @return integer bufnr +local function resolve_bufnr(bufnr) + vim.validate({ bufnr = { bufnr, 'n', true } }) + if bufnr == nil or bufnr == 0 then + return api.nvim_get_current_buf() + end + return bufnr +end + +--- @private +--- Sends a request to the server. +--- +--- 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 params table|nil LSP request params. +--- @param handler lsp.Handler|nil Response |lsp-handler| for this method. +--- @param bufnr integer Buffer handle (0 for current). +--- @return boolean status, integer|nil request_id {status} is a bool indicating +--- whether the request was successful. If it is `false`, then it will +--- always be `false` (the client has shutdown). If it was +--- successful, then it will return {request_id} as the +--- second result. You can use this with `client.cancel_request(request_id)` +--- to cancel the-request. +--- @see |vim.lsp.buf_request_all()| +function Client:_request(method, params, handler, bufnr) + if not handler then + handler = assert( + self:_resolve_handler(method), + string.format('not found: %q request handler for client %q.', method, self.name) + ) + end + -- Ensure pending didChange notifications are sent so that the server doesn't operate on a stale state + changetracking.flush(self, bufnr) + local version = lsp.util.buf_versions[bufnr] + bufnr = resolve_bufnr(bufnr) + if log.debug() then + log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr) + end + local success, request_id = self.rpc.request(method, params, function(err, result) + local context = { + method = method, + client_id = self.id, + bufnr = bufnr, + params = params, + version = version, + } + handler(err, result, context) + end, function(request_id) + local request = self.requests[request_id] + request.type = 'complete' + api.nvim_exec_autocmds('LspRequest', { + buffer = api.nvim_buf_is_valid(bufnr) and bufnr or nil, + modeline = false, + data = { client_id = self.id, request_id = request_id, request = request }, + }) + self.requests[request_id] = nil + end) + + if success and request_id then + local request = { type = 'pending', bufnr = bufnr, method = method } + self.requests[request_id] = request + api.nvim_exec_autocmds('LspRequest', { + buffer = bufnr, + modeline = false, + data = { client_id = self.id, request_id = request_id, request = request }, + }) + end + + return success, request_id +end + +-- TODO(lewis6991): duplicated from lsp.lua +local wait_result_reason = { [-1] = 'timeout', [-2] = 'interrupted', [-3] = 'error' } + +-- TODO(lewis6991): duplicated from lsp.lua +--- Concatenates and writes a list of strings to the Vim error buffer. +--- +---@param ... string List to write to the buffer +local function err_message(...) + api.nvim_err_writeln(table.concat(vim.tbl_flatten({ ... }))) + api.nvim_command('redraw') +end + +--- @private +--- Sends a request to the server and synchronously waits for the response. +--- +--- This is a wrapper around {client.request} +--- +--- @param method (string) LSP method name. +--- @param params (table) LSP request params. +--- @param timeout_ms (integer|nil) Maximum time in milliseconds to wait for +--- a result. Defaults to 1000 +--- @param bufnr (integer) Buffer handle (0 for current). +--- @return {err: lsp.ResponseError|nil, result:any}|nil, string|nil err # a dictionary, where +--- `err` and `result` come from the |lsp-handler|. +--- On timeout, cancel or error, returns `(nil, err)` where `err` is a +--- string describing the failure reason. If the request was unsuccessful +--- returns `nil`. +--- @see |vim.lsp.buf_request_sync()| +function Client:_request_sync(method, params, timeout_ms, bufnr) + local request_result = nil + local function _sync_handler(err, result) + request_result = { err = err, result = result } + end + + local success, request_id = self:_request(method, params, _sync_handler, bufnr) + if not success then + return nil + end + + local wait_result, reason = vim.wait(timeout_ms or 1000, function() + return request_result ~= nil + end, 10) + + if not wait_result then + if request_id then + self:_cancel_request(request_id) + end + return nil, wait_result_reason[reason] + end + return request_result +end + +--- @private +--- Sends a notification to an LSP server. +--- +--- @param method string LSP method name. +--- @param params table|nil LSP request params. +--- @return boolean status true if the notification was successful. +--- If it is false, then it will always be false +--- (the client has shutdown). +function Client:_notify(method, params) + if method ~= ms.textDocument_didChange then + changetracking.flush(self) + end + + local client_active = self.rpc.notify(method, params) + + if client_active then + vim.schedule(function() + api.nvim_exec_autocmds('LspNotify', { + modeline = false, + data = { + client_id = self.id, + method = method, + params = params, + }, + }) + end) + end + + return client_active +end + +--- @private +--- Cancels a request with a given request id. +--- +--- @param id (integer) id of request to cancel +--- @return boolean status true if notification was successful. false otherwise +--- @see |vim.lsp.client.notify()| +function Client:_cancel_request(id) + vim.validate({ id = { id, 'n' } }) + local request = self.requests[id] + if request and request.type == 'pending' then + request.type = 'cancel' + api.nvim_exec_autocmds('LspRequest', { + buffer = request.bufnr, + modeline = false, + data = { client_id = self.id, request_id = id, request = request }, + }) + end + return self.rpc.notify(ms.dollar_cancelRequest, { id = id }) +end + +--- @nodoc +--- Stops a client, optionally with force. +--- +--- By default, it will just ask the - server to shutdown without force. If +--- you request to stop a client which has previously been requested to +--- shutdown, it will automatically escalate and force shutdown. +--- +--- @param force boolean|nil +function Client:_stop(force) + local rpc = self.rpc + + if rpc.is_closing() then + return + end + + if force or not self.initialized or self._graceful_shutdown_failed then + rpc.terminate() + return + end + + -- Sending a signal after a process has exited is acceptable. + rpc.request(ms.shutdown, nil, function(err, _) + if err == nil then + rpc.notify(ms.exit) + else + -- If there was an error in the shutdown request, then term to be safe. + rpc.terminate() + self._graceful_shutdown_failed = true + end + end) +end + +--- @private +--- Checks whether a client is stopped. +--- +--- @return boolean # true if client is stopped or in the process of being +--- stopped; false otherwise +function Client:_is_stopped() + return self.rpc.is_closing() +end + +--- @private +--- Execute a lsp command, either via client command function (if available) +--- or via workspace/executeCommand (if supported by the server) +--- +--- @param command lsp.Command +--- @param context? {bufnr: integer} +--- @param handler? lsp.Handler only called if a server command +function Client:_exec_cmd(command, context, handler) + context = vim.deepcopy(context or {}, true) --[[@as lsp.HandlerContext]] + context.bufnr = context.bufnr or api.nvim_get_current_buf() + context.client_id = self.id + local cmdname = command.command + local fn = self.commands[cmdname] or lsp.commands[cmdname] + if fn then + fn(command, context) + return + end + + local command_provider = self.server_capabilities.executeCommandProvider + local commands = type(command_provider) == 'table' and command_provider.commands or {} + if not vim.list_contains(commands, cmdname) then + vim.notify_once( + string.format( + 'Language server `%s` does not support command `%s`. This command may require a client extension.', + self.name, + cmdname + ), + vim.log.levels.WARN + ) + return + end + -- Not using command directly to exclude extra properties, + -- see https://github.com/python-lsp/python-lsp-server/issues/146 + local params = { + command = command.command, + arguments = command.arguments, + } + self.request(ms.workspace_executeCommand, params, handler, context.bufnr) +end + +--- @package +--- Default handler for the 'textDocument/didOpen' LSP notification. +--- +--- @param bufnr integer Number of the buffer, or 0 for current +function Client:_text_document_did_open_handler(bufnr) + changetracking.init(self, bufnr) + if not vim.tbl_get(self.server_capabilities, 'textDocumentSync', 'openClose') then + return + end + if not api.nvim_buf_is_loaded(bufnr) then + return + end + local filetype = vim.bo[bufnr].filetype + + local params = { + textDocument = { + version = 0, + uri = vim.uri_from_bufnr(bufnr), + languageId = self.config.get_language_id(bufnr, filetype), + text = lsp._buf_get_full_text(bufnr), + }, + } + self.notify(ms.textDocument_didOpen, params) + lsp.util.buf_versions[bufnr] = params.textDocument.version + + -- Next chance we get, we should re-do the diagnostics + vim.schedule(function() + -- Protect against a race where the buffer disappears + -- between `did_open_handler` and the scheduled function firing. + if api.nvim_buf_is_valid(bufnr) then + local namespace = vim.lsp.diagnostic.get_namespace(self.id) + vim.diagnostic.show(namespace, bufnr) + end + end) +end + +--- @private +--- Runs the on_attach function from the client's config if it was defined. +--- @param bufnr integer Buffer number +function Client:_on_attach(bufnr) + self:_text_document_did_open_handler(bufnr) + + lsp._set_defaults(self, bufnr) + + api.nvim_exec_autocmds('LspAttach', { + buffer = bufnr, + modeline = false, + data = { client_id = self.id }, + }) + + if self.config.on_attach then + --- @type boolean, string? + local status, err = pcall(self.config.on_attach, self, bufnr) + if not status then + self:write_error(lsp.client_errors.ON_ATTACH_ERROR, err) + end + end + + -- schedule the initialization of semantic tokens to give the above + -- on_attach and LspAttach callbacks the ability to schedule wrap the + -- opt-out (deleting the semanticTokensProvider from capabilities) + vim.schedule(function() + if vim.tbl_get(self.server_capabilities, 'semanticTokensProvider', 'full') then + lsp.semantic_tokens.start(bufnr, self.id) + end + end) + + self.attached_buffers[bufnr] = true +end + +--- @private +--- Logs the given error to the LSP log and to the error buffer. +--- @param code integer Error code +--- @param err any Error arguments +function Client:write_error(code, err) + if log.error() then + log.error(self._log_prefix, 'on_error', { code = lsp.client_errors[code], err = err }) + end + err_message(self._log_prefix, ': Error ', lsp.client_errors[code], ': ', vim.inspect(err)) +end + +--- @param method string +--- @param opts? {bufnr: integer?} +function Client:_supports_method(method, opts) + opts = opts or {} + local required_capability = lsp._request_name_to_capability[method] + -- if we don't know about the method, assume that the client supports it. + if not required_capability then + return true + end + if vim.tbl_get(self.server_capabilities, unpack(required_capability)) then + return true + else + if self.dynamic_capabilities:supports_registration(method) then + return self.dynamic_capabilities:supports(method, opts) + end + return false + end +end + +return Client diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index 199da288f4..a045a6bad4 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -48,7 +48,7 @@ local function execute_lens(lens, bufnr, client_id) local client = vim.lsp.get_client_by_id(client_id) assert(client, 'Client is required to execute lens, client_id=' .. client_id) - client._exec_cmd(lens.command, { bufnr = bufnr }, function(...) + client:_exec_cmd(lens.command, { bufnr = bufnr }, function(...) vim.lsp.handlers[ms.workspace_executeCommand](...) M.refresh() end) -- cgit From 5785c32f1115833cf69ec9062c5bc8907360aab0 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 8 Feb 2024 07:34:38 +0800 Subject: fix(lsp): set fallback client name properly --- runtime/lua/vim/lsp/client.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 2daf564f63..36c3a4225e 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -127,7 +127,7 @@ end --- @param config lsp.ClientConfig --- @return lsp.Client function Client.new(id, rpc, handlers, offset_encoding, config) - local name = config.name + local name = config.name or tostring(id) --- @class lsp.Client local self = { -- cgit From 1f9da3d0835af2cfe937de250c2cde3a59e1677e Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 8 Feb 2024 09:24:47 +0000 Subject: refactor(lsp): tidy up logging --- runtime/lua/vim/lsp/client.lua | 25 ++--- runtime/lua/vim/lsp/codelens.lua | 4 +- runtime/lua/vim/lsp/diagnostic.lua | 4 +- runtime/lua/vim/lsp/handlers.lua | 9 +- runtime/lua/vim/lsp/inlay_hint.lua | 4 +- runtime/lua/vim/lsp/log.lua | 206 ++++++++++++++++++------------------- runtime/lua/vim/lsp/rpc.lua | 42 +++----- 7 files changed, 132 insertions(+), 162 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 36c3a4225e..0bcbb35be6 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -244,9 +244,7 @@ function Client:initialize(cb) end end - if log.trace() then - log.trace(self._log_prefix, 'initialize_params', initialize_params) - end + log.trace(self._log_prefix, 'initialize_params', initialize_params) local rpc = self.rpc @@ -278,13 +276,12 @@ function Client:initialize(cb) self:write_error(lsp.client_errors.ON_INIT_CALLBACK_ERROR, err) end end - if log.info() then - log.info( - self._log_prefix, - 'server_capabilities', - { server_capabilities = self.server_capabilities } - ) - end + + log.info( + self._log_prefix, + 'server_capabilities', + { server_capabilities = self.server_capabilities } + ) cb() end) @@ -340,9 +337,7 @@ function Client:_request(method, params, handler, bufnr) changetracking.flush(self, bufnr) local version = lsp.util.buf_versions[bufnr] bufnr = resolve_bufnr(bufnr) - if log.debug() then - log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr) - end + log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr) local success, request_id = self.rpc.request(method, params, function(err, result) local context = { method = method, @@ -635,9 +630,7 @@ end --- @param code integer Error code --- @param err any Error arguments function Client:write_error(code, err) - if log.error() then - log.error(self._log_prefix, 'on_error', { code = lsp.client_errors[code], err = err }) - end + log.error(self._log_prefix, 'on_error', { code = lsp.client_errors[code], err = err }) err_message(self._log_prefix, ': Error ', lsp.client_errors[code], ': ', vim.inspect(err)) end diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index a045a6bad4..61e3448024 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -262,9 +262,7 @@ end function M.on_codelens(err, result, ctx, _) if err then active_refreshes[assert(ctx.bufnr)] = nil - if log.error() then - log.error('codelens', err) - end + log.error('codelens', err) return end diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 036b0e6151..aa812fa78c 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -35,7 +35,7 @@ local function severity_vim_to_lsp(severity) return severity end ----@param lines string[] +---@param lines string[]? ---@param lnum integer ---@param col integer ---@param offset_encoding string @@ -55,7 +55,7 @@ local function line_byte_from_position(lines, lnum, col, offset_encoding) end ---@param bufnr integer ----@return string[] +---@return string[]? local function get_buf_lines(bufnr) if vim.api.nvim_buf_is_loaded(bufnr) then return vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 26a71487e2..2fa539d963 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -413,9 +413,7 @@ M[ms.textDocument_hover] = M.hover ---(`textDocument/definition` can return `Location` or `Location[]` local function location_handler(_, result, ctx, config) if result == nil or vim.tbl_isempty(result) then - if log.info() then - log.info(ctx.method, 'No location found') - end + log.info(ctx.method, 'No location found') return nil end local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) @@ -649,13 +647,14 @@ end -- Add boilerplate error validation and logging for all of these. for k, fn in pairs(M) do M[k] = function(err, result, ctx, config) - local _ = log.trace() - and log.trace('default_handler', ctx.method, { + if log.trace() then + log.trace('default_handler', ctx.method, { err = err, result = result, ctx = vim.inspect(ctx), config = config, }) + end if err then -- LSP spec: diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index 62138c0edf..49dc35fdf6 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -22,9 +22,7 @@ local augroup = api.nvim_create_augroup('vim_lsp_inlayhint', {}) ---@private function M.on_inlayhint(err, result, ctx, _) if err then - if log.error() then - log.error('inlayhint', err) - end + log.error('inlayhint', err) return end local bufnr = assert(ctx.bufnr) diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 00433474fe..a9d49bc8f4 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -12,130 +12,130 @@ log.levels = vim.deepcopy(vim.log.levels) -- Default log level is warn. local current_log_level = log.levels.WARN + local log_date_format = '%F %H:%M:%S' -local format_func = function(arg) + +local function format_func(arg) return vim.inspect(arg, { newline = '' }) end -do - local function notify(msg, level) - if vim.in_fast_event() then - vim.schedule(function() - vim.notify(msg, level) - end) - else +local function notify(msg, level) + if vim.in_fast_event() then + vim.schedule(function() vim.notify(msg, level) - end + end) + else + vim.notify(msg, level) end +end + +local logfilename = vim.fs.joinpath(vim.fn.stdpath('log'), 'lsp.log') + +-- TODO: Ideally the directory should be created in open_logfile(), right +-- before opening the log file, but open_logfile() can be called from libuv +-- callbacks, where using fn.mkdir() is not allowed. +vim.fn.mkdir(vim.fn.stdpath('log'), 'p') + +--- Returns the log filename. +---@return string log filename +function log.get_filename() + return logfilename +end + +--- @type file*?, string? +local logfile, openerr - local path_sep = vim.uv.os_uname().version:match('Windows') and '\\' or '/' - local function path_join(...) - return table.concat(vim.tbl_flatten({ ... }), path_sep) +--- Opens log file. Returns true if file is open, false on error +local function open_logfile() + -- Try to open file only once + if logfile then + return true + end + if openerr then + return false end - local logfilename = path_join(vim.fn.stdpath('log'), 'lsp.log') - -- TODO: Ideally the directory should be created in open_logfile(), right - -- before opening the log file, but open_logfile() can be called from libuv - -- callbacks, where using fn.mkdir() is not allowed. - vim.fn.mkdir(vim.fn.stdpath('log'), 'p') + logfile, openerr = io.open(logfilename, 'a+') + if not logfile then + local err_msg = string.format('Failed to open LSP client log file: %s', openerr) + notify(err_msg, vim.log.levels.ERROR) + return false + end - --- Returns the log filename. - ---@return string log filename - function log.get_filename() - return logfilename + local log_info = vim.uv.fs_stat(logfilename) + if log_info and log_info.size > 1e9 then + local warn_msg = string.format( + 'LSP client log is large (%d MB): %s', + log_info.size / (1000 * 1000), + logfilename + ) + notify(warn_msg) end - local logfile, openerr - --- Opens log file. Returns true if file is open, false on error - local function open_logfile() - -- Try to open file only once - if logfile then + -- Start message for logging + logfile:write(string.format('[START][%s] LSP logging initiated\n', os.date(log_date_format))) + return true +end + +for level, levelnr in pairs(log.levels) do + -- Also export the log level on the root object. + log[level] = levelnr +end + +vim.tbl_add_reverse_lookup(log.levels) + +--- @param level string +--- @param levelnr integer +--- @return fun(...:any): boolean? +local function create_logger(level, levelnr) + return function(...) + if levelnr < current_log_level then + return false + end + local argc = select('#', ...) + if argc == 0 then return true end - if openerr then + if not open_logfile() then return false end - - logfile, openerr = io.open(logfilename, 'a+') - if not logfile then - local err_msg = string.format('Failed to open LSP client log file: %s', openerr) - notify(err_msg, vim.log.levels.ERROR) - return false + local info = debug.getinfo(2, 'Sl') + local header = string.format( + '[%s][%s] ...%s:%s', + level, + os.date(log_date_format), + info.short_src:sub(-16), + info.currentline + ) + local parts = { header } + for i = 1, argc do + local arg = select(i, ...) + table.insert(parts, arg == nil and 'nil' or format_func(arg)) end + assert(logfile) + logfile:write(table.concat(parts, '\t'), '\n') + logfile:flush() + end +end - local log_info = vim.uv.fs_stat(logfilename) - if log_info and log_info.size > 1e9 then - local warn_msg = string.format( - 'LSP client log is large (%d MB): %s', - log_info.size / (1000 * 1000), - logfilename - ) - notify(warn_msg) - end +-- If called without arguments, it will check whether the log level is +-- greater than or equal to this one. When called with arguments, it will +-- log at that level (if applicable, it is checked either way). - -- Start message for logging - logfile:write(string.format('[START][%s] LSP logging initiated\n', os.date(log_date_format))) - return true - end +--- @nodoc +log.debug = create_logger('DEBUG', vim.log.levels.DEBUG) - for level, levelnr in pairs(log.levels) do - -- Also export the log level on the root object. - log[level] = levelnr - -- FIXME: DOC - -- Should be exposed in the vim docs. - -- - -- Set the lowercase name as the main use function. - -- If called without arguments, it will check whether the log level is - -- greater than or equal to this one. When called with arguments, it will - -- log at that level (if applicable, it is checked either way). - -- - -- Recommended usage: - -- ``` - -- if log.warn() then - -- log.warn("123") - -- end - -- ``` - -- - -- This way you can avoid string allocations if the log level isn't high enough. - if level ~= 'OFF' then - log[level:lower()] = function(...) - local argc = select('#', ...) - if levelnr < current_log_level then - return false - end - if argc == 0 then - return true - end - if not open_logfile() then - return false - end - local info = debug.getinfo(2, 'Sl') - local header = string.format( - '[%s][%s] ...%s:%s', - level, - os.date(log_date_format), - string.sub(info.short_src, #info.short_src - 15), - info.currentline - ) - local parts = { header } - for i = 1, argc do - local arg = select(i, ...) - if arg == nil then - table.insert(parts, 'nil') - else - table.insert(parts, format_func(arg)) - end - end - logfile:write(table.concat(parts, '\t'), '\n') - logfile:flush() - end - end - end -end +--- @nodoc +log.error = create_logger('ERROR', vim.log.levels.ERROR) --- This is put here on purpose after the loop above so that it doesn't --- interfere with iterating the levels -vim.tbl_add_reverse_lookup(log.levels) +--- @nodoc +log.info = create_logger('INFO', vim.log.levels.INFO) + +--- @nodoc +log.trace = create_logger('TRACE', vim.log.levels.TRACE) + +--- @nodoc +log.warn = create_logger('WARN', vim.log.levels.WARN) --- Sets the current log level. ---@param level (string|integer) One of `vim.lsp.log.levels` diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 660b126ce4..1aacf63392 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -26,24 +26,6 @@ local function format_message_with_content_length(message) }) end -local function log_error(...) - if log.error() then - log.error(...) - end -end - -local function log_info(...) - if log.info() then - log.info(...) - end -end - -local function log_debug(...) - if log.debug() then - log.debug(...) - end -end - ---@class vim.lsp.rpc.Headers: {string: any} ---@field content_length integer @@ -65,7 +47,7 @@ local function parse_headers(header) key = key:lower():gsub('%-', '_') --- @type string headers[key] = value else - log_error('invalid header line %q', line) + log.error('invalid header line %q', line) error(string.format('invalid header line %q', line)) end end @@ -224,7 +206,7 @@ local default_dispatchers = { ---@param method string The invoked LSP method ---@param params table Parameters for the invoked LSP method notification = function(method, params) - log_debug('notification', method, params) + log.debug('notification', method, params) end, --- Default dispatcher for requests sent to an LSP server. @@ -234,7 +216,7 @@ local default_dispatchers = { ---@return any result (always nil for the default dispatchers) ---@return lsp.ResponseError error `vim.lsp.protocol.ErrorCodes.MethodNotFound` server_request = function(method, params) - log_debug('server_request', method, params) + log.debug('server_request', method, params) return nil, M.rpc_response_error(protocol.ErrorCodes.MethodNotFound) end, @@ -243,7 +225,7 @@ local default_dispatchers = { ---@param code integer Exit code ---@param signal integer Number describing the signal used to terminate (if any) on_exit = function(code, signal) - log_info('client_exit', { code = code, signal = signal }) + log.info('client_exit', { code = code, signal = signal }) end, --- Default dispatcher for client errors. @@ -251,7 +233,7 @@ local default_dispatchers = { ---@param code integer Error code ---@param err any Details about the error on_error = function(code, err) - log_error('client_error:', M.client_errors[code], err) + log.error('client_error:', M.client_errors[code], err) end, } @@ -297,7 +279,7 @@ local Client = {} ---@private function Client:encode_and_send(payload) - log_debug('rpc.send', payload) + log.debug('rpc.send', payload) if self.transport.is_closing() then return false end @@ -419,7 +401,7 @@ function Client:handle_body(body) self:on_error(M.client_errors.INVALID_SERVER_JSON, decoded) return end - log_debug('rpc.receive', decoded) + log.debug('rpc.receive', decoded) if type(decoded.method) == 'string' and decoded.id then local err --- @type lsp.ResponseError|nil @@ -434,7 +416,7 @@ function Client:handle_body(body) decoded.method, decoded.params ) - log_debug( + log.debug( 'server_request: callback result', { status = status, result = result, err = err } ) @@ -490,7 +472,7 @@ function Client:handle_body(body) if decoded.error then local mute_error = false if decoded.error.code == protocol.ErrorCodes.RequestCancelled then - log_debug('Received cancellation ack', decoded) + log.debug('Received cancellation ack', decoded) mute_error = true end @@ -526,7 +508,7 @@ function Client:handle_body(body) ) else self:on_error(M.client_errors.NO_RESULT_CALLBACK_FOUND, decoded) - log_error('No callback found for server response id ' .. result_id) + log.error('No callback found for server response id ' .. result_id) end elseif type(decoded.method) == 'string' then -- Notification @@ -773,7 +755,7 @@ end --- - `is_closing()` returns a boolean indicating if the RPC is closing. --- - `terminate()` terminates the RPC client. function M.start(cmd, cmd_args, dispatchers, extra_spawn_params) - log_info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params }) + log.info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params }) validate({ cmd = { cmd, 's' }, @@ -813,7 +795,7 @@ function M.start(cmd, cmd_args, dispatchers, extra_spawn_params) local stderr_handler = function(_, chunk) if chunk then - log_error('rpc', cmd, 'stderr', chunk) + log.error('rpc', cmd, 'stderr', chunk) end end -- cgit From 451bc50d40ee43a40285d16039deb83c9bf05ff6 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 8 Feb 2024 12:11:47 +0000 Subject: feat(lsp): deprecate severity_limit Problem: `vim.lsp.diagnostic.on_diagnostic` accepts an undocumented severity_limit option which is widely used. Solution: Deprecate it in favour of `{min = severity}` used in `vim.diagnostic`. Since this is undocumented, the schedule for removal is accelerated to 0.11. --- runtime/lua/vim/lsp/diagnostic.lua | 52 ++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 28 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index aa812fa78c..3a4064a1e4 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -221,6 +221,13 @@ function M.get_namespace(client_id, is_pull) end end +local function convert_severity(opt) + if type(opt) == 'table' and not opt.severity and opt.severity_limit then + vim.deprecate('severity_limit', '{min = severity} See vim.diagnostic.severity', '0.11') + opt.severity = { min = severity_lsp_to_vim(opt.severity_limit) } + end +end + --- |lsp-handler| for the method "textDocument/publishDiagnostics" --- --- See |vim.diagnostic.config()| for configuration options. Handler-specific @@ -267,13 +274,8 @@ function M.on_publish_diagnostics(_, result, ctx, config) if config then for _, opt in pairs(config) do - if type(opt) == 'table' then - if not opt.severity and opt.severity_limit then - opt.severity = { min = severity_lsp_to_vim(opt.severity_limit) } - end - end + convert_severity(opt) end - -- Persist configuration to ensure buffer reloads use the same -- configuration. To make lsp.with configuration work (See :help -- lsp-handler-configuration) @@ -308,11 +310,14 @@ end --- ) --- ``` --- +---@param result lsp.DocumentDiagnosticReport ---@param ctx lsp.HandlerContext ---@param config table Configuration table (see |vim.diagnostic.config()|). function M.on_diagnostic(_, result, ctx, config) local client_id = ctx.client_id - local uri = ctx.params.textDocument.uri + --- @type lsp.DocumentDiagnosticParams + local params = ctx.params + local uri = params.textDocument.uri local fname = vim.uri_to_fname(uri) if result == nil then @@ -339,11 +344,8 @@ function M.on_diagnostic(_, result, ctx, config) if config then for _, opt in pairs(config) do - if type(opt) == 'table' and not opt.severity and opt.severity_limit then - opt.severity = { min = severity_lsp_to_vim(opt.severity_limit) } - end + convert_severity(opt) end - -- Persist configuration to ensure buffer reloads use the same -- configuration. To make lsp.with configuration work (See :help -- lsp-handler-configuration) @@ -381,34 +383,28 @@ end --- ---@param bufnr integer|nil The buffer number ---@param line_nr integer|nil The line number ----@param opts table|nil Configuration keys ---- - severity: (DiagnosticSeverity, default nil) ---- - Only return diagnostics with this severity. Overrides severity_limit ---- - severity_limit: (DiagnosticSeverity, default nil) ---- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. +---@param opts {severity?:lsp.DiagnosticSeverity}? +--- - severity: (lsp.DiagnosticSeverity) +--- - Only return diagnostics with this severity. ---@param client_id integer|nil the client id ---@return table Table with map of line number to list of diagnostics. --- Structured: { [1] = {...}, [5] = {.... } } ---@private function M.get_line_diagnostics(bufnr, line_nr, opts, client_id) - opts = opts or {} - if opts.severity then - opts.severity = severity_lsp_to_vim(opts.severity) - elseif opts.severity_limit then - opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } - end + convert_severity(opts) + local diag_opts = {} --- @type vim.diagnostic.GetOpts - if client_id then - opts.namespace = M.get_namespace(client_id, false) + if opts and opts.severity then + diag_opts.severity = severity_lsp_to_vim(opts.severity) end - if not line_nr then - line_nr = vim.api.nvim_win_get_cursor(0)[1] - 1 + if client_id then + diag_opts.namespace = M.get_namespace(client_id, false) end - opts.lnum = line_nr + diag_opts.lnum = line_nr or (api.nvim_win_get_cursor(0)[1] - 1) - return diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, opts)) + return diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, diag_opts)) end --- Clear diagnostics from pull based clients -- cgit From f0e61e6d92b5ce115388f8a03f8d34f00a3dea92 Mon Sep 17 00:00:00 2001 From: Tomasz N Date: Thu, 8 Feb 2024 22:06:54 +0100 Subject: fix(lsp): rename fails on missing parent directory #27291 Problem: If a rename results in a path that has missing parent directory(s), it will fail. Solution: Do a recursive mkdir before attempting the rename. --- runtime/lua/vim/lsp/util.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index b5e15e135c..86bef1ac8a 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -693,6 +693,9 @@ function M.rename(old_fname, new_fname, opts) end) end + local newdir = assert(vim.fs.dirname(new_fname)) + vim.fn.mkdir(newdir, 'p') + local ok, err = os.rename(old_fname, new_fname) assert(ok, err) -- cgit From 0fe86f7e240368c00ffa06516cd34850b92e00d3 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 28 Jan 2024 22:21:37 -0800 Subject: feat(lsp): add opts paramater to vim.lsp.codelens.refresh --- runtime/lua/vim/lsp/codelens.lua | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index 61e3448024..ab49e03c52 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -48,6 +48,7 @@ local function execute_lens(lens, bufnr, client_id) local client = vim.lsp.get_client_by_id(client_id) assert(client, 'Client is required to execute lens, client_id=' .. client_id) + ---@diagnostic disable-next-line: invisible client:_exec_cmd(lens.command, { bufnr = bufnr }, function(...) vim.lsp.handlers[ms.workspace_executeCommand](...) M.refresh() @@ -111,7 +112,7 @@ end --- Clear the lenses --- ---@param client_id integer|nil filter by client_id. All clients if nil ----@param bufnr integer|nil filter by buffer. All buffers if nil +---@param bufnr integer|nil filter by buffer. All buffers if nil, 0 for current buffer function M.clear(client_id, bufnr) bufnr = bufnr and resolve_bufnr(bufnr) local buffers = bufnr and { bufnr } @@ -277,25 +278,36 @@ function M.on_codelens(err, result, ctx, _) end) end ---- Refresh the codelens for the current buffer +--- @class vim.lsp.codelens.RefreshOptions +--- @field bufnr integer? filter by buffer. All buffers if nil, 0 for current buffer + +--- Refresh the lenses. --- --- It is recommended to trigger this using an autocmd or via keymap. --- --- Example: --- --- ```vim ---- autocmd BufEnter,CursorHold,InsertLeave lua vim.lsp.codelens.refresh() +--- autocmd BufEnter,CursorHold,InsertLeave lua vim.lsp.codelens.refresh({ bufnr = 0 }) --- ``` -function M.refresh() +--- +--- @param opts? vim.lsp.codelens.RefreshOptions Table with the following fields: +--- - `bufnr` (integer|nil): filter by buffer. All buffers if nil, 0 for current buffer +function M.refresh(opts) + opts = opts or {} + local bufnr = opts.bufnr and resolve_bufnr(opts.bufnr) + local buffers = bufnr and { bufnr } + or vim.tbl_filter(api.nvim_buf_is_loaded, api.nvim_list_bufs()) local params = { textDocument = util.make_text_document_params(), } - local bufnr = api.nvim_get_current_buf() - if active_refreshes[bufnr] then - return + + for _, buf in ipairs(buffers) do + if not active_refreshes[buf] then + active_refreshes[buf] = true + vim.lsp.buf_request(buf, ms.textDocument_codeLens, params, M.on_codelens) + end end - active_refreshes[bufnr] = true - vim.lsp.buf_request(0, ms.textDocument_codeLens, params, M.on_codelens) end return M -- cgit From c73d67d283c296bdb7a44a0283346e7b61d837f0 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 10 Feb 2024 14:03:44 -0800 Subject: refactor(lsp): add type annotations --- runtime/lua/vim/lsp/_changetracking.lua | 2 +- runtime/lua/vim/lsp/_dynamic.lua | 2 +- runtime/lua/vim/lsp/client.lua | 5 +++-- runtime/lua/vim/lsp/diagnostic.lua | 9 +++++---- runtime/lua/vim/lsp/health.lua | 2 +- runtime/lua/vim/lsp/rpc.lua | 2 +- runtime/lua/vim/lsp/sync.lua | 13 ++++++------- 7 files changed, 18 insertions(+), 17 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_changetracking.lua b/runtime/lua/vim/lsp/_changetracking.lua index 67c74f069d..8b624cd5ea 100644 --- a/runtime/lua/vim/lsp/_changetracking.lua +++ b/runtime/lua/vim/lsp/_changetracking.lua @@ -64,7 +64,7 @@ local state_by_group = setmetatable({}, { ---@param client lsp.Client ---@return vim.lsp.CTGroup local function get_group(client) - local allow_inc_sync = vim.F.if_nil(client.config.flags.allow_incremental_sync, true) + local allow_inc_sync = vim.F.if_nil(client.config.flags.allow_incremental_sync, true) --- @type boolean local change_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'change') local sync_kind = change_capability or protocol.TextDocumentSyncKind.None if not allow_inc_sync and change_capability == protocol.TextDocumentSyncKind.Incremental then diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua index 8b8f3bdc38..b6c335bb13 100644 --- a/runtime/lua/vim/lsp/_dynamic.lua +++ b/runtime/lua/vim/lsp/_dynamic.lua @@ -24,7 +24,7 @@ function M:supports_registration(method) end --- @param registrations lsp.Registration[] ---- @private +--- @package function M:register(registrations) -- remove duplicates self:unregister(registrations) diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 0bcbb35be6..7bf83f4d2c 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -630,8 +630,9 @@ end --- @param code integer Error code --- @param err any Error arguments function Client:write_error(code, err) - log.error(self._log_prefix, 'on_error', { code = lsp.client_errors[code], err = err }) - err_message(self._log_prefix, ': Error ', lsp.client_errors[code], ': ', vim.inspect(err)) + local client_error = lsp.client_errors[code] --- @type string|integer + log.error(self._log_prefix, 'on_error', { code = client_error, err = err }) + err_message(self._log_prefix, ': Error ', client_error, ': ', vim.inspect(err)) end --- @param method string diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 3a4064a1e4..5fdadd1771 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -22,7 +22,7 @@ end ---@param severity lsp.DiagnosticSeverity local function severity_lsp_to_vim(severity) if type(severity) == 'string' then - severity = protocol.DiagnosticSeverity[severity] + severity = protocol.DiagnosticSeverity[severity] --- @type integer end return severity end @@ -48,7 +48,7 @@ local function line_byte_from_position(lines, lnum, col, offset_encoding) local line = lines[lnum + 1] local ok, result = pcall(vim.str_byteindex, line, col, offset_encoding == 'utf-16') if ok then - return result + return result --- @type integer end return col @@ -362,7 +362,7 @@ end --- implementation so it's simply marked @private rather than @deprecated. --- ---@param client_id integer ----@param buffer_client_map table map of buffers to active clients +---@param buffer_client_map table> map of buffers to active clients ---@private function M.reset(client_id, buffer_client_map) buffer_client_map = vim.deepcopy(buffer_client_map) @@ -462,7 +462,8 @@ function M._enable(bufnr) return end if bufstates[bufnr] and bufstates[bufnr].enabled then - _refresh(bufnr, { only_visible = true, client_id = opts.data.client_id }) + local client_id = opts.data.client_id --- @type integer? + _refresh(bufnr, { only_visible = true, client_id = client_id }) end end, group = augroup, diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index 9c989e5246..d770735895 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -7,7 +7,7 @@ function M.check() local log = vim.lsp.log local current_log_level = log.get_level() - local log_level_string = log.levels[current_log_level] + local log_level_string = log.levels[current_log_level] ---@type string report_info(string.format('LSP log level : %s', log_level_string)) if current_log_level < log.levels.WARN then diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 1aacf63392..23f70826e5 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -498,7 +498,7 @@ function Client:handle_body(body) if decoded.error then decoded.error = setmetatable(decoded.error, { __tostring = M.format_rpc_error, - }) + }) --- @type table end self:try_call( M.client_errors.SERVER_RESULT_CALLBACK_ERROR, diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 7ebe2dbb88..7eed542667 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -58,8 +58,7 @@ local function byte_to_utf(line, byte, offset_encoding) -- convert to 0 based indexing for str_utfindex byte = byte - 1 - local utf_idx --- @type integer - local _ + local utf_idx, _ --- @type integer, integer -- Convert the byte range to utf-{8,16,32} and convert 1-based (lua) indexing to 0-based if offset_encoding == 'utf-16' then _, utf_idx = str_utfindex(line, byte) @@ -77,8 +76,7 @@ end ---@param offset_encoding string ---@return integer local function compute_line_length(line, offset_encoding) - local length --- @type integer - local _ + local length, _ --- @type integer, integer if offset_encoding == 'utf-16' then _, length = str_utfindex(line) elseif offset_encoding == 'utf-32' then @@ -202,9 +200,10 @@ end --- prev_end_range is the text range sent to the server representing the changed region. --- curr_end_range is the text that should be collected and sent to the server. -- ----@param prev_lines table list of lines ----@param curr_lines table list of lines ---@param start_range table +---@param prev_lines string[] list of lines +---@param curr_lines string[] list of lines +---@param firstline integer ---@param lastline integer ---@param new_lastline integer ---@param offset_encoding string @@ -253,7 +252,7 @@ local function compute_end_range( -- Editing the same line -- If the byte offset is zero, that means there is a difference on the last byte (not newline) if prev_line_idx == curr_line_idx then - local max_length + local max_length --- @type integer if start_line_idx == prev_line_idx then -- Search until beginning of difference max_length = min( -- cgit From 5a6868c888a9ef5bd22e004e7cb116e4578ccf32 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 10 Feb 2024 14:04:05 -0800 Subject: refactor(lsp): add shared diagnostic handler --- runtime/lua/vim/lsp/diagnostic.lua | 103 ++++++++++++++----------------------- 1 file changed, 39 insertions(+), 64 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 5fdadd1771..33051ab61c 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -228,6 +228,40 @@ local function convert_severity(opt) end end +--- @param uri string +--- @param client_id? integer +--- @param diagnostics vim.Diagnostic[] +--- @param is_pull boolean +--- @param config? vim.diagnostic.Opts +local function handle_diagnostics(uri, client_id, diagnostics, is_pull, config) + local fname = vim.uri_to_fname(uri) + + if #diagnostics == 0 and vim.fn.bufexists(fname) == 0 then + return + end + + local bufnr = vim.fn.bufadd(fname) + if not bufnr then + return + end + + client_id = get_client_id(client_id) + local namespace = M.get_namespace(client_id, is_pull) + + if config then + --- @cast config table + for _, opt in pairs(config) do + convert_severity(opt) + end + -- Persist configuration to ensure buffer reloads use the same + -- configuration. To make lsp.with configuration work (See :help + -- lsp-handler-configuration) + vim.diagnostic.config(config, namespace) + end + + vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) +end + --- |lsp-handler| for the method "textDocument/publishDiagnostics" --- --- See |vim.diagnostic.config()| for configuration options. Handler-specific @@ -253,36 +287,11 @@ end --- ) --- ``` --- +---@param result lsp.PublishDiagnosticsParams ---@param ctx lsp.HandlerContext ----@param config table Configuration table (see |vim.diagnostic.config()|). +---@param config? vim.diagnostic.Opts Configuration table (see |vim.diagnostic.config()|). function M.on_publish_diagnostics(_, result, ctx, config) - local client_id = ctx.client_id - local uri = result.uri - local fname = vim.uri_to_fname(uri) - local diagnostics = result.diagnostics - if #diagnostics == 0 and vim.fn.bufexists(fname) == 0 then - return - end - local bufnr = vim.fn.bufadd(fname) - - if not bufnr then - return - end - - client_id = get_client_id(client_id) - local namespace = M.get_namespace(client_id, false) - - if config then - for _, opt in pairs(config) do - convert_severity(opt) - end - -- Persist configuration to ensure buffer reloads use the same - -- configuration. To make lsp.with configuration work (See :help - -- lsp-handler-configuration) - vim.diagnostic.config(config, namespace) - end - - vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) + handle_diagnostics(result.uri, ctx.client_id, result.diagnostics, false, config) end --- |lsp-handler| for the method "textDocument/diagnostic" @@ -314,45 +323,11 @@ end ---@param ctx lsp.HandlerContext ---@param config table Configuration table (see |vim.diagnostic.config()|). function M.on_diagnostic(_, result, ctx, config) - local client_id = ctx.client_id - --- @type lsp.DocumentDiagnosticParams - local params = ctx.params - local uri = params.textDocument.uri - local fname = vim.uri_to_fname(uri) - - if result == nil then - return - end - - if result.kind == 'unchanged' then + if result == nil or result.kind == 'unchanged' then return end - local diagnostics = result.items - if #diagnostics == 0 and vim.fn.bufexists(fname) == 0 then - return - end - local bufnr = vim.fn.bufadd(fname) - - if not bufnr then - return - end - - client_id = get_client_id(client_id) - - local namespace = M.get_namespace(client_id, true) - - if config then - for _, opt in pairs(config) do - convert_severity(opt) - end - -- Persist configuration to ensure buffer reloads use the same - -- configuration. To make lsp.with configuration work (See :help - -- lsp-handler-configuration) - vim.diagnostic.config(config, namespace) - end - - vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) + handle_diagnostics(ctx.params.textDocument.uri, ctx.client_id, result.items, true, config) end --- Clear push diagnostics and diagnostic cache. -- cgit From eac7e3fc6c738d7023c104f09341dbb10bf3c4bc Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 10 Feb 2024 14:04:44 -0800 Subject: refactor(lsp): add vim.lsp.sync.Range type --- runtime/lua/vim/lsp/sync.lua | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 7eed542667..62fa0b33f4 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -120,6 +120,11 @@ local function align_end_position(line, byte, offset_encoding) return byte, char end +---@class vim.lsp.sync.Range +---@field line_idx integer +---@field byte_idx integer +---@field char_idx integer + --- Finds the first line, byte, and char index of the difference between the previous and current lines buffer normalized to the previous codepoint. ---@param prev_lines string[] list of lines from previous buffer ---@param curr_lines string[] list of lines from current buffer @@ -127,7 +132,7 @@ end ---@param lastline integer lastline from on_lines, adjusted to 1-index ---@param new_lastline integer new_lastline from on_lines, adjusted to 1-index ---@param offset_encoding string utf-8|utf-16|utf-32|nil (fallback to utf-8) ----@return table result table include line_idx, byte_idx, and char_idx of first change position +---@return vim.lsp.sync.Range result table include line_idx, byte_idx, and char_idx of first change position local function compute_start_range( prev_lines, curr_lines, @@ -200,15 +205,14 @@ end --- prev_end_range is the text range sent to the server representing the changed region. --- curr_end_range is the text that should be collected and sent to the server. -- ----@param start_range table ---@param prev_lines string[] list of lines ---@param curr_lines string[] list of lines +---@param start_range vim.lsp.sync.Range ---@param firstline integer ---@param lastline integer ---@param new_lastline integer ---@param offset_encoding string ----@return integer|table end_line_idx and end_col_idx of range ----@return table|nil end_col_idx of range +---@return vim.lsp.sync.Range, vim.lsp.sync.Range local function compute_end_range( prev_lines, curr_lines, @@ -285,7 +289,7 @@ local function compute_end_range( local prev_end_range = { line_idx = prev_line_idx, byte_idx = prev_byte_idx, char_idx = prev_char_idx } - local curr_end_range + local curr_end_range ---@type vim.lsp.sync.Range -- Deletion event, new_range cannot be before start if curr_line_idx < start_line_idx then curr_end_range = { line_idx = start_line_idx, byte_idx = 1, char_idx = 1 } @@ -346,8 +350,8 @@ end -- Line endings count here as 2 chars for \r\n (dos), 1 char for \n (unix), and 1 char for \r (mac) -- These correspond to Windows, Linux/macOS (OSX and newer), and macOS (version 9 and prior) ---@param lines string[] ----@param start_range table ----@param end_range table +---@param start_range vim.lsp.sync.Range +---@param end_range vim.lsp.sync.Range ---@param offset_encoding string ---@param line_ending string ---@return integer -- cgit From ed1b66bd998b98ee8cf76b5a23c323352588dd56 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 11 Feb 2024 12:37:20 +0000 Subject: refactor(lsp): move more code to client.lua The dispatchers used by the RPC client should be defined in the client, so they have been moved there. Due to this, it also made sense to move all code related to client configuration and the creation of the RPC client there too. Now vim.lsp.start_client is significantly simplified and now mostly contains logic for tracking open clients. - Renamed client.new -> client.start --- runtime/lua/vim/lsp/client.lua | 262 +++++++++++++++++++++++++++++++++++++---- runtime/lua/vim/lsp/rpc.lua | 17 +-- 2 files changed, 246 insertions(+), 33 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 7bf83f4d2c..58db4387b6 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -4,6 +4,30 @@ local lsp = vim.lsp local log = lsp.log local ms = lsp.protocol.Methods local changetracking = lsp._changetracking +local validate = vim.validate + +--- @class lsp.ClientConfig +--- @field cmd (string[]|fun(dispatchers: table):table) +--- @field cmd_cwd string +--- @field cmd_env (table) +--- @field detached boolean +--- @field workspace_folders (table) +--- @field capabilities lsp.ClientCapabilities +--- @field handlers table +--- @field settings table +--- @field commands table +--- @field init_options table +--- @field name? string +--- @field get_language_id fun(bufnr: integer, filetype: string): string +--- @field offset_encoding string +--- @field on_error fun(code: integer) +--- @field before_init fun(params: lsp.InitializeParams, config: lsp.ClientConfig) +--- @field on_init fun(client: lsp.Client, initialize_result: lsp.InitializeResult) +--- @field on_exit fun(code: integer, signal: integer, client_id: integer) +--- @field on_attach fun(client: lsp.Client, bufnr: integer) +--- @field trace 'off'|'messages'|'verbose'|nil +--- @field flags table +--- @field root_dir string --- @class lsp.Client.Progress: vim.Ringbuf<{token: integer|string, value: any}> --- @field pending table @@ -51,7 +75,6 @@ local changetracking = lsp._changetracking --- @field initialized true? --- @field workspace_folders lsp.WorkspaceFolder[]? --- @field attached_buffers table ---- @field commands table --- @field private _log_prefix string --- Track this so that we can escalate automatically if we've already tried a --- graceful shutdown @@ -119,27 +142,131 @@ local function method_wrapper(cls, meth) end end +local client_index = 0 + +--- Checks whether a given path is a directory. +--- @param filename (string) path to check +--- @return boolean # true if {filename} exists and is a directory, false otherwise +local function is_dir(filename) + validate({ filename = { filename, 's' } }) + local stat = uv.fs_stat(filename) + return stat and stat.type == 'directory' or false +end + +local valid_encodings = { + ['utf-8'] = 'utf-8', + ['utf-16'] = 'utf-16', + ['utf-32'] = 'utf-32', + ['utf8'] = 'utf-8', + ['utf16'] = 'utf-16', + ['utf32'] = 'utf-32', + UTF8 = 'utf-8', + UTF16 = 'utf-16', + UTF32 = 'utf-32', +} + +--- Normalizes {encoding} to valid LSP encoding names. +--- @param encoding string? Encoding to normalize +--- @return string # normalized encoding name +local function validate_encoding(encoding) + validate({ + encoding = { encoding, 's', true }, + }) + if not encoding then + return valid_encodings.UTF16 + end + return valid_encodings[encoding:lower()] + or error( + string.format( + "Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", + encoding + ) + ) +end + +--- Augments a validator function with support for optional (nil) values. +--- @param fn (fun(v): boolean) The original validator function; should return a +--- bool. +--- @return fun(v): boolean # The augmented function. Also returns true if {v} is +--- `nil`. +local function optional_validator(fn) + return function(v) + return v == nil or fn(v) + end +end + +--- Validates a client configuration as given to |vim.lsp.start_client()|. +--- @param config lsp.ClientConfig +local function process_client_config(config) + validate({ + config = { config, 't' }, + }) + validate({ + handlers = { config.handlers, 't', true }, + capabilities = { config.capabilities, 't', true }, + cmd_cwd = { config.cmd_cwd, optional_validator(is_dir), 'directory' }, + cmd_env = { config.cmd_env, 't', true }, + detached = { config.detached, 'b', true }, + name = { config.name, 's', true }, + on_error = { config.on_error, 'f', true }, + on_exit = { config.on_exit, 'f', true }, + on_init = { config.on_init, 'f', true }, + settings = { config.settings, 't', true }, + commands = { config.commands, 't', true }, + before_init = { config.before_init, 'f', true }, + offset_encoding = { config.offset_encoding, 's', true }, + flags = { config.flags, 't', true }, + get_language_id = { config.get_language_id, 'f', true }, + }) + assert( + ( + not config.flags + or not config.flags.debounce_text_changes + or type(config.flags.debounce_text_changes) == 'number' + ), + 'flags.debounce_text_changes must be a number with the debounce time in milliseconds' + ) + + if not config.name and type(config.cmd) == 'table' then + config.name = config.cmd[1] and vim.fs.basename(config.cmd[1]) or nil + end + + config.offset_encoding = validate_encoding(config.offset_encoding) + config.flags = config.flags or {} + config.settings = config.settings or {} + config.handlers = config.handlers or {} + + -- By default, get_language_id just returns the exact filetype it is passed. + -- It is possible to pass in something that will calculate a different filetype, + -- to be sent by the client. + config.get_language_id = config.get_language_id or function(_, filetype) + return filetype + end + + config.capabilities = config.capabilities or lsp.protocol.make_client_capabilities() + config.commands = config.commands or {} +end + --- @package ---- @param id integer ---- @param rpc vim.lsp.rpc.PublicClient ---- @param handlers table ---- @param offset_encoding string --- @param config lsp.ClientConfig ---- @return lsp.Client -function Client.new(id, rpc, handlers, offset_encoding, config) +--- @return lsp.Client? +function Client.start(config) + process_client_config(config) + + client_index = client_index + 1 + local id = client_index + local name = config.name or tostring(id) --- @class lsp.Client local self = { id = id, config = config, - handlers = handlers, - rpc = rpc, - offset_encoding = offset_encoding, + handlers = config.handlers, + offset_encoding = config.offset_encoding, name = name, _log_prefix = string.format('LSP[%s]', name), requests = {}, - commands = config.commands or {}, attached_buffers = {}, server_capabilities = {}, dynamic_capabilities = vim.lsp._dynamic.new(id), @@ -165,15 +292,46 @@ function Client.new(id, rpc, handlers, offset_encoding, config) self.on_attach = method_wrapper(self, Client._on_attach) self.supports_method = method_wrapper(self, Client._supports_method) - ---@type table title of unfinished progress sequences by token + --- @type table title of unfinished progress sequences by token self.progress.pending = {} - return setmetatable(self, Client) + --- @type vim.lsp.rpc.Dispatchers + local dispatchers = { + notification = method_wrapper(self, Client._notification), + server_request = method_wrapper(self, Client._server_request), + on_error = method_wrapper(self, Client._on_error), + on_exit = method_wrapper(self, Client._on_exit), + } + + -- Start the RPC client. + local rpc --- @type vim.lsp.rpc.PublicClient? + local config_cmd = config.cmd + if type(config_cmd) == 'function' then + rpc = config_cmd(dispatchers) + else + rpc = lsp.rpc.start(config_cmd, dispatchers, { + cwd = config.cmd_cwd, + env = config.cmd_env, + detached = config.detached, + }) + end + + -- Return nil if the rpc client fails to start + if not rpc then + return + end + + self.rpc = rpc + + setmetatable(self, Client) + + self:initialize() + + return self end --- @private ---- @param cb fun() -function Client:initialize(cb) +function Client:initialize() local valid_traces = { off = 'off', messages = 'messages', @@ -282,8 +440,6 @@ function Client:initialize(cb) 'server_capabilities', { server_capabilities = self.server_capabilities } ) - - cb() end) end @@ -302,7 +458,7 @@ end --- @param bufnr (integer|nil) Buffer number to resolve. Defaults to current buffer --- @return integer bufnr local function resolve_bufnr(bufnr) - vim.validate({ bufnr = { bufnr, 'n', true } }) + validate({ bufnr = { bufnr, 'n', true } }) if bufnr == nil or bufnr == 0 then return api.nvim_get_current_buf() end @@ -374,10 +530,9 @@ end -- TODO(lewis6991): duplicated from lsp.lua local wait_result_reason = { [-1] = 'timeout', [-2] = 'interrupted', [-3] = 'error' } --- TODO(lewis6991): duplicated from lsp.lua --- Concatenates and writes a list of strings to the Vim error buffer. --- ----@param ... string List to write to the buffer +--- @param ... string List to write to the buffer local function err_message(...) api.nvim_err_writeln(table.concat(vim.tbl_flatten({ ... }))) api.nvim_command('redraw') @@ -461,7 +616,7 @@ end --- @return boolean status true if notification was successful. false otherwise --- @see |vim.lsp.client.notify()| function Client:_cancel_request(id) - vim.validate({ id = { id, 'n' } }) + validate({ id = { id, 'n' } }) local request = self.requests[id] if request and request.type == 'pending' then request.type = 'cancel' @@ -527,7 +682,7 @@ function Client:_exec_cmd(command, context, handler) context.bufnr = context.bufnr or api.nvim_get_current_buf() context.client_id = self.id local cmdname = command.command - local fn = self.commands[cmdname] or lsp.commands[cmdname] + local fn = self.config.commands[cmdname] or lsp.commands[cmdname] if fn then fn(command, context) return @@ -654,4 +809,67 @@ function Client:_supports_method(method, opts) end end +--- @private +--- Handles a notification sent by an LSP server by invoking the +--- corresponding handler. +--- +--- @param method string LSP method name +--- @param params table The parameters for that method. +function Client:_notification(method, params) + log.trace('notification', method, params) + local handler = self:_resolve_handler(method) + if handler then + -- Method name is provided here for convenience. + handler(nil, params, { method = method, client_id = self.id }) + end +end + +--- @private +--- Handles a request from an LSP server by invoking the corresponding handler. +--- +--- @param method (string) LSP method name +--- @param params (table) The parameters for that method +--- @return any result +--- @return lsp.ResponseError error code and message set in case an exception happens during the request. +function Client:_server_request(method, params) + log.trace('server_request', method, params) + local handler = self:_resolve_handler(method) + if handler then + log.trace('server_request: found handler for', method) + return handler(nil, params, { method = method, client_id = self.id }) + end + log.warn('server_request: no handler found for', method) + return nil, lsp.rpc_response_error(lsp.protocol.ErrorCodes.MethodNotFound) +end + +--- @private +--- Invoked when the client operation throws an error. +--- +--- @param code integer Error code +--- @param err any Other arguments may be passed depending on the error kind +--- @see vim.lsp.rpc.client_errors for possible errors. Use +--- `vim.lsp.rpc.client_errors[code]` to get a human-friendly name. +function Client:_on_error(code, err) + self:write_error(code, err) + if self.config.on_error then + --- @type boolean, string + local status, usererr = pcall(self.config.on_error, code, err) + if not status then + log.error(self._log_prefix, 'user on_error failed', { err = usererr }) + err_message(self._log_prefix, ' user on_error failed: ', tostring(usererr)) + end + end +end + +--- @private +--- Invoked on client exit. +--- +--- @param code integer) exit code of the process +--- @param signal integer the signal used to terminate (if any) +function Client:_on_exit(code, signal) + if self.config.on_exit then + pcall(self.config.on_exit, code, signal, self.id) + end +end + return Client diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 23f70826e5..e849bb4f2a 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -732,8 +732,7 @@ end --- interact with it. Communication with the spawned process happens via stdio. For --- communication via TCP, spawn a process manually and use |vim.lsp.rpc.connect()| --- ----@param cmd string Command to start the LSP server. ----@param cmd_args string[] List of additional string arguments to pass to {cmd}. +---@param cmd string[] Command to start the LSP server. --- ---@param dispatchers? vim.lsp.rpc.Dispatchers Dispatchers for LSP message types. --- Valid dispatcher names are: @@ -754,12 +753,11 @@ end --- - `request()` |vim.lsp.rpc.request()| --- - `is_closing()` returns a boolean indicating if the RPC is closing. --- - `terminate()` terminates the RPC client. -function M.start(cmd, cmd_args, dispatchers, extra_spawn_params) - log.info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params }) +function M.start(cmd, dispatchers, extra_spawn_params) + log.info('Starting RPC client', { cmd = cmd, extra = extra_spawn_params }) validate({ - cmd = { cmd, 's' }, - cmd_args = { cmd_args, 't' }, + cmd = { cmd, 't' }, dispatchers = { dispatchers, 't', true }, }) @@ -795,7 +793,7 @@ function M.start(cmd, cmd_args, dispatchers, extra_spawn_params) local stderr_handler = function(_, chunk) if chunk then - log.error('rpc', cmd, 'stderr', chunk) + log.error('rpc', cmd[1], 'stderr', chunk) end end @@ -804,10 +802,7 @@ function M.start(cmd, cmd_args, dispatchers, extra_spawn_params) detached = extra_spawn_params.detached end - local cmd1 = { cmd } - vim.list_extend(cmd1, cmd_args) - - local ok, sysobj_or_err = pcall(vim.system, cmd1, { + local ok, sysobj_or_err = pcall(vim.system, cmd, { stdin = true, stdout = stdout_handler, stderr = stderr_handler, -- cgit From 917172dd9680cc4234a47beee91e8adcaf0e833c Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 11 Feb 2024 18:07:04 +0000 Subject: fix(lsp): semantic token defer loading Fixes #27424 --- runtime/lua/vim/lsp/handlers.lua | 5 +++++ runtime/lua/vim/lsp/semantic_tokens.lua | 6 ++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 2fa539d963..4bb14e5a09 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -644,6 +644,11 @@ M[ms.workspace_inlayHint_refresh] = function(err, result, ctx, config) return vim.lsp.inlay_hint.on_refresh(err, result, ctx, config) end +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#semanticTokens_refreshRequest +M[ms.workspace_semanticTokens_refresh] = function(err, result, ctx, _config) + return vim.lsp.semantic_tokens._refresh(err, result, ctx) +end + -- Add boilerplate error validation and logging for all of these. for k, fn in pairs(M) do M[k] = function(err, result, ctx, config) diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index b0cec0dd0e..fe8638bdfa 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -1,6 +1,5 @@ local api = vim.api local bit = require('bit') -local handlers = require('vim.lsp.handlers') local ms = require('vim.lsp.protocol').Methods local util = require('vim.lsp.util') local uv = vim.uv @@ -763,6 +762,7 @@ function M.highlight_token(token, bufnr, client_id, hl_group, opts) }) end +--- @package --- |lsp-handler| for the method `workspace/semanticTokens/refresh` --- --- Refresh requests are sent by the server to indicate a project-wide change @@ -770,9 +770,7 @@ end --- invalidate the current results of all buffers and automatically kick off a --- new request for buffers that are displayed in a window. For those that aren't, a --- the BufWinEnter event should take care of it next time it's displayed. ---- ----@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#semanticTokens_refreshRequest -handlers[ms.workspace_semanticTokens_refresh] = function(err, _, ctx) +function M._refresh(err, _, ctx) if err then return vim.NIL end -- cgit From 597ecf751603cde2d5f58021d503ae20a12eb2f2 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 12 Feb 2024 10:18:42 +0000 Subject: fix(lsp): re-add client.commands and mark private --- runtime/lua/vim/lsp/client.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 58db4387b6..a279be55e9 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -79,6 +79,7 @@ local validate = vim.validate --- Track this so that we can escalate automatically if we've already tried a --- graceful shutdown --- @field private _graceful_shutdown_failed true? +--- @field private commands table --- --- @field dynamic_capabilities lsp.DynamicCapabilities --- @@ -270,6 +271,7 @@ function Client.start(config) attached_buffers = {}, server_capabilities = {}, dynamic_capabilities = vim.lsp._dynamic.new(id), + commands = config.commands, -- Remove in Nvim 0.11 --- Contains $/progress report messages. --- They have the format {token: integer|string, value: any} -- cgit From 9f8c96240dc0318bd92a646966917e8fe0641144 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 12 Feb 2024 13:46:32 +0000 Subject: refactor(lsp): resolve the config-client entanglement Previously the LSP-Client object contained some fields that are also in the client config, but for a lot of other fields, the config was used directly making the two objects vaguely entangled with either not having a clear role. Now the config object is treated purely as config (read-only) from the client, and any fields the client needs from the config are now copied in as additional fields. This means: - the config object is no longet normalised and is left as the user provided it. - the client only reads the config on creation of the client and all other implementations now read the clients version of the fields. In addition, internal support for multiple callbacks has been added to the client so the client tracking logic (done in lua.lsp) can be done more robustly instead of wrapping the user callbacks which may error. --- runtime/lua/vim/lsp/_changetracking.lua | 6 +- runtime/lua/vim/lsp/_dynamic.lua | 4 +- runtime/lua/vim/lsp/_watchfiles.lua | 8 +- runtime/lua/vim/lsp/client.lua | 307 +++++++++++++++++++------------- runtime/lua/vim/lsp/codelens.lua | 1 - runtime/lua/vim/lsp/handlers.lua | 4 +- runtime/lua/vim/lsp/health.lua | 2 +- 7 files changed, 195 insertions(+), 137 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_changetracking.lua b/runtime/lua/vim/lsp/_changetracking.lua index 8b624cd5ea..3ecdec1659 100644 --- a/runtime/lua/vim/lsp/_changetracking.lua +++ b/runtime/lua/vim/lsp/_changetracking.lua @@ -64,7 +64,7 @@ local state_by_group = setmetatable({}, { ---@param client lsp.Client ---@return vim.lsp.CTGroup local function get_group(client) - local allow_inc_sync = vim.F.if_nil(client.config.flags.allow_incremental_sync, true) --- @type boolean + local allow_inc_sync = vim.F.if_nil(client.flags.allow_incremental_sync, true) --- @type boolean local change_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'change') local sync_kind = change_capability or protocol.TextDocumentSyncKind.None if not allow_inc_sync and change_capability == protocol.TextDocumentSyncKind.Incremental then @@ -134,12 +134,12 @@ function M.init(client, bufnr) local group = get_group(client) local state = state_by_group[group] if state then - state.debounce = math.min(state.debounce, client.config.flags.debounce_text_changes or 150) + state.debounce = math.min(state.debounce, client.flags.debounce_text_changes or 150) state.clients[client.id] = client else state = { buffers = {}, - debounce = client.config.flags.debounce_text_changes or 150, + debounce = client.flags.debounce_text_changes or 150, clients = { [client.id] = client, }, diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua index b6c335bb13..9c2af979fa 100644 --- a/runtime/lua/vim/lsp/_dynamic.lua +++ b/runtime/lua/vim/lsp/_dynamic.lua @@ -19,7 +19,7 @@ function M:supports_registration(method) if not client then return false end - local capability = vim.tbl_get(client.config.capabilities, unpack(vim.split(method, '/'))) + local capability = vim.tbl_get(client.capabilities, unpack(vim.split(method, '/'))) return type(capability) == 'table' and capability.dynamicRegistration end @@ -91,7 +91,7 @@ function M:match(bufnr, documentSelector) if not client then return false end - local language = client.config.get_language_id(bufnr, vim.bo[bufnr].filetype) + local language = client.get_language_id(bufnr, vim.bo[bufnr].filetype) local uri = vim.uri_from_bufnr(bufnr) local fname = vim.uri_to_fname(uri) for _, filter in ipairs(documentSelector) do diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua index 59b8c38166..6ca60b78cd 100644 --- a/runtime/lua/vim/lsp/_watchfiles.lua +++ b/runtime/lua/vim/lsp/_watchfiles.lua @@ -44,12 +44,8 @@ function M.register(reg, ctx) local client = assert(vim.lsp.get_client_by_id(client_id), 'Client must be running') -- Ill-behaved servers may not honor the client capability and try to register -- anyway, so ignore requests when the user has opted out of the feature. - local has_capability = vim.tbl_get( - client.config.capabilities or {}, - 'workspace', - 'didChangeWatchedFiles', - 'dynamicRegistration' - ) + local has_capability = + vim.tbl_get(client.capabilities, 'workspace', 'didChangeWatchedFiles', 'dynamicRegistration') if not has_capability or not client.workspace_folders then return end diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index a279be55e9..a460d95cc6 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -6,28 +6,33 @@ local ms = lsp.protocol.Methods local changetracking = lsp._changetracking local validate = vim.validate +--- @alias vim.lsp.client.on_init_cb fun(client: lsp.Client, initialize_result: lsp.InitializeResult) +--- @alias vim.lsp.client.on_attach_cb fun(client: lsp.Client, bufnr: integer) +--- @alias vim.lsp.client.on_exit_cb fun(code: integer, signal: integer, client_id: integer) +--- @alias vim.lsp.client.before_init_cb fun(params: lsp.InitializeParams, config: lsp.ClientConfig) + --- @class lsp.ClientConfig ---- @field cmd (string[]|fun(dispatchers: table):table) ---- @field cmd_cwd string ---- @field cmd_env (table) ---- @field detached boolean ---- @field workspace_folders (table) ---- @field capabilities lsp.ClientCapabilities ---- @field handlers table ---- @field settings table ---- @field commands table +--- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient? +--- @field cmd_cwd? string +--- @field cmd_env? table +--- @field detached? boolean +--- @field workspace_folders? lsp.WorkspaceFolder[] +--- @field capabilities? lsp.ClientCapabilities +--- @field handlers? table +--- @field settings? table +--- @field commands? table --- @field init_options table --- @field name? string ---- @field get_language_id fun(bufnr: integer, filetype: string): string ---- @field offset_encoding string ---- @field on_error fun(code: integer) ---- @field before_init fun(params: lsp.InitializeParams, config: lsp.ClientConfig) ---- @field on_init fun(client: lsp.Client, initialize_result: lsp.InitializeResult) ---- @field on_exit fun(code: integer, signal: integer, client_id: integer) ---- @field on_attach fun(client: lsp.Client, bufnr: integer) ---- @field trace 'off'|'messages'|'verbose'|nil ---- @field flags table ---- @field root_dir string +--- @field get_language_id? fun(bufnr: integer, filetype: string): string +--- @field offset_encoding? string +--- @field on_error? fun(code: integer, err: string) +--- @field before_init? vim.lsp.client.before_init_cb +--- @field on_init? elem_or_list +--- @field on_exit? elem_or_list +--- @field on_attach? elem_or_list +--- @field trace? 'off'|'messages'|'verbose' +--- @field flags? table +--- @field root_dir? string --- @class lsp.Client.Progress: vim.Ringbuf<{token: integer|string, value: any}> --- @field pending table @@ -66,21 +71,43 @@ local validate = vim.validate --- --- Response from the server sent on --- initialize` describing the server's capabilities. ---- @field server_capabilities lsp.ServerCapabilities +--- @field server_capabilities lsp.ServerCapabilities? --- --- A ring buffer (|vim.ringbuf()|) containing progress messages --- sent by the server. --- @field progress lsp.Client.Progress --- --- @field initialized true? +--- +--- The workspace folders configured in the client when the server starts. +--- This property is only available if the client supports workspace folders. +--- It can be `null` if the client supports workspace folders but none are +--- configured. --- @field workspace_folders lsp.WorkspaceFolder[]? +--- @field root_dir string +--- --- @field attached_buffers table --- @field private _log_prefix string +--- --- Track this so that we can escalate automatically if we've already tried a --- graceful shutdown --- @field private _graceful_shutdown_failed true? ---- @field private commands table --- +--- The initial trace setting. If omitted trace is disabled ("off"). +--- trace = "off" | "messages" | "verbose"; +--- @field private _trace 'off'|'messages'|'verbose' +--- +--- Table of command name to function which is called if any LSP action +--- (code action, code lenses, ...) triggers the command. +--- Client commands take precedence over the global command registry. +--- @field commands table +--- +--- @field settings table +--- @field flags table +--- @field get_language_id fun(bufnr: integer, filetype: string): string +--- +--- The capabilities provided by the client (editor or tool) +--- @field capabilities lsp.ClientCapabilities --- @field dynamic_capabilities lsp.DynamicCapabilities --- --- Sends a request to the server. @@ -122,6 +149,12 @@ local validate = vim.validate --- Useful for buffer-local setup. --- @field on_attach fun(bufnr: integer) --- +--- @field private _before_init_cb? vim.lsp.client.before_init_cb +--- @field private _on_attach_cbs vim.lsp.client.on_attach_cb[] +--- @field private _on_init_cbs vim.lsp.client.on_init_cb[] +--- @field private _on_exit_cbs vim.lsp.client.on_exit_cb[] +--- @field private _on_error_cb? fun(code: integer, err: string) +--- --- Checks if a client supports a given method. --- Always returns true for unknown off-spec methods. --- [opts] is a optional `{bufnr?: integer}` table. @@ -196,9 +229,18 @@ local function optional_validator(fn) end end +--- By default, get_language_id just returns the exact filetype it is passed. +--- It is possible to pass in something that will calculate a different filetype, +--- to be sent by the client. +--- @param _bufnr integer +--- @param filetype string +local function default_get_language_id(_bufnr, filetype) + return filetype +end + --- Validates a client configuration as given to |vim.lsp.start_client()|. --- @param config lsp.ClientConfig -local function process_client_config(config) +local function validate_config(config) validate({ config = { config, 't' }, }) @@ -210,15 +252,17 @@ local function process_client_config(config) detached = { config.detached, 'b', true }, name = { config.name, 's', true }, on_error = { config.on_error, 'f', true }, - on_exit = { config.on_exit, 'f', true }, - on_init = { config.on_init, 'f', true }, + on_exit = { config.on_exit, { 'f', 't' }, true }, + on_init = { config.on_init, { 'f', 't' }, true }, + on_attach = { config.on_attach, { 'f', 't' }, true }, settings = { config.settings, 't', true }, commands = { config.commands, 't', true }, - before_init = { config.before_init, 'f', true }, + before_init = { config.before_init, { 'f', 't' }, true }, offset_encoding = { config.offset_encoding, 's', true }, flags = { config.flags, 't', true }, get_language_id = { config.get_language_id, 'f', true }, }) + assert( ( not config.flags @@ -227,51 +271,98 @@ local function process_client_config(config) ), 'flags.debounce_text_changes must be a number with the debounce time in milliseconds' ) +end + +--- @param trace string +--- @return 'off'|'messages'|'verbose' +local function get_trace(trace) + local valid_traces = { + off = 'off', + messages = 'messages', + verbose = 'verbose', + } + return trace and valid_traces[trace] or 'off' +end - if not config.name and type(config.cmd) == 'table' then - config.name = config.cmd[1] and vim.fs.basename(config.cmd[1]) or nil +--- @param id integer +--- @param config lsp.ClientConfig +--- @return string +local function get_name(id, config) + local name = config.name + if name then + return name end - config.offset_encoding = validate_encoding(config.offset_encoding) - config.flags = config.flags or {} - config.settings = config.settings or {} - config.handlers = config.handlers or {} + if type(config.cmd) == 'table' and config.cmd[1] then + return assert(vim.fs.basename(config.cmd[1])) + end - -- By default, get_language_id just returns the exact filetype it is passed. - -- It is possible to pass in something that will calculate a different filetype, - -- to be sent by the client. - config.get_language_id = config.get_language_id or function(_, filetype) - return filetype + return tostring(id) +end + +--- @param workspace_folders lsp.WorkspaceFolder[]? +--- @param root_dir string? +--- @return lsp.WorkspaceFolder[]? +local function get_workspace_folders(workspace_folders, root_dir) + if workspace_folders then + return workspace_folders end + if root_dir then + return { + { + uri = vim.uri_from_fname(root_dir), + name = string.format('%s', root_dir), + }, + } + end +end - config.capabilities = config.capabilities or lsp.protocol.make_client_capabilities() - config.commands = config.commands or {} +--- @generic T +--- @param x elem_or_list? +--- @return T[] +local function ensure_list(x) + if type(x) == 'table' then + return x + end + return { x } end --- @package --- @param config lsp.ClientConfig --- @return lsp.Client? -function Client.start(config) - process_client_config(config) +function Client.create(config) + validate_config(config) client_index = client_index + 1 local id = client_index - - local name = config.name or tostring(id) + local name = get_name(id, config) --- @class lsp.Client local self = { id = id, config = config, - handlers = config.handlers, - offset_encoding = config.offset_encoding, + handlers = config.handlers or {}, + offset_encoding = validate_encoding(config.offset_encoding), name = name, _log_prefix = string.format('LSP[%s]', name), requests = {}, attached_buffers = {}, server_capabilities = {}, - dynamic_capabilities = vim.lsp._dynamic.new(id), - commands = config.commands, -- Remove in Nvim 0.11 + dynamic_capabilities = lsp._dynamic.new(id), + commands = config.commands or {}, + settings = config.settings or {}, + flags = config.flags or {}, + get_language_id = config.get_language_id or default_get_language_id, + capabilities = config.capabilities or lsp.protocol.make_client_capabilities(), + workspace_folders = get_workspace_folders(config.workspace_folders, config.root_dir), + root_dir = config.root_dir, + _before_init_cb = config.before_init, + _on_init_cbs = ensure_list(config.on_init), + _on_exit_cbs = ensure_list(config.on_exit), + _on_attach_cbs = ensure_list(config.on_attach), + _on_error_cb = config.on_error, + _root_dir = config.root_dir, + _trace = get_trace(config.trace), --- Contains $/progress report messages. --- They have the format {token: integer|string, value: any} @@ -327,41 +418,31 @@ function Client.start(config) setmetatable(self, Client) - self:initialize() - return self end ---- @private -function Client:initialize() - local valid_traces = { - off = 'off', - messages = 'messages', - verbose = 'verbose', - } +--- @param cbs function[] +--- @param error_id integer +--- @param ... any +function Client:_run_callbacks(cbs, error_id, ...) + for _, cb in pairs(cbs) do + --- @type boolean, string? + local status, err = pcall(cb, ...) + if not status then + self:write_error(error_id, err) + end + end +end +--- @package +function Client:initialize() local config = self.config - local workspace_folders --- @type lsp.WorkspaceFolder[]? local root_uri --- @type string? local root_path --- @type string? - if config.workspace_folders or config.root_dir then - if config.root_dir and not config.workspace_folders then - workspace_folders = { - { - uri = vim.uri_from_fname(config.root_dir), - name = string.format('%s', config.root_dir), - }, - } - else - workspace_folders = config.workspace_folders - end - root_uri = workspace_folders[1].uri + if self.workspace_folders then + root_uri = self.workspace_folders[1].uri root_path = vim.uri_to_fname(root_uri) - else - workspace_folders = nil - root_uri = nil - root_path = nil end local initialize_params = { @@ -383,26 +464,19 @@ function Client:initialize() -- The rootUri of the workspace. Is null if no folder is open. If both -- `rootPath` and `rootUri` are set `rootUri` wins. rootUri = root_uri or vim.NIL, - -- The workspace folders configured in the client when the server starts. - -- This property is only available if the client supports workspace folders. - -- It can be `null` if the client supports workspace folders but none are - -- configured. - workspaceFolders = workspace_folders or vim.NIL, + workspaceFolders = self.workspace_folders or vim.NIL, -- User provided initialization options. initializationOptions = config.init_options, - -- The capabilities provided by the client (editor or tool) - capabilities = config.capabilities, - -- The initial trace setting. If omitted trace is disabled ("off"). - -- trace = "off" | "messages" | "verbose"; - trace = valid_traces[config.trace] or 'off', + capabilities = self.capabilities, + trace = self._trace, } - if config.before_init then - --- @type boolean, string? - local status, err = pcall(config.before_init, initialize_params, config) - if not status then - self:write_error(lsp.client_errors.BEFORE_INIT_CALLBACK_ERROR, err) - end - end + + self:_run_callbacks( + { self._before_init_cb }, + lsp.client_errors.BEFORE_INIT_CALLBACK_ERROR, + initialize_params, + config + ) log.trace(self._log_prefix, 'initialize_params', initialize_params) @@ -413,7 +487,6 @@ function Client:initialize() assert(result, 'server sent empty result') rpc.notify('initialized', vim.empty_dict()) self.initialized = true - self.workspace_folders = workspace_folders -- These are the cleaned up capabilities we use for dynamically deciding -- when to send certain events to clients. @@ -425,17 +498,11 @@ function Client:initialize() self.offset_encoding = self.server_capabilities.positionEncoding end - if next(config.settings) then - self:_notify(ms.workspace_didChangeConfiguration, { settings = config.settings }) + if next(self.settings) then + self:_notify(ms.workspace_didChangeConfiguration, { settings = self.settings }) end - if config.on_init then - --- @type boolean, string? - local status, err = pcall(config.on_init, self, result) - if not status then - self:write_error(lsp.client_errors.ON_INIT_CALLBACK_ERROR, err) - end - end + self:_run_callbacks(self._on_init_cbs, lsp.client_errors.ON_INIT_CALLBACK_ERROR, self, result) log.info( self._log_prefix, @@ -672,7 +739,7 @@ function Client:_is_stopped() return self.rpc.is_closing() end ---- @private +--- @package --- Execute a lsp command, either via client command function (if available) --- or via workspace/executeCommand (if supported by the server) --- @@ -684,7 +751,7 @@ function Client:_exec_cmd(command, context, handler) context.bufnr = context.bufnr or api.nvim_get_current_buf() context.client_id = self.id local cmdname = command.command - local fn = self.config.commands[cmdname] or lsp.commands[cmdname] + local fn = self.commands[cmdname] or lsp.commands[cmdname] if fn then fn(command, context) return @@ -730,7 +797,7 @@ function Client:_text_document_did_open_handler(bufnr) textDocument = { version = 0, uri = vim.uri_from_bufnr(bufnr), - languageId = self.config.get_language_id(bufnr, filetype), + languageId = self.get_language_id(bufnr, filetype), text = lsp._buf_get_full_text(bufnr), }, } @@ -742,13 +809,13 @@ function Client:_text_document_did_open_handler(bufnr) -- Protect against a race where the buffer disappears -- between `did_open_handler` and the scheduled function firing. if api.nvim_buf_is_valid(bufnr) then - local namespace = vim.lsp.diagnostic.get_namespace(self.id) + local namespace = lsp.diagnostic.get_namespace(self.id) vim.diagnostic.show(namespace, bufnr) end end) end ---- @private +--- @package --- Runs the on_attach function from the client's config if it was defined. --- @param bufnr integer Buffer number function Client:_on_attach(bufnr) @@ -762,13 +829,7 @@ function Client:_on_attach(bufnr) data = { client_id = self.id }, }) - if self.config.on_attach then - --- @type boolean, string? - local status, err = pcall(self.config.on_attach, self, bufnr) - if not status then - self:write_error(lsp.client_errors.ON_ATTACH_ERROR, err) - end - end + self:_run_callbacks(self._on_attach_cbs, lsp.client_errors.ON_ATTACH_ERROR, self, bufnr) -- schedule the initialization of semantic tokens to give the above -- on_attach and LspAttach callbacks the ability to schedule wrap the @@ -795,7 +856,6 @@ end --- @param method string --- @param opts? {bufnr: integer?} function Client:_supports_method(method, opts) - opts = opts or {} local required_capability = lsp._request_name_to_capability[method] -- if we don't know about the method, assume that the client supports it. if not required_capability then @@ -803,12 +863,11 @@ function Client:_supports_method(method, opts) end if vim.tbl_get(self.server_capabilities, unpack(required_capability)) then return true - else - if self.dynamic_capabilities:supports_registration(method) then - return self.dynamic_capabilities:supports(method, opts) - end - return false end + if self.dynamic_capabilities:supports_registration(method) then + return self.dynamic_capabilities:supports(method, opts) + end + return false end --- @private @@ -853,9 +912,9 @@ end --- `vim.lsp.rpc.client_errors[code]` to get a human-friendly name. function Client:_on_error(code, err) self:write_error(code, err) - if self.config.on_error then + if self._on_error_cb then --- @type boolean, string - local status, usererr = pcall(self.config.on_error, code, err) + local status, usererr = pcall(self._on_error_cb, code, err) if not status then log.error(self._log_prefix, 'user on_error failed', { err = usererr }) err_message(self._log_prefix, ' user on_error failed: ', tostring(usererr)) @@ -869,9 +928,13 @@ end --- @param code integer) exit code of the process --- @param signal integer the signal used to terminate (if any) function Client:_on_exit(code, signal) - if self.config.on_exit then - pcall(self.config.on_exit, code, signal, self.id) - end + self:_run_callbacks( + self._on_exit_cbs, + lsp.client_errors.ON_EXIT_CALLBACK_ERROR, + code, + signal, + self.id + ) end return Client diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index ab49e03c52..966c7f4d03 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -48,7 +48,6 @@ local function execute_lens(lens, bufnr, client_id) local client = vim.lsp.get_client_by_id(client_id) assert(client, 'Client is required to execute lens, client_id=' .. client_id) - ---@diagnostic disable-next-line: invisible client:_exec_cmd(lens.command, { bufnr = bufnr }, function(...) vim.lsp.handlers[ms.workspace_executeCommand](...) M.refresh() diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 4bb14e5a09..a9da812231 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -197,10 +197,10 @@ M[ms.workspace_configuration] = function(_, result, ctx) local response = {} for _, item in ipairs(result.items) do if item.section then - local value = lookup_section(client.config.settings, item.section) + local value = lookup_section(client.settings, item.section) -- For empty sections with no explicit '' key, return settings as is if value == nil and item.section == '' then - value = client.config.settings + value = client.settings end if value == nil then value = vim.NIL diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index d770735895..15e4555b55 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -38,7 +38,7 @@ function M.check() '%s (id=%s, root_dir=%s, attached_to=[%s])', client.name, client.id, - vim.fn.fnamemodify(client.config.root_dir, ':~'), + vim.fn.fnamemodify(client.root_dir, ':~'), attached_to ) ) -- cgit From d09957e0a06f350443c750d9838b5f1016c0cccc Mon Sep 17 00:00:00 2001 From: Tomasz N Date: Wed, 14 Feb 2024 21:11:29 +0100 Subject: fix(lsp): rename: load and list new buffer if attached to window (#27408) --- runtime/lua/vim/lsp/util.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 86bef1ac8a..4abc58ee3c 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -702,6 +702,8 @@ function M.rename(old_fname, new_fname, opts) if vim.fn.isdirectory(new_fname) == 0 then local newbuf = vim.fn.bufadd(new_fname) if win then + vim.fn.bufload(newbuf) + vim.bo[newbuf].buflisted = true api.nvim_win_set_buf(win, newbuf) end end -- cgit From cc15ba212c7992c3f3aae8b90962862572b21e83 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 18 Feb 2024 14:52:16 -0800 Subject: refactor(lsp): typings for protocol constants --- runtime/lua/vim/lsp/protocol.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 35eb0305d7..82e8c4a7de 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -1,6 +1,6 @@ --- Protocol for the Microsoft Language Server Protocol (mslsp) +--- @diagnostic disable: duplicate-doc-alias -local protocol = {} +-- Protocol for the Microsoft Language Server Protocol (mslsp) --[=[ ---@private @@ -20,7 +20,7 @@ function transform_schema_to_table() end --]=] -local constants = { +local protocol = { --- @enum lsp.DiagnosticSeverity DiagnosticSeverity = { -- Reports an error. @@ -313,7 +313,7 @@ local constants = { }, } -for k, v in pairs(constants) do +for k, v in pairs(protocol) do local tbl = vim.deepcopy(v, true) vim.tbl_add_reverse_lookup(tbl) protocol[k] = tbl @@ -723,7 +723,7 @@ function protocol.make_client_capabilities() codeActionLiteralSupport = { codeActionKind = { valueSet = (function() - local res = vim.tbl_values(constants.CodeActionKind) + local res = vim.tbl_values(protocol.CodeActionKind) table.sort(res) return res end)(), -- cgit From ac0e8323dc82622a201f49efcdfcb79567a8f75e Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Wed, 21 Feb 2024 03:31:56 -0800 Subject: fix(lsp): add parentheses to generated union array types (#27560) --- runtime/lua/vim/lsp/_meta/protocol.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua index b897b6bba5..a5da5ac6b7 100644 --- a/runtime/lua/vim/lsp/_meta/protocol.lua +++ b/runtime/lua/vim/lsp/_meta/protocol.lua @@ -409,7 +409,7 @@ error('Cannot require a meta file') --- ---If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then ---only plain `TextEdit`s using the `changes` property are supported. ----@field documentChanges? lsp.TextDocumentEdit|lsp.CreateFile|lsp.RenameFile|lsp.DeleteFile[] +---@field documentChanges? (lsp.TextDocumentEdit|lsp.CreateFile|lsp.RenameFile|lsp.DeleteFile)[] --- ---A map of change annotations that can be referenced in `AnnotatedTextEdit`s or create, rename and ---delete file / folder operations. @@ -1888,7 +1888,7 @@ error('Cannot require a meta file') --- ---@since 3.16.0 - support for AnnotatedTextEdit. This is guarded using a ---client capability. ----@field edits lsp.TextEdit|lsp.AnnotatedTextEdit[] +---@field edits (lsp.TextEdit|lsp.AnnotatedTextEdit)[] ---Create file operation. ---@class lsp.CreateFile: lsp.ResourceOperation @@ -3146,7 +3146,7 @@ error('Cannot require a meta file') ---@class lsp.NotebookDocumentSyncOptions --- ---The notebooks to be synced ----@field notebookSelector lsp._anonym14.notebookSelector|lsp._anonym16.notebookSelector[] +---@field notebookSelector (lsp._anonym14.notebookSelector|lsp._anonym16.notebookSelector)[] --- ---Whether save notification should be forwarded to ---the server. Will only be honored if mode === `notebook`. -- cgit From 90f6d999b12a93bb8a2aa9a735d2d77fc97b94db Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 24 Feb 2024 21:14:12 +0900 Subject: refactor(lsp): remove redundant code (#27601) * use builtin function * buffer:// was removed in 236c20795eb9f11e21e0719b735ea741711acc08. --- runtime/lua/vim/lsp/util.lua | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 4abc58ee3c..418eb5e159 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -639,21 +639,12 @@ function M.text_document_completion_list_to_complete_items(result, prefix) return vim.lsp._completion._lsp_to_complete_items(result, prefix) end ---- Like vim.fn.bufwinid except it works across tabpages. -local function bufwinid(bufnr) - for _, win in ipairs(api.nvim_list_wins()) do - if api.nvim_win_get_buf(win) == bufnr then - return win - end - end -end - --- Get list of buffers for a directory local function get_dir_bufs(path) path = path:gsub('([^%w])', '%%%1') local buffers = {} for _, v in ipairs(vim.api.nvim_list_bufs()) do - local bufname = vim.api.nvim_buf_get_name(v):gsub('buffer://', '') + local bufname = vim.api.nvim_buf_get_name(v) if bufname:find(path) then table.insert(buffers, v) end @@ -682,7 +673,7 @@ function M.rename(old_fname, new_fname, opts) else local oldbuf = vim.fn.bufadd(old_fname) table.insert(oldbufs, oldbuf) - win = bufwinid(oldbuf) + win = vim.fn.win_findbuf(oldbuf)[1] end for _, b in ipairs(oldbufs) do @@ -1061,7 +1052,7 @@ function M.show_document(location, offset_encoding, opts) vim.fn.settagstack(vim.fn.win_getid(), { items = items }, 't') end - local win = opts.reuse_win and bufwinid(bufnr) + local win = opts.reuse_win and vim.fn.win_findbuf(bufnr)[1] or focus and api.nvim_get_current_win() or create_window_without_focus() -- cgit From a0394b648c2486ce7085d3e6e7541024e1a3fe9a Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 24 Feb 2024 14:49:36 +0100 Subject: docs(lsp): mark `ClientConfig.init_options` as optional Followup to neovim/neovim#27443 --- runtime/lua/vim/lsp/client.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index a460d95cc6..c1b41a7183 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -21,7 +21,7 @@ local validate = vim.validate --- @field handlers? table --- @field settings? table --- @field commands? table ---- @field init_options table +--- @field init_options? table --- @field name? string --- @field get_language_id? fun(bufnr: integer, filetype: string): string --- @field offset_encoding? string -- cgit From 8addd27504e698da62176824209ae2d3d24247c0 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sun, 25 Feb 2024 00:47:34 +0900 Subject: fix(lsp): when renaming directory, check path prefix of buffer names (#27603) For example, when renaming /path/to/dir, buffers like fern://drawer/file:///path/to/dir, /path/to/dir123 should not be matched. --- runtime/lua/vim/lsp/util.lua | 53 ++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 14 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 418eb5e159..444354fdc3 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -639,13 +639,28 @@ function M.text_document_completion_list_to_complete_items(result, prefix) return vim.lsp._completion._lsp_to_complete_items(result, prefix) end ---- Get list of buffers for a directory -local function get_dir_bufs(path) - path = path:gsub('([^%w])', '%%%1') +local function path_components(path) + return vim.split(path, '/', { plain = true }) +end + +local function path_under_prefix(path, prefix) + for i, c in ipairs(prefix) do + if c ~= path[i] then + return false + end + end + return true +end + +--- Get list of buffers whose filename matches the given path prefix (normalized full path) +---@return integer[] +local function get_bufs_with_prefix(prefix) + prefix = path_components(prefix) local buffers = {} for _, v in ipairs(vim.api.nvim_list_bufs()) do - local bufname = vim.api.nvim_buf_get_name(v) - if bufname:find(path) then + local bname = vim.api.nvim_buf_get_name(v) + local path = path_components(vim.fs.normalize(bname, { expand_env = false })) + if path_under_prefix(path, prefix) then table.insert(buffers, v) end end @@ -654,24 +669,34 @@ end --- Rename old_fname to new_fname --- ----@param opts (table) --- overwrite? bool --- ignoreIfExists? bool +---@param old_fname string +---@param new_fname string +---@param opts? table options +--- - overwrite? boolean +--- - ignoreIfExists? boolean function M.rename(old_fname, new_fname, opts) opts = opts or {} + local skip = not opts.overwrite or opts.ignoreIfExists + + local old_fname_full = vim.uv.fs_realpath(vim.fs.normalize(old_fname, { expand_env = false })) + if not old_fname_full then + vim.notify('Invalid path: ' .. old_fname, vim.log.levels.ERROR) + return + end + local target_exists = uv.fs_stat(new_fname) ~= nil - if target_exists and not opts.overwrite or opts.ignoreIfExists then - vim.notify('Rename target already exists. Skipping rename.') + if target_exists and skip then + vim.notify(new_fname .. ' already exists. Skipping rename.', vim.log.levels.ERROR) return end local oldbufs = {} local win = nil - if vim.fn.isdirectory(old_fname) == 1 then - oldbufs = get_dir_bufs(old_fname) + if vim.fn.isdirectory(old_fname_full) == 1 then + oldbufs = get_bufs_with_prefix(old_fname_full) else - local oldbuf = vim.fn.bufadd(old_fname) + local oldbuf = vim.fn.bufadd(old_fname_full) table.insert(oldbufs, oldbuf) win = vim.fn.win_findbuf(oldbuf)[1] end @@ -687,7 +712,7 @@ function M.rename(old_fname, new_fname, opts) local newdir = assert(vim.fs.dirname(new_fname)) vim.fn.mkdir(newdir, 'p') - local ok, err = os.rename(old_fname, new_fname) + local ok, err = os.rename(old_fname_full, new_fname) assert(ok, err) if vim.fn.isdirectory(new_fname) == 0 then -- cgit From 2e1f5055acdef650c27efc4afdf8606037ec021b Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sat, 24 Feb 2024 19:21:57 -0600 Subject: fix(lsp): add assertion for explicit bufnr in apply_text_edits (#27614) Assert that the buffer number passed to apply_text_edits is fully resolved (not 0 or null). Pass the known buffer number to apply_text_edits from lsp.formatexpr(). --- runtime/lua/vim/lsp/util.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 444354fdc3..b60135f851 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -419,6 +419,9 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) if not next(text_edits) then return end + + assert(bufnr ~= 0, 'Explicit buffer number is required') + if not api.nvim_buf_is_loaded(bufnr) then vim.fn.bufload(bufnr) end @@ -457,7 +460,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) -- save and restore local marks since they get deleted by nvim_buf_set_lines local marks = {} - for _, m in pairs(vim.fn.getmarklist(bufnr or vim.api.nvim_get_current_buf())) do + for _, m in pairs(vim.fn.getmarklist(bufnr)) do if m.mark:match("^'[a-z]$") then marks[m.mark:sub(2, 2)] = { m.pos[2], m.pos[3] - 1 } -- api-indexed end @@ -516,7 +519,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) local max = api.nvim_buf_line_count(bufnr) -- no need to restore marks that still exist - for _, m in pairs(vim.fn.getmarklist(bufnr or vim.api.nvim_get_current_buf())) do + for _, m in pairs(vim.fn.getmarklist(bufnr)) do marks[m.mark:sub(2, 2)] = nil end -- restore marks -- cgit From 9beb40a4db5613601fc1a4b828a44e5977eca046 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 15 Feb 2024 17:16:04 +0000 Subject: feat(docs): replace lua2dox.lua Problem: The documentation flow (`gen_vimdoc.py`) has several issues: - it's not very versatile - depends on doxygen - doesn't work well with Lua code as it requires an awkward filter script to convert it into pseudo-C. - The intermediate XML files and filters makes it too much like a rube goldberg machine. Solution: Re-implement the flow using Lua, LPEG and treesitter. - `gen_vimdoc.py` is now replaced with `gen_vimdoc.lua` and replicates a portion of the logic. - `lua2dox.lua` is gone! - No more XML files. - Doxygen is now longer used and instead we now use: - LPEG for comment parsing (see `scripts/luacats_grammar.lua` and `scripts/cdoc_grammar.lua`). - LPEG for C parsing (see `scripts/cdoc_parser.lua`) - Lua patterns for Lua parsing (see `scripts/luacats_parser.lua`). - Treesitter for Markdown parsing (see `scripts/text_utils.lua`). - The generated `runtime/doc/*.mpack` files have been removed. - `scripts/gen_eval_files.lua` now instead uses `scripts/cdoc_parser.lua` directly. - Text wrapping is implemented in `scripts/text_utils.lua` and appears to produce more consistent results (the main contributer to the diff of this change). --- runtime/lua/vim/lsp/buf.lua | 35 +++++++++++++++++++---------------- runtime/lua/vim/lsp/codelens.lua | 2 ++ runtime/lua/vim/lsp/diagnostic.lua | 4 ++-- runtime/lua/vim/lsp/handlers.lua | 5 ++++- runtime/lua/vim/lsp/log.lua | 2 +- runtime/lua/vim/lsp/rpc.lua | 2 -- runtime/lua/vim/lsp/sync.lua | 4 ++-- runtime/lua/vim/lsp/util.lua | 8 ++++++-- 8 files changed, 36 insertions(+), 26 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 7fc5286a78..d2e92de083 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -12,7 +12,7 @@ local M = {} ---@param method (string) LSP method name ---@param params (table|nil) Parameters to send to the server ---@param handler (function|nil) 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 @@ -172,12 +172,13 @@ end --- --- - filter (function|nil): --- Predicate used to filter clients. Receives a client as argument and must return a ---- boolean. Clients matching the predicate are included. Example:
lua
----                     -- Never request typescript-language-server for formatting
----                     vim.lsp.buf.format {
----                       filter = function(client) return client.name ~= "tsserver" end
----                     }
----         
+--- boolean. Clients matching the predicate are included. Example: +--- ```lua +--- -- Never request typescript-language-server for formatting +--- vim.lsp.buf.format { +--- filter = function(client) return client.name ~= "tsserver" end +--- } +--- ``` --- --- - async boolean|nil --- If true the method won't block. Defaults to false. @@ -472,6 +473,7 @@ end --- Add the folder at path to the workspace folders. If {path} is --- not provided, the user will be prompted for a path using |input()|. +--- @param workspace_folder? string function M.add_workspace_folder(workspace_folder) workspace_folder = workspace_folder or npcall(vim.fn.input, 'Workspace Folder: ', vim.fn.expand('%:p:h'), 'dir') @@ -511,6 +513,7 @@ end --- Remove the folder at path from the workspace folders. If --- {path} is not provided, the user will be prompted for --- a path using |input()|. +--- @param workspace_folder? string function M.remove_workspace_folder(workspace_folder) workspace_folder = workspace_folder or npcall(vim.fn.input, 'Workspace Folder: ', vim.fn.expand('%:p:h')) @@ -725,15 +728,15 @@ end --- ---@param options table|nil Optional table which holds the following optional fields: --- - context: (table|nil) ---- Corresponds to `CodeActionContext` of the LSP specification: ---- - diagnostics (table|nil): ---- LSP `Diagnostic[]`. Inferred from the current ---- position if not provided. ---- - only (table|nil): ---- List of LSP `CodeActionKind`s used to filter the code actions. ---- Most language servers support values like `refactor` ---- or `quickfix`. ---- - triggerKind (number|nil): The reason why code actions were requested. +--- Corresponds to `CodeActionContext` of the LSP specification: +--- - diagnostics (table|nil): +--- LSP `Diagnostic[]`. Inferred from the current +--- position if not provided. +--- - only (table|nil): +--- List of LSP `CodeActionKind`s used to filter the code actions. +--- Most language servers support values like `refactor` +--- or `quickfix`. +--- - triggerKind (number|nil): The reason why code actions were requested. --- - filter: (function|nil) --- Predicate taking an `CodeAction` and returning a boolean. --- - apply: (boolean|nil) diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index 966c7f4d03..7aed6f99e3 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -258,6 +258,8 @@ end --- |lsp-handler| for the method `textDocument/codeLens` --- +---@param err lsp.ResponseError? +---@param result lsp.CodeLens[] ---@param ctx lsp.HandlerContext function M.on_codelens(err, result, ctx, _) if err then diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 33051ab61c..1fa67fc473 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -1,5 +1,3 @@ ----@brief lsp-diagnostic - local protocol = require('vim.lsp.protocol') local ms = protocol.Methods @@ -287,6 +285,7 @@ end --- ) --- ``` --- +---@param _ lsp.ResponseError? ---@param result lsp.PublishDiagnosticsParams ---@param ctx lsp.HandlerContext ---@param config? vim.diagnostic.Opts Configuration table (see |vim.diagnostic.config()|). @@ -319,6 +318,7 @@ end --- ) --- ``` --- +---@param _ lsp.ResponseError? ---@param result lsp.DocumentDiagnosticReport ---@param ctx lsp.HandlerContext ---@param config table Configuration table (see |vim.diagnostic.config()|). diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index a9da812231..781d720486 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -368,6 +368,8 @@ end --- ) --- ``` --- +---@param _ lsp.ResponseError? +---@param result lsp.Hover ---@param ctx lsp.HandlerContext ---@param config table Configuration table. --- - border: (default=nil) @@ -464,7 +466,8 @@ M[ms.textDocument_implementation] = location_handler --- ) --- ``` --- ----@param result table Response from the language server +---@param _ lsp.ResponseError? +---@param result lsp.SignatureHelp Response from the language server ---@param ctx lsp.HandlerContext Client context ---@param config table Configuration table. --- - border: (default=nil) diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index a9d49bc8f4..018003bb81 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -165,7 +165,7 @@ end --- Checks whether the level is sufficient for logging. ---@param level integer log level ----@returns (bool) true if would log, false if not +---@return bool : true if would log, false if not function log.should_log(level) return level >= current_log_level end diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index e849bb4f2a..1455ab51fa 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -273,8 +273,6 @@ end ---@field notify_reply_callbacks table dict of message_id to callback ---@field transport vim.lsp.rpc.Transport ---@field dispatchers vim.lsp.rpc.Dispatchers - ----@class vim.lsp.rpc.Client local Client = {} ---@private diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 62fa0b33f4..936579e003 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -53,7 +53,7 @@ local str_utf_end = vim.str_utf_end ---@param line string the line to index into ---@param byte integer the byte idx ---@param offset_encoding string utf-8|utf-16|utf-32|nil (default: utf-8) ---@returns integer the utf idx for the given encoding +---@return integer utf_idx for the given encoding local function byte_to_utf(line, byte, offset_encoding) -- convert to 0 based indexing for str_utfindex byte = byte - 1 @@ -204,7 +204,7 @@ end --- Normalized to the next codepoint. --- prev_end_range is the text range sent to the server representing the changed region. --- curr_end_range is the text that should be collected and sent to the server. --- +--- ---@param prev_lines string[] list of lines ---@param curr_lines string[] list of lines ---@param start_range vim.lsp.sync.Range diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index b60135f851..e371cb0e15 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -574,6 +574,7 @@ end --- ---@param text_document_edit table: a `TextDocumentEdit` object ---@param index integer: Optional index of the edit, if from a list of edits (or nil, if not from a list) +---@param offset_encoding? string ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit function M.apply_text_document_edit(text_document_edit, index, offset_encoding) local text_document = text_document_edit.textDocument @@ -770,7 +771,7 @@ end --- ---@param workspace_edit table `WorkspaceEdit` ---@param offset_encoding string utf-8|utf-16|utf-32 (required) ---see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit function M.apply_workspace_edit(workspace_edit, offset_encoding) if offset_encoding == nil then vim.notify_once( @@ -1130,6 +1131,7 @@ end --- - for LocationLink, targetRange is shown (e.g., body of function definition) --- ---@param location table a single `Location` or `LocationLink` +---@param opts table ---@return integer|nil buffer id of float window ---@return integer|nil window id of float window function M.preview_location(location, opts) @@ -1243,6 +1245,7 @@ end --- --- If you want to open a popup with fancy markdown, use `open_floating_preview` instead --- +---@param bufnr integer ---@param contents table of lines to show in window ---@param opts table with optional fields --- - height of floating window @@ -1603,7 +1606,7 @@ end ---@param contents table of lines to show in window ---@param syntax string of syntax to set for opened buffer ---@param opts table with optional fields (additional keys are filtered with |vim.lsp.util.make_floating_popup_options()| ---- before they are passed on to |nvim_open_win()|) +--- before they are passed on to |nvim_open_win()|) --- - height: (integer) height of floating window --- - width: (integer) width of floating window --- - wrap: (boolean, default true) wrap long lines @@ -1868,6 +1871,7 @@ end --- Converts symbols to quickfix list items. --- ---@param symbols table DocumentSymbol[] or SymbolInformation[] +---@param bufnr integer function M.symbols_to_items(symbols, bufnr) local function _symbols_to_items(_symbols, _items, _bufnr) for _, symbol in ipairs(_symbols) do -- cgit From 3d96e3f9f25389e979bb7f2417ec2135f79fbfbb Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Mon, 26 Feb 2024 11:42:16 -0800 Subject: refactor(lsp): alias for CompletionResult --- runtime/lua/vim/lsp/_completion.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_completion.lua b/runtime/lua/vim/lsp/_completion.lua index 84dbf9083e..3a38c1b5e1 100644 --- a/runtime/lua/vim/lsp/_completion.lua +++ b/runtime/lua/vim/lsp/_completion.lua @@ -4,6 +4,8 @@ local lsp = vim.lsp local protocol = lsp.protocol local ms = protocol.Methods +--- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] + ---@param input string unparsed snippet ---@return string parsed snippet local function parse_snippet(input) @@ -37,7 +39,7 @@ local function get_completion_word(item) return item.label end ----@param result lsp.CompletionList|lsp.CompletionItem[] +---@param result vim.lsp.CompletionResult ---@return lsp.CompletionItem[] local function get_items(result) if result.items then @@ -49,7 +51,7 @@ end --- Turns the result of a `textDocument/completion` request into vim-compatible --- |complete-items|. --- ----@param result lsp.CompletionList|lsp.CompletionItem[] Result of `textDocument/completion` +---@param result vim.lsp.CompletionResult Result of `textDocument/completion` ---@param prefix string prefix to filter the completion items ---@return table[] ---@see complete-items @@ -130,7 +132,7 @@ end ---@param lnum integer 0-indexed line number ---@param client_start_boundary integer 0-indexed word boundary ---@param server_start_boundary? integer 0-indexed word boundary, based on textEdit.range.start.character ----@param result lsp.CompletionList|lsp.CompletionItem[] +---@param result vim.lsp.CompletionResult ---@param encoding string ---@return table[] matches ---@return integer? server_start_boundary -- cgit From 63f9c2da9aab52fa698fcbfdbc58ffd41794d28a Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Mon, 26 Feb 2024 11:42:51 -0800 Subject: feat(lsp): support completion itemDefaults --- runtime/lua/vim/lsp/_completion.lua | 40 ++++++++++++++++++++++++++++++++++++- runtime/lua/vim/lsp/protocol.lua | 8 ++++++++ runtime/lua/vim/lsp/util.lua | 4 ++++ 3 files changed, 51 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_completion.lua b/runtime/lua/vim/lsp/_completion.lua index 3a38c1b5e1..a169f96565 100644 --- a/runtime/lua/vim/lsp/_completion.lua +++ b/runtime/lua/vim/lsp/_completion.lua @@ -6,6 +6,14 @@ local ms = protocol.Methods --- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] +-- TODO(mariasolos): Remove this declaration once we figure out a better way to handle +-- literal/anonymous types (see https://github.com/neovim/neovim/pull/27542/files#r1495259331). +--- @class lsp.ItemDefaults +--- @field editRange lsp.Range | { insert: lsp.Range, replace: lsp.Range } | nil +--- @field insertTextFormat lsp.InsertTextFormat? +--- @field insertTextMode lsp.InsertTextMode? +--- @field data any + ---@param input string unparsed snippet ---@return string parsed snippet local function parse_snippet(input) @@ -39,13 +47,43 @@ local function get_completion_word(item) return item.label end +--- Applies the given defaults to the completion item, modifying it in place. +--- +--- @param item lsp.CompletionItem +--- @param defaults lsp.ItemDefaults? +local function apply_defaults(item, defaults) + if not defaults then + return + end + + item.insertTextFormat = item.insertTextFormat or defaults.insertTextFormat + item.insertTextMode = item.insertTextMode or defaults.insertTextMode + item.data = item.data or defaults.data + if defaults.editRange then + local textEdit = item.textEdit or {} + item.textEdit = textEdit + textEdit.newText = textEdit.newText or item.textEditText or item.insertText + if defaults.editRange.start then + textEdit.range = textEdit.range or defaults.editRange + elseif defaults.editRange.insert then + textEdit.insert = defaults.editRange.insert + textEdit.replace = defaults.editRange.replace + end + end +end + ---@param result vim.lsp.CompletionResult ---@return lsp.CompletionItem[] local function get_items(result) if result.items then + for _, item in ipairs(result.items) do + ---@diagnostic disable-next-line: param-type-mismatch + apply_defaults(item, result.itemDefaults) + end return result.items + else + return result end - return result end --- Turns the result of a `textDocument/completion` request into vim-compatible diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 82e8c4a7de..fb41311961 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -764,6 +764,14 @@ function protocol.make_client_capabilities() return res end)(), }, + completionList = { + itemDefaults = { + 'editRange', + 'insertTextFormat', + 'insertTextMode', + 'data', + }, + }, -- TODO(tjdevries): Implement this contextSupport = false, diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index e371cb0e15..3973e606f8 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -551,6 +551,10 @@ end --- Can be used to extract the completion items from a --- `textDocument/completion` request, which may return one of --- `CompletionItem[]`, `CompletionList` or null. +--- +--- Note that this method doesn't apply `itemDefaults` to `CompletionList`s, and hence the returned +--- results might be incorrect. +--- ---@deprecated ---@param result table The result of a `textDocument/completion` request ---@return lsp.CompletionItem[] List of completion items -- cgit From 7311958e1238559db7a0b1f490f15f618f51af06 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Thu, 29 Feb 2024 01:32:25 +0900 Subject: fix(lsp): remove unnecessary file load/write when renaming (#27621) Previously rename would unconditionally read the to-be-renamed file from the disk and write it to the disk. This is redundant in some cases If the file is not already loaded, it's not attached to lsp client, so nvim doesn't need to care about this file. If the file is loaded but has no change, it doesn't need to be written. --- runtime/lua/vim/lsp/util.lua | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 3973e606f8..d2a5d9a08e 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -710,11 +710,12 @@ function M.rename(old_fname, new_fname, opts) end for _, b in ipairs(oldbufs) do - vim.fn.bufload(b) - -- The there may be pending changes in the buffer - api.nvim_buf_call(b, function() - vim.cmd('w!') - end) + -- There may be pending changes in the buffer + if api.nvim_buf_is_loaded(b) then + api.nvim_buf_call(b, function() + vim.cmd('update!') + end) + end end local newdir = assert(vim.fs.dirname(new_fname)) -- cgit From aa62898ae329ec7ef978b4e7263c6f41b28f2503 Mon Sep 17 00:00:00 2001 From: notomo Date: Thu, 29 Feb 2024 01:36:28 +0900 Subject: fix(lsp): correct the error message's cmd on spawning (#27632) --- runtime/lua/vim/lsp/rpc.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 1455ab51fa..e52c06a1bd 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -819,7 +819,8 @@ function M.start(cmd, dispatchers, extra_spawn_params) else sfx = string.format(' with error message: %s', err) end - local msg = string.format('Spawning language server with cmd: `%s` failed%s', cmd, sfx) + local msg = + string.format('Spawning language server with cmd: `%s` failed%s', vim.inspect(cmd), sfx) vim.notify(msg, vim.log.levels.WARN) return nil end -- cgit From d981670bc9acd4cfd7b0768b8bc64390b026bf98 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 25 Feb 2024 12:05:35 -0800 Subject: refactor(lsp): remove outdated comment --- runtime/lua/vim/lsp/protocol.lua | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index fb41311961..4a5ab1a73d 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -2,24 +2,6 @@ -- Protocol for the Microsoft Language Server Protocol (mslsp) ---[=[ ----@private ---- Useful for interfacing with: ---- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md -function transform_schema_comments() - nvim.command [[silent! '<,'>g/\/\*\*\|\*\/\|^$/d]] - nvim.command [[silent! '<,'>s/^\(\s*\) \* \=\(.*\)/\1--\2/]] -end ----@private -function transform_schema_to_table() - transform_schema_comments() - nvim.command [[silent! '<,'>s/: \S\+//]] - nvim.command [[silent! '<,'>s/export const //]] - nvim.command [[silent! '<,'>s/export namespace \(\S*\)\s*{/protocol.\1 = {/]] - nvim.command [[silent! '<,'>s/namespace \(\S*\)\s*{/protocol.\1 = {/]] -end ---]=] - local protocol = { --- @enum lsp.DiagnosticSeverity DiagnosticSeverity = { -- cgit From 853f647da618d2891e4ac513fb96d3c8a42fa131 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 25 Feb 2024 12:45:39 -0800 Subject: fix(lsp): handle reverse lookup in capabilities --- runtime/lua/vim/lsp/protocol.lua | 52 ++++++++++++---------------------------- 1 file changed, 15 insertions(+), 37 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 4a5ab1a73d..fa614780c2 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -1,5 +1,11 @@ --- @diagnostic disable: duplicate-doc-alias +local function get_value_set(t) + return vim.iter.filter(function(i) + return type(i) == 'number' + end, ipairs(t)) +end + -- Protocol for the Microsoft Language Server Protocol (mslsp) local protocol = { @@ -295,6 +301,7 @@ local protocol = { }, } +-- TODO(mariasolos): Remove this reverse lookup. for k, v in pairs(protocol) do local tbl = vim.deepcopy(v, true) vim.tbl_add_reverse_lookup(tbl) @@ -705,7 +712,10 @@ function protocol.make_client_capabilities() codeActionLiteralSupport = { codeActionKind = { valueSet = (function() - local res = vim.tbl_values(protocol.CodeActionKind) + local res = vim.iter.filter(function(value) + -- Filter out the keys that were added by the reverse lookup. + return value:match('^%l') + end, vim.tbl_values(protocol.CodeActionKind)) table.sort(res) return res end)(), @@ -736,15 +746,7 @@ function protocol.make_client_capabilities() documentationFormat = { protocol.MarkupKind.Markdown, protocol.MarkupKind.PlainText }, }, completionItemKind = { - valueSet = (function() - local res = {} - for k in ipairs(protocol.CompletionItemKind) do - if type(k) == 'number' then - table.insert(res, k) - end - end - return res - end)(), + valueSet = get_value_set(protocol.CompletionItemKind), }, completionList = { itemDefaults = { @@ -794,15 +796,7 @@ function protocol.make_client_capabilities() documentSymbol = { dynamicRegistration = false, symbolKind = { - valueSet = (function() - local res = {} - for k in ipairs(protocol.SymbolKind) do - if type(k) == 'number' then - table.insert(res, k) - end - end - return res - end)(), + valueSet = get_value_set(protocol.SymbolKind), }, hierarchicalDocumentSymbolSupport = true, }, @@ -813,15 +807,7 @@ function protocol.make_client_capabilities() publishDiagnostics = { relatedInformation = true, tagSupport = { - valueSet = (function() - local res = {} - for k in ipairs(protocol.DiagnosticTag) do - if type(k) == 'number' then - table.insert(res, k) - end - end - return res - end)(), + valueSet = get_value_set(protocol.DiagnosticTag), }, dataSupport = true, }, @@ -833,15 +819,7 @@ function protocol.make_client_capabilities() symbol = { dynamicRegistration = false, symbolKind = { - valueSet = (function() - local res = {} - for k in ipairs(protocol.SymbolKind) do - if type(k) == 'number' then - table.insert(res, k) - end - end - return res - end)(), + valueSet = get_value_set(protocol.SymbolKind), }, }, configuration = true, -- cgit From 2c8f36a3b0b6e9d8a8c0d0f9cafff9cbf8bcb520 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 29 Feb 2024 10:21:02 +0100 Subject: fix(lsp): use plain loop for non-list-like table of protocol values Fixup for #27628 Closes #27669 --- runtime/lua/vim/lsp/protocol.lua | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index fa614780c2..7016209372 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -1,9 +1,17 @@ --- @diagnostic disable: duplicate-doc-alias +-- TODO(clason) can be simplified after reverse lookup is removed +---@param t table +---@return number[] local function get_value_set(t) - return vim.iter.filter(function(i) - return type(i) == 'number' - end, ipairs(t)) + local result = {} + for _, v in pairs(t) do + if type(v) == 'number' then + table.insert(result, v) + end + end + table.sort(result) + return result end -- Protocol for the Microsoft Language Server Protocol (mslsp) -- cgit From b413f5d048ab8676d5a77d0f2b3c20587a270673 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 2 Mar 2024 02:31:54 +0900 Subject: fix(lsp): rename undofile when renaming (#27684) Problem: After `rename()`, the undo information for the renamed file(s) are lost. Solution: Rename the undofile as well. --- runtime/lua/vim/lsp/util.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index d2a5d9a08e..0553d39851 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -724,6 +724,13 @@ function M.rename(old_fname, new_fname, opts) local ok, err = os.rename(old_fname_full, new_fname) assert(ok, err) + local old_undofile = vim.fn.undofile(old_fname_full) + if uv.fs_stat(old_undofile) ~= nil then + local new_undofile = vim.fn.undofile(new_fname) + vim.fn.mkdir(assert(vim.fs.dirname(new_undofile)), 'p') + os.rename(old_undofile, new_undofile) + end + if vim.fn.isdirectory(new_fname) == 0 then local newbuf = vim.fn.bufadd(new_fname) if win then -- cgit From b87505e11656163ddf0dbbc16b7d224815873964 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 7 Feb 2024 11:24:44 +0000 Subject: refactor(watch): general tidy up - Rename watch.poll to watch.watchdirs - Unify how include and exclude is applied - Improve type hints --- runtime/lua/vim/lsp/_watchfiles.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua index 6ca60b78cd..220052be5f 100644 --- a/runtime/lua/vim/lsp/_watchfiles.lua +++ b/runtime/lua/vim/lsp/_watchfiles.lua @@ -7,7 +7,11 @@ local lpeg = vim.lpeg local M = {} -M._watchfunc = (vim.fn.has('win32') == 1 or vim.fn.has('mac') == 1) and watch.watch or watch.poll +if vim.fn.has('win32') == 1 or vim.fn.has('mac') == 1 then + M._watchfunc = watch.watch +else + M._watchfunc = watch.watchdirs +end ---@type table> client id -> registration id -> cancel function local cancels = vim.defaulttable() @@ -164,3 +168,4 @@ function M.unregister(unreg, ctx) end return M + -- cgit From 816b56f878f0291c00a9018d5057b7b2b00f1891 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 7 Feb 2024 13:05:33 +0000 Subject: fix(lsp): cancel watchers when closing a client --- runtime/lua/vim/lsp/_watchfiles.lua | 9 +++++++++ runtime/lua/vim/lsp/client.lua | 1 + 2 files changed, 10 insertions(+) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua index 220052be5f..c66a76feae 100644 --- a/runtime/lua/vim/lsp/_watchfiles.lua +++ b/runtime/lua/vim/lsp/_watchfiles.lua @@ -167,5 +167,14 @@ function M.unregister(unreg, ctx) end end +--- @param client_id integer +function M.cancel(client_id) + for _, reg_cancels in pairs(cancels[client_id]) do + for _, cancel in pairs(reg_cancels) do + cancel() + end + end +end + return M diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index c1b41a7183..1e709a1992 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -727,6 +727,7 @@ function Client:_stop(force) rpc.terminate() self._graceful_shutdown_failed = true end + vim.lsp._watchfiles.cancel(self.id) end) end -- cgit From 4ff3217bbd8747d2d44680a825ac29097faf9c4b Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 7 Feb 2024 11:28:35 +0000 Subject: feat(lsp): add fswatch watchfunc backend Problem: vim._watch.watchdirs has terrible performance. Solution: - On linux use fswatch as a watcher backend if available. - Add File watcher section to health:vim.lsp. Warn if watchfunc is libuv-poll. --- runtime/lua/vim/lsp/_watchfiles.lua | 3 ++- runtime/lua/vim/lsp/health.lua | 40 ++++++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua index c66a76feae..49328fbe9b 100644 --- a/runtime/lua/vim/lsp/_watchfiles.lua +++ b/runtime/lua/vim/lsp/_watchfiles.lua @@ -9,6 +9,8 @@ local M = {} if vim.fn.has('win32') == 1 or vim.fn.has('mac') == 1 then M._watchfunc = watch.watch +elseif vim.fn.executable('fswatch') == 1 then + M._watchfunc = watch.fswatch else M._watchfunc = watch.watchdirs end @@ -177,4 +179,3 @@ function M.cancel(client_id) end return M - diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index 15e4555b55..797a1097f9 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -1,10 +1,9 @@ local M = {} ---- Performs a healthcheck for LSP -function M.check() - local report_info = vim.health.info - local report_warn = vim.health.warn +local report_info = vim.health.info +local report_warn = vim.health.warn +local function check_log() local log = vim.lsp.log local current_log_level = log.get_level() local log_level_string = log.levels[current_log_level] ---@type string @@ -27,9 +26,11 @@ function M.check() local report_fn = (log_size / 1000000 > 100 and report_warn or report_info) report_fn(string.format('Log size: %d KB', log_size / 1000)) +end - local clients = vim.lsp.get_clients() +local function check_active_clients() vim.health.start('vim.lsp: Active Clients') + local clients = vim.lsp.get_clients() if next(clients) then for _, client in pairs(clients) do local attached_to = table.concat(vim.tbl_keys(client.attached_buffers or {}), ',') @@ -48,4 +49,33 @@ function M.check() end end +local function check_watcher() + vim.health.start('vim.lsp: File watcher') + local watchfunc = vim.lsp._watchfiles._watchfunc + assert(watchfunc) + local watchfunc_name --- @type string + if watchfunc == vim._watch.watch then + watchfunc_name = 'libuv-watch' + elseif watchfunc == vim._watch.watchdirs then + watchfunc_name = 'libuv-watchdirs' + elseif watchfunc == vim._watch.fswatch then + watchfunc_name = 'fswatch' + else + local nm = debug.getinfo(watchfunc, 'S').source + watchfunc_name = string.format('Custom (%s)', nm) + end + + report_info('File watch backend: ' .. watchfunc_name) + if watchfunc_name == 'libuv-watchdirs' then + report_warn('libuv-watchdirs has known performance issues. Consider installing fswatch.') + end +end + +--- Performs a healthcheck for LSP +function M.check() + check_log() + check_active_clients() + check_watcher() +end + return M -- cgit From a5fe8f59d98398d04bed8586cee73864bbcdde92 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 27 Feb 2024 15:20:32 +0000 Subject: docs: improve/add documentation of Lua types - Added `@inlinedoc` so single use Lua types can be inlined into the functions docs. E.g. ```lua --- @class myopts --- @inlinedoc --- --- Documentation for some field --- @field somefield integer --- @param opts myOpts function foo(opts) end ``` Will be rendered as ``` foo(opts) Parameters: - {opts} (table) Object with the fields: - somefield (integer) Documentation for some field ``` - Marked many classes with with `@nodoc` or `(private)`. We can eventually introduce these when we want to. --- runtime/lua/vim/lsp/_changetracking.lua | 12 +- runtime/lua/vim/lsp/buf.lua | 251 ++++++++++++++++++-------------- runtime/lua/vim/lsp/client.lua | 123 +++++++++++++--- runtime/lua/vim/lsp/codelens.lua | 6 +- runtime/lua/vim/lsp/diagnostic.lua | 2 +- runtime/lua/vim/lsp/handlers.lua | 1 + runtime/lua/vim/lsp/inlay_hint.lua | 24 ++- runtime/lua/vim/lsp/rpc.lua | 40 ++--- runtime/lua/vim/lsp/semantic_tokens.lua | 26 ++-- runtime/lua/vim/lsp/util.lua | 91 ++++++++---- 10 files changed, 357 insertions(+), 219 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_changetracking.lua b/runtime/lua/vim/lsp/_changetracking.lua index 3ecdec1659..b2be53269f 100644 --- a/runtime/lua/vim/lsp/_changetracking.lua +++ b/runtime/lua/vim/lsp/_changetracking.lua @@ -61,7 +61,7 @@ local state_by_group = setmetatable({}, { end, }) ----@param client lsp.Client +---@param client vim.lsp.Client ---@return vim.lsp.CTGroup local function get_group(client) local allow_inc_sync = vim.F.if_nil(client.flags.allow_incremental_sync, true) --- @type boolean @@ -127,7 +127,7 @@ local function incremental_changes(state, encoding, bufnr, firstline, lastline, return incremental_change end ----@param client lsp.Client +---@param client vim.lsp.Client ---@param bufnr integer function M.init(client, bufnr) assert(client.offset_encoding, 'lsp client must have an offset_encoding') @@ -165,7 +165,7 @@ function M.init(client, bufnr) end end ---- @param client lsp.Client +--- @param client vim.lsp.Client --- @param bufnr integer --- @param name string --- @return string @@ -189,7 +189,7 @@ local function reset_timer(buf_state) end end ---- @param client lsp.Client +--- @param client vim.lsp.Client --- @param bufnr integer function M.reset_buf(client, bufnr) M.flush(client, bufnr) @@ -207,7 +207,7 @@ function M.reset_buf(client, bufnr) end end ---- @param client lsp.Client +--- @param client vim.lsp.Client function M.reset(client) local state = state_by_group[get_group(client)] if not state then @@ -350,7 +350,7 @@ function M.send_changes(bufnr, firstline, lastline, new_lastline) end --- Flushes any outstanding change notification. ----@param client lsp.Client +---@param client vim.lsp.Client ---@param bufnr? integer function M.flush(client, bufnr) local group = get_group(client) diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index d2e92de083..377c8680c7 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -11,7 +11,7 @@ local M = {} --- ---@param method (string) LSP method name ---@param params (table|nil) Parameters to send to the server ----@param handler (function|nil) See |lsp-handler|. Follows |lsp-handler-resolution| +---@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. @@ -31,7 +31,7 @@ end --- Checks whether the language servers attached to the current buffer are --- ready. --- ----@return boolean if server responds. +---@return boolean : if server responds. ---@deprecated function M.server_ready() vim.deprecate('vim.lsp.buf.server_ready()', nil, '0.10') @@ -57,35 +57,57 @@ local function request_with_options(name, params, options) request(name, params, req_handler) end ---- Jumps to the declaration of the symbol under the cursor. ----@note Many servers do not implement this method. Generally, see |vim.lsp.buf.definition()| instead. +--- @class vim.lsp.ListOpts +--- +--- list-handler replacing the default handler. +--- Called for any non-empty result. +--- This table can be used with |setqflist()| or |setloclist()|. E.g.: +--- ```lua +--- local function on_list(options) +--- vim.fn.setqflist({}, ' ', options) +--- vim.cmd.cfirst() +--- end --- ----@param options table|nil additional options ---- - reuse_win: (boolean) Jump to existing window if buffer is already open. ---- - on_list: (function) |lsp-on-list-handler| replacing the default handler. ---- Called for any non-empty result. +--- vim.lsp.buf.definition({ on_list = on_list }) +--- vim.lsp.buf.references(nil, { on_list = on_list }) +--- ``` +--- +--- If you prefer loclist do something like this: +--- ```lua +--- local function on_list(options) +--- vim.fn.setloclist(0, {}, ' ', options) +--- vim.cmd.lopen() +--- end +--- ``` +--- @field on_list? fun(t: vim.lsp.LocationOpts.OnList) + +--- @class vim.lsp.LocationOpts.OnList +--- @field items table[] Structured like |setqflist-what| +--- @field title? string Title for the list. +--- @field context? table `ctx` from |lsp-handler| + +--- @class vim.lsp.LocationOpts: vim.lsp.ListOpts +--- +--- Jump to existing window if buffer is already open. +--- @field reuse_win? boolean + +--- Jumps to the declaration of the symbol under the cursor. +--- @note Many servers do not implement this method. Generally, see |vim.lsp.buf.definition()| instead. +--- @param options? vim.lsp.LocationOpts function M.declaration(options) local params = util.make_position_params() request_with_options(ms.textDocument_declaration, params, options) end --- Jumps to the definition of the symbol under the cursor. ---- ----@param options table|nil additional options ---- - reuse_win: (boolean) Jump to existing window if buffer is already open. ---- - on_list: (function) |lsp-on-list-handler| replacing the default handler. ---- Called for any non-empty result. +--- @param options? vim.lsp.LocationOpts function M.definition(options) local params = util.make_position_params() request_with_options(ms.textDocument_definition, params, options) end --- Jumps to the definition of the type of the symbol under the cursor. ---- ----@param options table|nil additional options ---- - reuse_win: (boolean) Jump to existing window if buffer is already open. ---- - on_list: (function) |lsp-on-list-handler| replacing the default handler. ---- Called for any non-empty result. +--- @param options? vim.lsp.LocationOpts function M.type_definition(options) local params = util.make_position_params() request_with_options(ms.textDocument_typeDefinition, params, options) @@ -93,10 +115,7 @@ end --- Lists all the implementations for the symbol under the cursor in the --- quickfix window. ---- ----@param options table|nil additional options ---- - on_list: (function) |lsp-on-list-handler| replacing the default handler. ---- Called for any non-empty result. +--- @param options? vim.lsp.LocationOpts function M.implementation(options) local params = util.make_position_params() request_with_options(ms.textDocument_implementation, params, options) @@ -156,45 +175,55 @@ local function range_from_selection(bufnr, mode) } end +--- @class vim.lsp.buf.format.Opts +--- @inlinedoc +--- +--- Can be used to specify FormattingOptions. Some unspecified options will be +--- automatically derived from the current Nvim options. +--- See https://microsoft.github.io/language-server-protocol/specification/#formattingOptions +--- @field formatting_options? table +--- +--- Time in milliseconds to block for formatting requests. No effect if async=true. +--- (default: `1000`) +--- @field timeout_ms? integer +--- +--- Restrict formatting to the clients attached to the given buffer. +--- (default: current buffer) +--- @field bufnr? integer +--- +--- Predicate used to filter clients. Receives a client as argument and must +--- return a boolean. Clients matching the predicate are included. Example: +--- ```lua +--- -- Never request typescript-language-server for formatting +--- vim.lsp.buf.format { +--- filter = function(client) return client.name ~= "tsserver" end +--- } +--- ``` +--- @field filter? fun(client: vim.lsp.Client): boolean? +--- +--- If true the method won't block. +--- Editing the buffer while formatting asynchronous can lead to unexpected +--- changes. +--- (Default: false) +--- @field async? boolean +--- +--- Restrict formatting to the client with ID (client.id) matching this field. +--- @field id? integer +--- +--- Restrict formatting to the client with name (client.name) matching this field. +--- @field name? string +--- +--- Range to format. +--- Table must contain `start` and `end` keys with {row,col} tuples using +--- (1,0) indexing. +--- (Default: current selection in visual mode, `nil` in other modes, +--- formatting the full buffer) +--- @field range? {start:integer[],end:integer[]} + --- Formats a buffer using the attached (and optionally filtered) language --- server clients. --- ---- @param options table|nil Optional table which holds the following optional fields: ---- - formatting_options (table|nil): ---- Can be used to specify FormattingOptions. Some unspecified options will be ---- automatically derived from the current Nvim options. ---- See https://microsoft.github.io/language-server-protocol/specification/#formattingOptions ---- - timeout_ms (integer|nil, default 1000): ---- Time in milliseconds to block for formatting requests. No effect if async=true ---- - bufnr (number|nil): ---- Restrict formatting to the clients attached to the given buffer, defaults to the current ---- buffer (0). ---- ---- - filter (function|nil): ---- Predicate used to filter clients. Receives a client as argument and must return a ---- boolean. Clients matching the predicate are included. Example: ---- ```lua ---- -- Never request typescript-language-server for formatting ---- vim.lsp.buf.format { ---- filter = function(client) return client.name ~= "tsserver" end ---- } ---- ``` ---- ---- - async boolean|nil ---- If true the method won't block. Defaults to false. ---- Editing the buffer while formatting asynchronous can lead to unexpected ---- changes. ---- ---- - id (number|nil): ---- Restrict formatting to the client with ID (client.id) matching this field. ---- - name (string|nil): ---- Restrict formatting to the client with name (client.name) matching this field. ---- ---- - range (table|nil) Range to format. ---- Table must contain `start` and `end` keys with {row,col} tuples using ---- (1,0) indexing. ---- Defaults to current selection in visual mode ---- Defaults to `nil` in other modes, formatting the full buffer +--- @param options? vim.lsp.buf.format.Opts function M.format(options) options = options or {} local bufnr = options.bufnr or api.nvim_get_current_buf() @@ -229,8 +258,7 @@ function M.format(options) end if options.async then - local do_format - do_format = function(idx, client) + local function do_format(idx, client) if not client then return end @@ -256,17 +284,22 @@ function M.format(options) end end +--- @class vim.lsp.buf.rename.Opts +--- @inlinedoc +--- +--- Predicate used to filter clients. Receives a client as argument and +--- must return a boolean. Clients matching the predicate are included. +--- @field filter? fun(client: vim.lsp.Client): boolean? +--- +--- Restrict clients used for rename to ones where client.name matches +--- this field. +--- @field name? string + --- Renames all references to the symbol under the cursor. --- ---@param new_name string|nil If not provided, the user will be prompted for a new --- name using |vim.ui.input()|. ----@param options table|nil additional options ---- - filter (function|nil): ---- Predicate used to filter clients. Receives a client as argument and ---- must return a boolean. Clients matching the predicate are included. ---- - name (string|nil): ---- Restrict clients used for rename to ones where client.name matches ---- this field. +---@param options? vim.lsp.buf.rename.Opts Additional options: function M.rename(new_name, options) options = options or {} local bufnr = options.bufnr or api.nvim_get_current_buf() @@ -386,8 +419,7 @@ end --- ---@param context (table|nil) Context for the request ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references ----@param options table|nil additional options ---- - on_list: (function) handler for list results. See |lsp-on-list-handler| +---@param options? vim.lsp.ListOpts function M.references(context, options) validate({ context = { context, 't', true } }) local params = util.make_position_params() @@ -398,14 +430,13 @@ function M.references(context, options) end --- Lists all symbols in the current buffer in the quickfix window. ---- ----@param options table|nil additional options ---- - on_list: (function) handler for list results. See |lsp-on-list-handler| +--- @param options? vim.lsp.ListOpts function M.document_symbol(options) local params = { textDocument = util.make_text_document_params() } request_with_options(ms.textDocument_documentSymbol, params, options) end +--- @param call_hierarchy_items lsp.CallHierarchyItem[]? local function pick_call_hierarchy_item(call_hierarchy_items) if not call_hierarchy_items then return @@ -425,8 +456,10 @@ local function pick_call_hierarchy_item(call_hierarchy_items) return choice end +--- @param method string local function call_hierarchy(method) local params = util.make_position_params() + --- @param result lsp.CallHierarchyItem[]? request(ms.textDocument_prepareCallHierarchy, params, function(err, result, ctx) if err then vim.notify(err.message, vim.log.levels.WARN) @@ -545,9 +578,8 @@ end --- call, the user is prompted to enter a string on the command line. An empty --- string means no filtering is done. --- ----@param query string|nil optional ----@param options table|nil additional options ---- - on_list: (function) handler for list results. See |lsp-on-list-handler| +--- @param query string? optional +--- @param options? vim.lsp.ListOpts function M.workspace_symbol(query, options) query = query or npcall(vim.fn.input, 'Query: ') if query == nil then @@ -582,16 +614,36 @@ function M.clear_references() util.buf_clear_references() end +---@nodoc ---@class vim.lsp.CodeActionResultEntry ---@field error? lsp.ResponseError ---@field result? (lsp.Command|lsp.CodeAction)[] ---@field ctx lsp.HandlerContext ----@class vim.lsp.buf.code_action.opts ----@field context? lsp.CodeActionContext ----@field filter? fun(x: lsp.CodeAction|lsp.Command):boolean ----@field apply? boolean ----@field range? {start: integer[], end: integer[]} +--- @class vim.lsp.buf.code_action.Opts +--- @inlinedoc +--- +--- Corresponds to `CodeActionContext` of the LSP specification: +--- - {diagnostics}? (`table`) LSP `Diagnostic[]`. Inferred from the current +--- position if not provided. +--- - {only}? (`table`) List of LSP `CodeActionKind`s used to filter the code actions. +--- Most language servers support values like `refactor` +--- or `quickfix`. +--- - {triggerKind}? (`integer`) The reason why code actions were requested. +--- @field context? lsp.CodeActionContext +--- +--- Predicate taking an `CodeAction` and returning a boolean. +--- @field filter? fun(x: lsp.CodeAction|lsp.Command):boolean +--- +--- When set to `true`, and there is just one remaining action +--- (after filtering), the action is applied without user query. +--- @field apply? boolean +--- +--- Range for which code actions should be requested. +--- If in visual mode this defaults to the active selection. +--- Table must contain `start` and `end` keys with {row,col} tuples +--- using mark-like indexing. See |api-indexing| +--- @field range? {start: integer[], end: integer[]} --- This is not public because the main extension point is --- vim.ui.select which can be overridden independently. @@ -602,7 +654,7 @@ end --- need to be able to link a `CodeAction|Command` to the right client for --- `codeAction/resolve` ---@param results table ----@param opts? vim.lsp.buf.code_action.opts +---@param opts? vim.lsp.buf.code_action.Opts local function on_code_action_results(results, opts) ---@param a lsp.Command|lsp.CodeAction local function action_filter(a) @@ -647,14 +699,15 @@ local function on_code_action_results(results, opts) end ---@param action lsp.Command|lsp.CodeAction - ---@param client lsp.Client + ---@param client vim.lsp.Client ---@param ctx lsp.HandlerContext local function apply_action(action, client, ctx) if action.edit then 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 + local a_cmd = action.command + if a_cmd then + local command = type(a_cmd) == 'table' and a_cmd or action client:_exec_cmd(command, ctx) end end @@ -676,7 +729,6 @@ local function on_code_action_results(results, opts) -- command: string -- arguments?: any[] -- - ---@type lsp.Client local client = assert(vim.lsp.get_client_by_id(choice.ctx.client_id)) local action = choice.action local bufnr = assert(choice.ctx.bufnr, 'Must have buffer number') @@ -726,29 +778,7 @@ end --- Selects a code action available at the current --- cursor position. --- ----@param options table|nil Optional table which holds the following optional fields: ---- - context: (table|nil) ---- Corresponds to `CodeActionContext` of the LSP specification: ---- - diagnostics (table|nil): ---- LSP `Diagnostic[]`. Inferred from the current ---- position if not provided. ---- - only (table|nil): ---- List of LSP `CodeActionKind`s used to filter the code actions. ---- Most language servers support values like `refactor` ---- or `quickfix`. ---- - triggerKind (number|nil): The reason why code actions were requested. ---- - filter: (function|nil) ---- Predicate taking an `CodeAction` and returning a boolean. ---- - apply: (boolean|nil) ---- When set to `true`, and there is just one remaining action ---- (after filtering), the action is applied without user query. ---- ---- - range: (table|nil) ---- Range for which code actions should be requested. ---- If in visual mode this defaults to the active selection. ---- Table must contain `start` and `end` keys with {row,col} tuples ---- using mark-like indexing. See |api-indexing| ---- +---@param options? vim.lsp.buf.code_action.Opts ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction ---@see vim.lsp.protocol.CodeActionTriggerKind function M.code_action(options) @@ -814,9 +844,8 @@ function M.code_action(options) end --- Executes an LSP server command. ---- ----@param command_params table A valid `ExecuteCommandParams` object ----@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand +--- @param command_params lsp.ExecuteCommandParams +--- @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand function M.execute_command(command_params) validate({ command = { command_params.command, 's' }, diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index c1b41a7183..fcbaadbc57 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -6,38 +6,125 @@ local ms = lsp.protocol.Methods local changetracking = lsp._changetracking local validate = vim.validate ---- @alias vim.lsp.client.on_init_cb fun(client: lsp.Client, initialize_result: lsp.InitializeResult) ---- @alias vim.lsp.client.on_attach_cb fun(client: lsp.Client, bufnr: integer) +--- @alias vim.lsp.client.on_init_cb fun(client: vim.lsp.Client, initialize_result: lsp.InitializeResult) +--- @alias vim.lsp.client.on_attach_cb fun(client: vim.lsp.Client, bufnr: integer) --- @alias vim.lsp.client.on_exit_cb fun(code: integer, signal: integer, client_id: integer) ---- @alias vim.lsp.client.before_init_cb fun(params: lsp.InitializeParams, config: lsp.ClientConfig) - ---- @class lsp.ClientConfig +--- @alias vim.lsp.client.before_init_cb fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig) + +--- @class vim.lsp.ClientConfig +--- command string[] that launches the language +--- server (treated as in |jobstart()|, must be absolute or on `$PATH`, shell constructs like +--- "~" are not expanded), or function that creates an RPC client. Function receives +--- a `dispatchers` table and returns a table with member functions `request`, `notify`, +--- `is_closing` and `terminate`. +--- See |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|. +--- For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()| --- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient? +--- +--- Directory to launch the `cmd` process. Not related to `root_dir`. +--- (default: cwd) --- @field cmd_cwd? string +--- +--- Environment flags to pass to the LSP on spawn. +--- Must be specified using a table. +--- Non-string values are coerced to string. +--- Example: +--- ```lua +--- { PORT = 8080; HOST = "0.0.0.0"; } +--- ``` --- @field cmd_env? table +--- +--- Daemonize the server process so that it runs in a separate process group from Nvim. +--- Nvim will shutdown the process on exit, but if Nvim fails to exit cleanly this could leave +--- behind orphaned server processes. +--- (default: true) --- @field detached? boolean +--- +--- List of workspace folders passed to the language server. +--- For backwards compatibility rootUri and rootPath will be derived from the first workspace +--- folder in this list. See `workspaceFolders` in the LSP spec. --- @field workspace_folders? lsp.WorkspaceFolder[] +--- +--- Map overriding the default capabilities defined by |vim.lsp.protocol.make_client_capabilities()|, +--- passed to the language server on initialization. Hint: use make_client_capabilities() and modify +--- its result. +--- - Note: To send an empty dictionary use |vim.empty_dict()|, else it will be encoded as an +--- array. --- @field capabilities? lsp.ClientCapabilities +--- +--- Map of language server method names to |lsp-handler| --- @field handlers? table +--- +--- Map with language server specific settings. These are returned to the language server if +--- requested via `workspace/configuration`. Keys are case-sensitive. --- @field settings? table +--- +--- Table that maps string of clientside commands to user-defined functions. +--- Commands passed to start_client take precedence over the global command registry. Each key +--- must be a unique command name, and the value is a function which is called if any LSP action +--- (code action, code lenses, ...) triggers the command. --- @field commands? table +--- +--- Values to pass in the initialization request as `initializationOptions`. See `initialize` in +--- the LSP spec. --- @field init_options? table +--- +--- Name in log messages. +--- (default: client-id) --- @field name? string +--- +--- Language ID as string. Defaults to the filetype. --- @field get_language_id? fun(bufnr: integer, filetype: string): string ---- @field offset_encoding? string +--- +--- The encoding that the LSP server expects. Client does not verify this is correct. +--- @field offset_encoding? 'utf-8'|'utf-16'|'utf-32' +--- +--- Callback invoked when the client operation throws an error. `code` is a number describing the error. +--- Other arguments may be passed depending on the error kind. See `vim.lsp.rpc.client_errors` +--- for possible errors. Use `vim.lsp.rpc.client_errors[code]` to get human-friendly name. --- @field on_error? fun(code: integer, err: string) +--- +--- Callback invoked before the LSP "initialize" phase, where `params` contains the parameters +--- being sent to the server and `config` is the config that was passed to |vim.lsp.start_client()|. +--- You can use this to modify parameters before they are sent. --- @field before_init? vim.lsp.client.before_init_cb +--- +--- Callback invoked after LSP "initialize", where `result` is a table of `capabilities` +--- and anything else the server may send. For example, clangd sends +--- `initialize_result.offsetEncoding` if `capabilities.offsetEncoding` was sent to it. +--- You can only modify the `client.offset_encoding` here before any notifications are sent. --- @field on_init? elem_or_list +--- +--- Callback invoked on client exit. +--- - code: exit code of the process +--- - signal: number describing the signal used to terminate (if any) +--- - client_id: client handle --- @field on_exit? elem_or_list +--- +--- Callback invoked when client attaches to a buffer. --- @field on_attach? elem_or_list +--- +--- Passed directly to the language server in the initialize request. Invalid/empty values will +--- (default: "off") --- @field trace? 'off'|'messages'|'verbose' +--- +--- A table with flags for the client. The current (experimental) flags are: +--- - allow_incremental_sync (bool, default true): Allow using incremental sync for buffer edits +--- - debounce_text_changes (number, default 150): Debounce didChange +--- notifications to the server by the given number in milliseconds. No debounce +--- occurs if nil +--- - exit_timeout (number|boolean, default false): Milliseconds to wait for server to +--- exit cleanly after sending the "shutdown" request before sending kill -15. +--- If set to false, nvim exits immediately after sending the "shutdown" request to the server. --- @field flags? table +--- +--- Directory where the LSP server will base its workspaceFolders, rootUri, and rootPath on initialization. --- @field root_dir? string ---- @class lsp.Client.Progress: vim.Ringbuf<{token: integer|string, value: any}> +--- @class vim.lsp.Client.Progress: vim.Ringbuf<{token: integer|string, value: any}> --- @field pending table ---- @class lsp.Client +--- @class vim.lsp.Client --- --- The id allocated to the client. --- @field id integer @@ -67,7 +154,7 @@ local validate = vim.validate --- --- copy of the table that was passed by the user --- to |vim.lsp.start_client()|. ---- @field config lsp.ClientConfig +--- @field config vim.lsp.ClientConfig --- --- Response from the server sent on --- initialize` describing the server's capabilities. @@ -75,7 +162,7 @@ local validate = vim.validate --- --- A ring buffer (|vim.ringbuf()|) containing progress messages --- sent by the server. ---- @field progress lsp.Client.Progress +--- @field progress vim.lsp.Client.Progress --- --- @field initialized true? --- @@ -239,7 +326,7 @@ local function default_get_language_id(_bufnr, filetype) end --- Validates a client configuration as given to |vim.lsp.start_client()|. ---- @param config lsp.ClientConfig +--- @param config vim.lsp.ClientConfig local function validate_config(config) validate({ config = { config, 't' }, @@ -285,7 +372,7 @@ local function get_trace(trace) end --- @param id integer ---- @param config lsp.ClientConfig +--- @param config vim.lsp.ClientConfig --- @return string local function get_name(id, config) local name = config.name @@ -328,8 +415,8 @@ local function ensure_list(x) end --- @package ---- @param config lsp.ClientConfig ---- @return lsp.Client? +--- @param config vim.lsp.ClientConfig +--- @return vim.lsp.Client? function Client.create(config) validate_config(config) @@ -337,7 +424,7 @@ function Client.create(config) local id = client_index local name = get_name(id, config) - --- @class lsp.Client + --- @class vim.lsp.Client local self = { id = id, config = config, @@ -370,7 +457,7 @@ function Client.create(config) --- - lsp.WorkDoneProgressBegin, --- - lsp.WorkDoneProgressReport (extended with title from Begin) --- - lsp.WorkDoneProgressEnd (extended with title from Begin) - progress = vim.ringbuf(50) --[[@as lsp.Client.Progress]], + progress = vim.ringbuf(50) --[[@as vim.lsp.Client.Progress]], --- @deprecated use client.progress instead messages = { name = name, messages = {}, progress = {}, status = {} }, @@ -421,6 +508,7 @@ function Client.create(config) return self end +--- @private --- @param cbs function[] --- @param error_id integer --- @param ... any @@ -698,7 +786,7 @@ function Client:_cancel_request(id) return self.rpc.notify(ms.dollar_cancelRequest, { id = id }) end ---- @nodoc +--- @private --- Stops a client, optionally with force. --- --- By default, it will just ask the - server to shutdown without force. If @@ -853,6 +941,7 @@ function Client:write_error(code, err) err_message(self._log_prefix, ': Error ', client_error, ': ', vim.inspect(err)) end +--- @private --- @param method string --- @param opts? {bufnr: integer?} function Client:_supports_method(method, opts) diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index 7aed6f99e3..48c096c0c1 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -279,7 +279,8 @@ function M.on_codelens(err, result, ctx, _) end) end ---- @class vim.lsp.codelens.RefreshOptions +--- @class vim.lsp.codelens.refresh.Opts +--- @inlinedoc --- @field bufnr integer? filter by buffer. All buffers if nil, 0 for current buffer --- Refresh the lenses. @@ -292,8 +293,7 @@ end --- autocmd BufEnter,CursorHold,InsertLeave lua vim.lsp.codelens.refresh({ bufnr = 0 }) --- ``` --- ---- @param opts? vim.lsp.codelens.RefreshOptions Table with the following fields: ---- - `bufnr` (integer|nil): filter by buffer. All buffers if nil, 0 for current buffer +--- @param opts? vim.lsp.codelens.refresh.Opts Optional fields function M.refresh(opts) opts = opts or {} local bufnr = opts.bufnr and resolve_bufnr(opts.bufnr) diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 1fa67fc473..6156821093 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -390,7 +390,7 @@ local function clear(bufnr) end end ----@class lsp.diagnostic.bufstate +---@class (private) lsp.diagnostic.bufstate ---@field enabled boolean Whether inlay hints are enabled for this buffer ---@type table local bufstates = {} diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 781d720486..d816fb1482 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -412,6 +412,7 @@ M[ms.textDocument_hover] = M.hover ---@param _ nil not used ---@param result (table) result of LSP method; a location or a list of locations. ---@param ctx (lsp.HandlerContext) table containing the context of the request, including the method +---@param config? vim.lsp.buf.LocationOpts ---(`textDocument/definition` can return `Location` or `Location[]` local function location_handler(_, result, ctx, config) if result == nil or vim.tbl_isempty(result) then diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index 49dc35fdf6..ec676ea97f 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -4,12 +4,12 @@ local ms = require('vim.lsp.protocol').Methods local api = vim.api local M = {} ----@class lsp.inlay_hint.bufstate +---@class (private) vim.lsp.inlay_hint.bufstate ---@field version? integer ---@field client_hints? table> client_id -> (lnum -> hints) ---@field applied table Last version of hints applied to this line ---@field enabled boolean Whether inlay hints are enabled for this buffer ----@type table +---@type table local bufstates = {} local namespace = api.nvim_create_namespace('vim_lsp_inlayhint') @@ -103,11 +103,14 @@ function M.on_refresh(err, _, ctx, _) return vim.NIL end ---- @class vim.lsp.inlay_hint.get.filter +--- Optional filters |kwargs|: +--- @class vim.lsp.inlay_hint.get.Filter +--- @inlinedoc --- @field bufnr integer? --- @field range lsp.Range? ---- + --- @class vim.lsp.inlay_hint.get.ret +--- @inlinedoc --- @field bufnr integer --- @field client_id integer --- @field inlay_hint lsp.InlayHint @@ -130,17 +133,8 @@ end --- }) --- ``` --- ---- @param filter vim.lsp.inlay_hint.get.filter? ---- Optional filters |kwargs|: ---- - bufnr (integer?): 0 for current buffer ---- - range (lsp.Range?) ---- +--- @param filter vim.lsp.inlay_hint.get.Filter? --- @return vim.lsp.inlay_hint.get.ret[] ---- Each list item is a table with the following fields: ---- - bufnr (integer) ---- - client_id (integer) ---- - inlay_hint (lsp.InlayHint) ---- --- @since 12 function M.get(filter) vim.validate({ filter = { filter, 'table', true } }) @@ -241,7 +235,7 @@ end --- Refresh inlay hints, only if we have attached clients that support it ---@param bufnr (integer) Buffer handle, or 0 for current ----@param opts? lsp.util.RefreshOptions Additional options to pass to util._refresh +---@param opts? vim.lsp.util._refresh.Opts Additional options to pass to util._refresh ---@private local function _refresh(bufnr, opts) opts = opts or {} diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index e52c06a1bd..8e014b1063 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -26,7 +26,7 @@ local function format_message_with_content_length(message) }) end ----@class vim.lsp.rpc.Headers: {string: any} +---@class (private) vim.lsp.rpc.Headers: {string: any} ---@field content_length integer --- Parses an LSP Message's header @@ -193,7 +193,9 @@ function M.rpc_response_error(code, message, data) }) end +--- Dispatchers for LSP message types. --- @class vim.lsp.rpc.Dispatchers +--- @inlinedoc --- @field notification fun(method: string, params: table) --- @field server_request fun(method: string, params: table): any?, lsp.ResponseError? --- @field on_exit fun(code: integer, signal: integer) @@ -266,8 +268,7 @@ function M.create_read_loop(handle_body, on_no_chunk, on_error) end end ----@private ----@class vim.lsp.rpc.Client +---@class (private) vim.lsp.rpc.Client ---@field message_index integer ---@field message_callbacks table dict of message_id to callback ---@field notify_reply_callbacks table dict of message_id to callback @@ -522,7 +523,7 @@ function Client:handle_body(body) end end ----@class vim.lsp.rpc.Transport +---@class (private) vim.lsp.rpc.Transport ---@field write fun(msg: string) ---@field is_closing fun(): boolean ---@field terminate fun() @@ -721,32 +722,21 @@ function M.domain_socket_connect(pipe_path) end end ----@class vim.lsp.rpc.ExtraSpawnParams ----@field cwd? string Working directory for the LSP server process ----@field detached? boolean Detach the LSP server process from the current process ----@field env? table Additional environment variables for LSP server process. See |vim.system| +--- Additional context for the LSP server process. +--- @class vim.lsp.rpc.ExtraSpawnParams +--- @inlinedoc +--- @field cwd? string Working directory for the LSP server process +--- @field detached? boolean Detach the LSP server process from the current process +--- @field env? table Additional environment variables for LSP server process. See |vim.system()| --- Starts an LSP server process and create an LSP RPC client object to --- interact with it. Communication with the spawned process happens via stdio. For --- communication via TCP, spawn a process manually and use |vim.lsp.rpc.connect()| --- ----@param cmd string[] Command to start the LSP server. ---- ----@param dispatchers? vim.lsp.rpc.Dispatchers Dispatchers for LSP message types. ---- Valid dispatcher names are: ---- - `"notification"` ---- - `"server_request"` ---- - `"on_error"` ---- - `"on_exit"` ---- ----@param extra_spawn_params? vim.lsp.rpc.ExtraSpawnParams Additional context for the LSP ---- server process. May contain: ---- - {cwd} (string) Working directory for the LSP server process ---- - {detached?} (boolean) Detach the LSP server process from the current process. ---- Defaults to false on Windows and true otherwise. ---- - {env?} (table) Additional environment variables for LSP server process ---- ----@return vim.lsp.rpc.PublicClient? Client RPC object, with these methods: +--- @param cmd string[] Command to start the LSP server. +--- @param dispatchers? vim.lsp.rpc.Dispatchers +--- @param extra_spawn_params? vim.lsp.rpc.ExtraSpawnParams +--- @return vim.lsp.rpc.PublicClient? : Client RPC object, with these methods: --- - `notify()` |vim.lsp.rpc.notify()| --- - `request()` |vim.lsp.rpc.request()| --- - `is_closing()` returns a boolean indicating if the RPC is closing. diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index fe8638bdfa..92546e8520 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -4,7 +4,7 @@ local ms = require('vim.lsp.protocol').Methods local util = require('vim.lsp.util') local uv = vim.uv ---- @class STTokenRange +--- @class (private) STTokenRange --- @field line integer line number 0-based --- @field start_col integer start column 0-based --- @field end_col integer end column 0-based @@ -12,23 +12,23 @@ local uv = vim.uv --- @field modifiers table token modifiers as a set. E.g., { static = true, readonly = true } --- @field marked boolean whether this token has had extmarks applied --- ---- @class STCurrentResult +--- @class (private) STCurrentResult --- @field version? integer document version associated with this result --- @field result_id? string resultId from the server; used with delta requests --- @field highlights? STTokenRange[] cache of highlight ranges for this document version --- @field tokens? integer[] raw token array as received by the server. used for calculating delta responses --- @field namespace_cleared? boolean whether the namespace was cleared for this result yet --- ---- @class STActiveRequest +--- @class (private) STActiveRequest --- @field request_id? integer the LSP request ID of the most recent request sent to the server --- @field version? integer the document version associated with the most recent request --- ---- @class STClientState +--- @class (private) STClientState --- @field namespace integer --- @field active_request STActiveRequest --- @field current_result STCurrentResult ----@class STHighlighter +---@class (private) STHighlighter ---@field active table ---@field bufnr integer ---@field augroup integer augroup for buffer events @@ -92,7 +92,7 @@ end --- ---@param data integer[] ---@param bufnr integer ----@param client lsp.Client +---@param client vim.lsp.Client ---@param request STActiveRequest ---@return STTokenRange[] local function tokens_to_ranges(data, bufnr, client, request) @@ -646,6 +646,7 @@ function M.stop(bufnr, client_id) end end +--- @nodoc --- @class STTokenRangeInspect : STTokenRange --- @field client_id integer @@ -727,6 +728,13 @@ function M.force_refresh(bufnr) end end +--- @class vim.lsp.semantic_tokens.highlight_token.Opts +--- @inlinedoc +--- +--- Priority for the applied extmark. +--- (Default: `vim.highlight.priorities.semantic_tokens + 3`) +--- @field priority? integer + --- Highlight a semantic token. --- --- Apply an extmark with a given highlight group for a semantic token. The @@ -735,11 +743,9 @@ end --- use inside |LspTokenUpdate| callbacks. ---@param token (table) a semantic token, found as `args.data.token` in |LspTokenUpdate|. ---@param bufnr (integer) the buffer to highlight ----@param client_id (integer) The ID of the |vim.lsp.client| +---@param client_id (integer) The ID of the |vim.lsp.Client| ---@param hl_group (string) Highlight group name ----@param opts (table|nil) Optional parameters. ---- - priority: (integer|nil) Priority for the applied extmark. Defaults ---- to `vim.highlight.priorities.semantic_tokens + 3` +---@param opts? vim.lsp.semantic_tokens.highlight_token.Opts Optional parameters: function M.highlight_token(token, bufnr, client_id, hl_group, opts) local highlighter = STHighlighter.active[bufnr] if not highlighter then diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 0553d39851..60d0f0cc83 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -675,13 +675,15 @@ local function get_bufs_with_prefix(prefix) return buffers end +--- @class vim.lsp.util.rename.Opts +--- @inlinedoc +--- @field overwrite? boolean +--- @field ignoreIfExists? boolean + --- Rename old_fname to new_fname ---- ----@param old_fname string ----@param new_fname string ----@param opts? table options ---- - overwrite? boolean ---- - ignoreIfExists? boolean +--- @param old_fname string +--- @param new_fname string +--- @param opts? vim.lsp.util.rename.Opts Options: function M.rename(old_fname, new_fname, opts) opts = opts or {} local skip = not opts.overwrite or opts.ignoreIfExists @@ -1450,7 +1452,7 @@ function M.stylize_markdown(bufnr, contents, opts) return stripped end ---- @class lsp.util.NormalizeMarkdownOptions +--- @class (private) vim.lsp.util._normalize_markdown.Opts --- @field width integer Thematic breaks are expanded to this size. Defaults to 80. --- Normalizes Markdown input to a canonical form. @@ -1466,7 +1468,7 @@ end --- ---@private ---@param contents string[] ----@param opts? lsp.util.NormalizeMarkdownOptions +---@param opts? vim.lsp.util._normalize_markdown.Opts ---@return string[] table of lines containing normalized Markdown ---@see https://github.github.com/gfm function M._normalize_markdown(contents, opts) @@ -1537,7 +1539,7 @@ local function close_preview_autocmd(events, winnr, bufnrs) end end ----@internal +---@private --- Computes size of float needed to show contents (with optional wrapping) --- ---@param contents table of lines to show in window @@ -1613,24 +1615,50 @@ function M._make_floating_popup_size(contents, opts) return width, height end +--- @class vim.lsp.util.open_floating_preview.Opts +--- @inlinedoc +--- +--- Height of floating window +--- @field height? integer +--- +--- Width of floating window +--- @field width? integer +--- +--- Wrap long lines +--- (default: `true`) +--- @field wrap? boolean +--- +--- Character to wrap at for computing height when wrap is enabled +--- @field wrap_at? integer +--- +--- Maximal width of floating window +--- @field max_width? integer +--- +--- Maximal height of floating window +--- @field max_height? integer +--- +--- If a popup with this id is opened, then focus it +--- @field focus_id? string +--- +--- List of events that closes the floating window +--- @field close_events? table +--- +--- Make float focusable. +--- (default: `true`) +--- @field focusable? boolean +--- +--- If `true`, and if {focusable} is also `true`, focus an existing floating +--- window with the same {focus_id} +--- (default: `true`) +--- @field focus? boolean + --- Shows contents in a floating window. --- ---@param contents table of lines to show in window ---@param syntax string of syntax to set for opened buffer ----@param opts table with optional fields (additional keys are filtered with |vim.lsp.util.make_floating_popup_options()| ---- before they are passed on to |nvim_open_win()|) ---- - height: (integer) height of floating window ---- - width: (integer) width of floating window ---- - wrap: (boolean, default true) wrap long lines ---- - wrap_at: (integer) character to wrap at for computing height when wrap is enabled ---- - max_width: (integer) maximal width of floating window ---- - max_height: (integer) maximal height of floating window ---- - focus_id: (string) if a popup with this id is opened, then focus it ---- - close_events: (table) list of events that closes the floating window ---- - focusable: (boolean, default true) Make float focusable ---- - focus: (boolean, default true) If `true`, and if {focusable} ---- is also `true`, focus an existing floating window with the same ---- {focus_id} +---@param opts? vim.lsp.util.open_floating_preview.Opts with optional fields +--- (additional keys are filtered with |vim.lsp.util.make_floating_popup_options()| +--- before they are passed on to |nvim_open_win()|) ---@return integer bufnr of newly created float window ---@return integer winid of newly created float window preview window function M.open_floating_preview(contents, syntax, opts) @@ -1794,7 +1822,8 @@ local position_sort = sort_by_key(function(v) return { v.start.line, v.start.character } end) ----@class vim.lsp.util.LocationItem +---@class vim.lsp.util.locations_to_items.ret +---@inlinedoc ---@field filename string ---@field lnum integer 1-indexed line number ---@field col integer 1-indexed column @@ -1813,7 +1842,7 @@ end) ---@param locations lsp.Location[]|lsp.LocationLink[] ---@param offset_encoding string offset_encoding for locations utf-8|utf-16|utf-32 --- default to first client of buffer ----@return vim.lsp.util.LocationItem[] list of items +---@return vim.lsp.util.locations_to_items.ret[] function M.locations_to_items(locations, offset_encoding) if offset_encoding == nil then vim.notify_once( @@ -2221,16 +2250,16 @@ local function make_line_range_params(bufnr, start_line, end_line, offset_encodi } end ----@private ---- Request updated LSP information for a buffer. ---- ----@class lsp.util.RefreshOptions +---@class (private) vim.lsp.util._refresh.Opts ---@field bufnr integer? Buffer to refresh (default: 0) ---@field only_visible? boolean Whether to only refresh for the visible regions of the buffer (default: false) ---@field client_id? integer Client ID to refresh (default: all clients) --- + +---@private +--- Request updated LSP information for a buffer. +--- ---@param method string LSP method to call ----@param opts? lsp.util.RefreshOptions Options table +---@param opts? vim.lsp.util._refresh.Opts Options table function M._refresh(method, opts) opts = opts or {} local bufnr = opts.bufnr -- cgit From 39cc38a87b29d61e7e5342bad2e5156446eb8649 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 2 Mar 2024 18:51:10 +0900 Subject: fix(lsp): defer writing error msgs (#27688) Context: Nvim catches errors from the user's `on_exit` and rpc handler callbacks and prints the error message. Problem: Printing the error message uses Nvim api functions. But callbacks mentioned above run in `:h lua-loop-callbacks` where most of `vim.api` is not allowed, so Nvim itself raises error. Solution: `vim.schedule()` the error reporting when necessary. --- runtime/lua/vim/lsp/client.lua | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index dfb5137e2a..0f47c57cd5 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -691,8 +691,16 @@ local wait_result_reason = { [-1] = 'timeout', [-2] = 'interrupted', [-3] = 'err --- --- @param ... string List to write to the buffer local function err_message(...) - api.nvim_err_writeln(table.concat(vim.tbl_flatten({ ... }))) - api.nvim_command('redraw') + local message = table.concat(vim.tbl_flatten({ ... })) + if vim.in_fast_event() then + vim.schedule(function() + api.nvim_err_writeln(message) + api.nvim_command('redraw') + end) + else + api.nvim_err_writeln(message) + api.nvim_command('redraw') + end end --- @private -- cgit From dc8c086c7e73a9035c34be6416e7c465d61edc0e Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 2 Mar 2024 23:21:53 +0900 Subject: fix(lsp): directly rename the existing buffers when renaming (#27690) Problem: `vim.lsp.util.rename()` deletes the buffers that are affected by renaming. This has undesireable side effects. For example, when renaming a directory, all buffers under that directory are deleted and windows displaying those buffers are closed. Also, buffer options may change after renaming. Solution: Rename the buffers with :saveas. An alternative approach is to record all the relevant states and restore it after renaming, but that seems to be more complex. In fact, the older version was attempting to restore the states but only partially and incorrectly. --- runtime/lua/vim/lsp/util.lua | 78 ++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 28 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 60d0f0cc83..f8e5b6a90d 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -675,12 +675,23 @@ local function get_bufs_with_prefix(prefix) return buffers end +local function escape_gsub_repl(s) + return (s:gsub('%%', '%%%%')) +end + --- @class vim.lsp.util.rename.Opts --- @inlinedoc --- @field overwrite? boolean --- @field ignoreIfExists? boolean --- Rename old_fname to new_fname +--- +--- Existing buffers are renamed as well, while maintaining their bufnr. +--- +--- It deletes existing buffers that conflict with the renamed file name only when +--- * `opts` requests overwriting; or +--- * the conflicting buffers are not loaded, so that deleting thme does not result in data loss. +--- --- @param old_fname string --- @param new_fname string --- @param opts? vim.lsp.util.rename.Opts Options: @@ -700,24 +711,36 @@ function M.rename(old_fname, new_fname, opts) return end - local oldbufs = {} - local win = nil - - if vim.fn.isdirectory(old_fname_full) == 1 then - oldbufs = get_bufs_with_prefix(old_fname_full) - else - local oldbuf = vim.fn.bufadd(old_fname_full) - table.insert(oldbufs, oldbuf) - win = vim.fn.win_findbuf(oldbuf)[1] - end - - for _, b in ipairs(oldbufs) do - -- There may be pending changes in the buffer - if api.nvim_buf_is_loaded(b) then - api.nvim_buf_call(b, function() - vim.cmd('update!') - end) + local buf_rename = {} ---@type table + local old_fname_pat = '^' .. vim.pesc(old_fname_full) + for b in + vim.iter(get_bufs_with_prefix(old_fname_full)):filter(function(b) + -- No need to care about unloaded or nofile buffers. Also :saveas won't work for them. + return api.nvim_buf_is_loaded(b) + and not vim.list_contains({ 'nofile', 'nowrite' }, vim.bo[b].buftype) + end) + do + -- Renaming a buffer may conflict with another buffer that happens to have the same name. In + -- most cases, this would have been already detected by the file conflict check above, but the + -- conflicting buffer may not be associated with a file. For example, 'buftype' can be "nofile" + -- or "nowrite", or the buffer can be a normal buffer but has not been written to the file yet. + -- Renaming should fail in such cases to avoid losing the contents of the conflicting buffer. + local old_bname = vim.api.nvim_buf_get_name(b) + local new_bname = old_bname:gsub(old_fname_pat, escape_gsub_repl(new_fname)) + if vim.fn.bufexists(new_bname) == 1 then + local existing_buf = vim.fn.bufnr(new_bname) + if api.nvim_buf_is_loaded(existing_buf) and skip then + vim.notify( + new_bname .. ' already exists in the buffer list. Skipping rename.', + vim.log.levels.ERROR + ) + return + end + -- no need to preserve if such a buffer is empty + api.nvim_buf_delete(existing_buf, {}) end + + buf_rename[b] = { from = old_bname, to = new_bname } end local newdir = assert(vim.fs.dirname(new_fname)) @@ -733,17 +756,16 @@ function M.rename(old_fname, new_fname, opts) os.rename(old_undofile, new_undofile) end - if vim.fn.isdirectory(new_fname) == 0 then - local newbuf = vim.fn.bufadd(new_fname) - if win then - vim.fn.bufload(newbuf) - vim.bo[newbuf].buflisted = true - api.nvim_win_set_buf(win, newbuf) - end - end - - for _, b in ipairs(oldbufs) do - api.nvim_buf_delete(b, {}) + for b, rename in pairs(buf_rename) do + -- Rename with :saveas. This does two things: + -- * Unset BF_WRITE_MASK, so that users don't get E13 when they do :write. + -- * Send didClose and didOpen via textDocument/didSave handler. + api.nvim_buf_call(b, function() + vim.cmd('keepalt saveas! ' .. vim.fn.fnameescape(rename.to)) + end) + -- Delete the new buffer with the old name created by :saveas. nvim_buf_delete and + -- :bwipeout are futile because the buffer will be added again somewhere else. + vim.cmd('bdelete! ' .. vim.fn.bufnr(rename.from)) end end -- cgit From a4290f462ed7dc81e17b09bd27877b106b24b6bd Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 5 Mar 2024 12:06:15 +0000 Subject: docs(lua): improvements for LSP and Diagnostic --- runtime/lua/vim/lsp/client.lua | 47 ++++++++++++++++++++++----------- runtime/lua/vim/lsp/diagnostic.lua | 2 +- runtime/lua/vim/lsp/semantic_tokens.lua | 2 +- 3 files changed, 34 insertions(+), 17 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 0f47c57cd5..6dd898bea7 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -11,6 +11,24 @@ local validate = vim.validate --- @alias vim.lsp.client.on_exit_cb fun(code: integer, signal: integer, client_id: integer) --- @alias vim.lsp.client.before_init_cb fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig) +--- @class vim.lsp.Client.Flags +--- @inlinedoc +--- +--- Allow using incremental sync for buffer edits +--- (defailt: `true`) +--- @field allow_incremental_sync? boolean +--- +--- Debounce `didChange` notifications to the server by the given number in milliseconds. +--- No debounce occurs if `nil`. +--- (default: `150`) +--- @field debounce_text_changes integer +--- +--- Milliseconds to wait for server to exit cleanly after sending the +--- "shutdown" request before sending kill -15. If set to false, nvim exits +--- immediately after sending the "shutdown" request to the server. +--- (default: `false`) +--- @field exit_timeout integer|false + --- @class vim.lsp.ClientConfig --- command string[] that launches the language --- server (treated as in |jobstart()|, must be absolute or on `$PATH`, shell constructs like @@ -55,8 +73,8 @@ local validate = vim.validate --- Map of language server method names to |lsp-handler| --- @field handlers? table --- ---- Map with language server specific settings. These are returned to the language server if ---- requested via `workspace/configuration`. Keys are case-sensitive. +--- Map with language server specific settings. +--- See the {settings} in |vim.lsp.Client|. --- @field settings? table --- --- Table that maps string of clientside commands to user-defined functions. @@ -87,36 +105,29 @@ local validate = vim.validate --- Callback invoked before the LSP "initialize" phase, where `params` contains the parameters --- being sent to the server and `config` is the config that was passed to |vim.lsp.start_client()|. --- You can use this to modify parameters before they are sent. ---- @field before_init? vim.lsp.client.before_init_cb +--- @field before_init? fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig) --- --- Callback invoked after LSP "initialize", where `result` is a table of `capabilities` --- and anything else the server may send. For example, clangd sends --- `initialize_result.offsetEncoding` if `capabilities.offsetEncoding` was sent to it. --- You can only modify the `client.offset_encoding` here before any notifications are sent. ---- @field on_init? elem_or_list +--- @field on_init? elem_or_list --- --- Callback invoked on client exit. --- - code: exit code of the process --- - signal: number describing the signal used to terminate (if any) --- - client_id: client handle ---- @field on_exit? elem_or_list +--- @field on_exit? elem_or_list --- --- Callback invoked when client attaches to a buffer. ---- @field on_attach? elem_or_list +--- @field on_attach? elem_or_list --- --- Passed directly to the language server in the initialize request. Invalid/empty values will --- (default: "off") --- @field trace? 'off'|'messages'|'verbose' --- --- A table with flags for the client. The current (experimental) flags are: ---- - allow_incremental_sync (bool, default true): Allow using incremental sync for buffer edits ---- - debounce_text_changes (number, default 150): Debounce didChange ---- notifications to the server by the given number in milliseconds. No debounce ---- occurs if nil ---- - exit_timeout (number|boolean, default false): Milliseconds to wait for server to ---- exit cleanly after sending the "shutdown" request before sending kill -15. ---- If set to false, nvim exits immediately after sending the "shutdown" request to the server. ---- @field flags? table +--- @field flags? vim.lsp.Client.Flags --- --- Directory where the LSP server will base its workspaceFolders, rootUri, and rootPath on initialization. --- @field root_dir? string @@ -189,8 +200,14 @@ local validate = vim.validate --- Client commands take precedence over the global command registry. --- @field commands table --- +--- Map with language server specific settings. These are returned to the +--- language server if requested via `workspace/configuration`. Keys are +--- case-sensitive. --- @field settings table ---- @field flags table +--- +--- A table with flags for the client. The current (experimental) flags are: +--- @field flags vim.lsp.Client.Flags +--- --- @field get_language_id fun(bufnr: integer, filetype: string): string --- --- The capabilities provided by the client (editor or tool) diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 6156821093..e4620897ac 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -321,7 +321,7 @@ end ---@param _ lsp.ResponseError? ---@param result lsp.DocumentDiagnosticReport ---@param ctx lsp.HandlerContext ----@param config table Configuration table (see |vim.diagnostic.config()|). +---@param config vim.diagnostic.Opts Configuration table (see |vim.diagnostic.config()|). function M.on_diagnostic(_, result, ctx, config) if result == nil or result.kind == 'unchanged' then return diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index 92546e8520..20ac0a125f 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -572,7 +572,7 @@ local M = {} --- ---@param bufnr integer ---@param client_id integer ----@param opts (nil|table) Optional keyword arguments +---@param opts? table Optional keyword arguments --- - debounce (integer, default: 200): Debounce token requests --- to the server by the given number in milliseconds function M.start(bufnr, client_id, opts) -- cgit From 3e016fa8d4f797345d55f6006c42026abedb6c4e Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 6 Mar 2024 10:43:43 +0000 Subject: fix(lsp): actually send diagnostic-tags back to the server Fixes #27318 --- runtime/lua/vim/lsp/diagnostic.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index e4620897ac..08cea13548 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -136,7 +136,7 @@ end --- @param diagnostic vim.Diagnostic --- @return lsp.DiagnosticTag[]? -local function tags_vim_to_vim(diagnostic) +local function tags_vim_to_lsp(diagnostic) if not diagnostic._tags then return end @@ -173,7 +173,7 @@ local function diagnostic_vim_to_lsp(diagnostics) message = diagnostic.message, source = diagnostic.source, code = diagnostic.code, - tags = tags_vim_to_vim(diagnostics), + tags = tags_vim_to_lsp(diagnostic), }, diagnostic.user_data and (diagnostic.user_data.lsp or {}) or {}) end, diagnostics) end -- cgit From 85b13751a5fc28fadbe74d72982325ca27b4c775 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 6 Mar 2024 12:15:25 +0000 Subject: refactor(types): more fixes (2) --- runtime/lua/vim/lsp/_dynamic.lua | 2 +- runtime/lua/vim/lsp/buf.lua | 7 ++++ runtime/lua/vim/lsp/handlers.lua | 77 ++++++++++++++++++++++------------------ 3 files changed, 50 insertions(+), 36 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua index 9c2af979fa..819b03a63a 100644 --- a/runtime/lua/vim/lsp/_dynamic.lua +++ b/runtime/lua/vim/lsp/_dynamic.lua @@ -58,7 +58,7 @@ end --- @param method string --- @param opts? {bufnr: integer?} --- @return lsp.Registration? (table|nil) the registration if found ---- @private +--- @package function M:get(method, opts) opts = opts or {} opts.bufnr = opts.bufnr or vim.api.nvim_get_current_buf() diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 377c8680c7..fd78a10672 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -248,6 +248,9 @@ function M.format(options) vim.notify('[LSP] Format request failed, no matching language servers.') end + --- @param client vim.lsp.Client + --- @param params lsp.DocumentFormattingParams + --- @return lsp.DocumentFormattingParams local function set_range(client, params) if range then local range_params = @@ -294,6 +297,9 @@ end --- Restrict clients used for rename to ones where client.name matches --- this field. --- @field name? string +--- +--- (default: current buffer) +--- @field bufnr? integer --- Renames all references to the symbol under the cursor. --- @@ -786,6 +792,7 @@ function M.code_action(options) options = options or {} -- Detect old API call code_action(context) which should now be -- code_action({ context = context} ) + --- @diagnostic disable-next-line:undefined-field if options.diagnostics or options.only then options = { options = options } end diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index d816fb1482..daf4fec8d2 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -16,12 +16,12 @@ local function err_message(...) api.nvim_command('redraw') end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand M[ms.workspace_executeCommand] = function(_, _, _, _) -- Error handling is done implicitly by wrapping all handlers; see end of this file end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress ---@param result lsp.ProgressParams ---@param ctx lsp.HandlerContext M[ms.dollar_progress] = function(_, result, ctx) @@ -57,7 +57,7 @@ M[ms.dollar_progress] = function(_, result, ctx) }) end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create ---@param result lsp.WorkDoneProgressCreateParams ---@param ctx lsp.HandlerContext M[ms.window_workDoneProgress_create] = function(_, result, ctx) @@ -70,7 +70,7 @@ M[ms.window_workDoneProgress_create] = function(_, result, ctx) return vim.NIL end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest ---@param result lsp.ShowMessageRequestParams M[ms.window_showMessageRequest] = function(_, result) local actions = result.actions or {} @@ -106,7 +106,8 @@ M[ms.window_showMessageRequest] = function(_, result) end end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability +--- @param result lsp.RegistrationParams M[ms.client_registerCapability] = function(_, result, ctx) local client_id = ctx.client_id local client = assert(vim.lsp.get_client_by_id(client_id)) @@ -136,7 +137,8 @@ M[ms.client_registerCapability] = function(_, result, ctx) return vim.NIL end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_unregisterCapability +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_unregisterCapability +--- @param result lsp.UnregistrationParams M[ms.client_unregisterCapability] = function(_, result, ctx) local client_id = ctx.client_id local client = assert(vim.lsp.get_client_by_id(client_id)) @@ -150,7 +152,7 @@ M[ms.client_unregisterCapability] = function(_, result, ctx) return vim.NIL end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit M[ms.workspace_applyEdit] = function(_, workspace_edit, ctx) assert( workspace_edit, @@ -178,7 +180,8 @@ local function lookup_section(table, section) return vim.tbl_get(table, unpack(keys)) end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration +--- @param result lsp.ConfigurationParams M[ms.workspace_configuration] = function(_, result, ctx) local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) @@ -211,7 +214,7 @@ M[ms.workspace_configuration] = function(_, result, ctx) return response end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_workspaceFolders +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_workspaceFolders M[ms.workspace_workspaceFolders] = function(_, _, ctx) local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) @@ -238,7 +241,7 @@ M[ms.textDocument_inlayHint] = function(...) return vim.lsp.inlay_hint.on_inlayhint(...) end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references M[ms.textDocument_references] = function(_, result, ctx, config) if not result or vim.tbl_isempty(result) then vim.notify('No references found') @@ -296,7 +299,7 @@ local function response_to_list(map_result, entity, title_fn) end end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol M[ms.textDocument_documentSymbol] = response_to_list( util.symbols_to_items, 'document symbols', @@ -306,12 +309,12 @@ M[ms.textDocument_documentSymbol] = response_to_list( end ) ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol M[ms.workspace_symbol] = response_to_list(util.symbols_to_items, 'symbols', function(ctx) return string.format("Symbols matching '%s'", ctx.params.query) end) ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename M[ms.textDocument_rename] = function(_, result, ctx, _) if not result then vim.notify("Language server couldn't provide rename result", vim.log.levels.INFO) @@ -321,7 +324,7 @@ M[ms.textDocument_rename] = function(_, result, ctx, _) util.apply_workspace_edit(result, client.offset_encoding) end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting M[ms.textDocument_rangeFormatting] = function(_, result, ctx, _) if not result then return @@ -330,7 +333,7 @@ M[ms.textDocument_rangeFormatting] = function(_, result, ctx, _) util.apply_text_edits(result, ctx.bufnr, client.offset_encoding) end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting M[ms.textDocument_formatting] = function(_, result, ctx, _) if not result then return @@ -339,7 +342,7 @@ M[ms.textDocument_formatting] = function(_, result, ctx, _) util.apply_text_edits(result, ctx.bufnr, client.offset_encoding) end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion M[ms.textDocument_completion] = function(_, result, _, _) if vim.tbl_isempty(result or {}) then return @@ -405,14 +408,14 @@ function M.hover(_, result, ctx, config) return util.open_floating_preview(contents, format, config) end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover M[ms.textDocument_hover] = M.hover --- Jumps to a location. Used as a handler for multiple LSP methods. ---@param _ nil not used ---@param result (table) result of LSP method; a location or a list of locations. ---@param ctx (lsp.HandlerContext) table containing the context of the request, including the method ----@param config? vim.lsp.buf.LocationOpts +---@param config? vim.lsp.LocationOpts ---(`textDocument/definition` can return `Location` or `Location[]` local function location_handler(_, result, ctx, config) if result == nil or vim.tbl_isempty(result) then @@ -445,13 +448,13 @@ local function location_handler(_, result, ctx, config) api.nvim_command('botright copen') end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration M[ms.textDocument_declaration] = location_handler ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition M[ms.textDocument_definition] = location_handler ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition M[ms.textDocument_typeDefinition] = location_handler ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation M[ms.textDocument_implementation] = location_handler --- |lsp-handler| for the method "textDocument/signatureHelp". @@ -509,10 +512,10 @@ function M.signature_help(_, result, ctx, config) return fbuf, fwin end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp M[ms.textDocument_signatureHelp] = M.signature_help ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight M[ms.textDocument_documentHighlight] = function(_, result, ctx, _) if not result then return @@ -525,21 +528,22 @@ M[ms.textDocument_documentHighlight] = function(_, result, ctx, _) util.buf_highlight_references(ctx.bufnr, result, client.offset_encoding) end ----@private +--- @private --- --- Displays call hierarchy in the quickfix window. --- ----@param direction 'from'|'to' `"from"` for incoming calls and `"to"` for outgoing calls ----@return function ---- `CallHierarchyIncomingCall[]` if {direction} is `"from"`, ---- `CallHierarchyOutgoingCall[]` if {direction} is `"to"`, -local make_call_hierarchy_handler = function(direction) +--- @param direction 'from'|'to' `"from"` for incoming calls and `"to"` for outgoing calls +--- @overload fun(direction:'from'): fun(_, result: lsp.CallHierarchyIncomingCall[]?) +--- @overload fun(direction:'to'): fun(_, result: lsp.CallHierarchyOutgoingCall[]?) +local function make_call_hierarchy_handler(direction) + --- @param result lsp.CallHierarchyIncomingCall[]|lsp.CallHierarchyOutgoingCall[] return function(_, result) if not result then return end local items = {} for _, call_hierarchy_call in pairs(result) do + --- @type lsp.CallHierarchyItem local call_hierarchy_item = call_hierarchy_call[direction] for _, range in pairs(call_hierarchy_call.fromRanges) do table.insert(items, { @@ -555,13 +559,14 @@ local make_call_hierarchy_handler = function(direction) end end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_incomingCalls +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_incomingCalls M[ms.callHierarchy_incomingCalls] = make_call_hierarchy_handler('from') ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_outgoingCalls +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_outgoingCalls M[ms.callHierarchy_outgoingCalls] = make_call_hierarchy_handler('to') ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_logMessage +--- @see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_logMessage +--- @param result lsp.LogMessageParams M[ms.window_logMessage] = function(_, result, ctx, _) local message_type = result.type local message = result.message @@ -583,7 +588,8 @@ M[ms.window_logMessage] = function(_, result, ctx, _) return result end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessage +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessage +--- @param result lsp.ShowMessageParams M[ms.window_showMessage] = function(_, result, ctx, _) local message_type = result.type local message = result.message @@ -602,7 +608,8 @@ M[ms.window_showMessage] = function(_, result, ctx, _) return result end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showDocument +--- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showDocument +--- @param result lsp.ShowDocumentParams M[ms.window_showDocument] = function(_, result, ctx, _) local uri = result.uri -- cgit From 0101bdaa1ad8b09ebd5ef5551faf077f39be238c Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Mon, 19 Feb 2024 18:28:07 -0800 Subject: docs(lsp): nits and typos in client.lua --- runtime/lua/vim/lsp/client.lua | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 6dd898bea7..d0054e073c 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -156,7 +156,7 @@ local validate = vim.validate --- @field handlers table --- --- The current pending requests in flight to the server. Entries are key-value ---- pairs with the key being the request ID while the value is a table with +--- pairs with the key being the request id while the value is a table with --- `type`, `bufnr`, and `method` key-value pairs. `type` is either "pending" --- for an active request, or "cancel" for a cancel request. It will be --- "complete" ephemerally while executing |LspRequest| autocmds when replies @@ -167,8 +167,8 @@ local validate = vim.validate --- to |vim.lsp.start_client()|. --- @field config vim.lsp.ClientConfig --- ---- Response from the server sent on ---- initialize` describing the server's capabilities. +--- Response from the server sent on `initialize` describing the server's +--- capabilities. --- @field server_capabilities lsp.ServerCapabilities? --- --- A ring buffer (|vim.ringbuf()|) containing progress messages @@ -217,10 +217,11 @@ local validate = vim.validate --- Sends a request to the server. --- This is a thin wrapper around {client.rpc.request} with some additional --- checking. ---- If {handler} is not specified, If one is not found there, then an error ---- will occur. Returns: {status}, {[client_id]}. {status} is a boolean ---- indicating if the notification was successful. If it is `false`, then it ---- will always be `false` (the client has shutdown). +--- If {handler} is not specified and if there's no respective global +--- handler, then an error will occur. +--- Returns: {status}, {[client_id]}. {status} is a boolean indicating if +--- the notification was successful. If it is `false`, then it will always +--- be `false` (the client has shutdown). --- If {status} is `true`, the function returns {request_id} as the second --- result. You can use this with `client.cancel_request(request_id)` to cancel --- the request. -- cgit From e52c25b7617ac6401b080f76b0e227161dfef230 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 2 Mar 2024 13:11:23 -0800 Subject: feat(lua): deprecate vim.tbl_add_reverse_lookup --- runtime/lua/vim/lsp/log.lua | 26 +++++++++-------- runtime/lua/vim/lsp/protocol.lua | 60 +++++++++++++++++----------------------- runtime/lua/vim/lsp/rpc.lua | 9 ++++-- 3 files changed, 48 insertions(+), 47 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 018003bb81..9f2bd71158 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -2,16 +2,19 @@ local log = {} +local log_levels = vim.log.levels + --- Log level dictionary with reverse lookup as well. --- --- Can be used to lookup the number from the name or the name from the number. --- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" --- Level numbers begin with "TRACE" at 0 +--- @type table --- @nodoc -log.levels = vim.deepcopy(vim.log.levels) +log.levels = vim.deepcopy(log_levels) -- Default log level is warn. -local current_log_level = log.levels.WARN +local current_log_level = log_levels.WARN local log_date_format = '%F %H:%M:%S' @@ -58,7 +61,7 @@ local function open_logfile() logfile, openerr = io.open(logfilename, 'a+') if not logfile then local err_msg = string.format('Failed to open LSP client log file: %s', openerr) - notify(err_msg, vim.log.levels.ERROR) + notify(err_msg, log_levels.ERROR) return false end @@ -77,12 +80,13 @@ local function open_logfile() return true end -for level, levelnr in pairs(log.levels) do +for level, levelnr in pairs(log_levels) do -- Also export the log level on the root object. log[level] = levelnr -end -vim.tbl_add_reverse_lookup(log.levels) + -- Add a reverse lookup. + log.levels[levelnr] = level +end --- @param level string --- @param levelnr integer @@ -123,19 +127,19 @@ end -- log at that level (if applicable, it is checked either way). --- @nodoc -log.debug = create_logger('DEBUG', vim.log.levels.DEBUG) +log.debug = create_logger('DEBUG', log_levels.DEBUG) --- @nodoc -log.error = create_logger('ERROR', vim.log.levels.ERROR) +log.error = create_logger('ERROR', log_levels.ERROR) --- @nodoc -log.info = create_logger('INFO', vim.log.levels.INFO) +log.info = create_logger('INFO', log_levels.INFO) --- @nodoc -log.trace = create_logger('TRACE', vim.log.levels.TRACE) +log.trace = create_logger('TRACE', log_levels.TRACE) --- @nodoc -log.warn = create_logger('WARN', vim.log.levels.WARN) +log.warn = create_logger('WARN', log_levels.WARN) --- Sets the current log level. ---@param level (string|integer) One of `vim.lsp.log.levels` diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 7016209372..599f02425e 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -1,22 +1,19 @@ --- @diagnostic disable: duplicate-doc-alias --- TODO(clason) can be simplified after reverse lookup is removed ----@param t table ----@return number[] -local function get_value_set(t) - local result = {} - for _, v in pairs(t) do - if type(v) == 'number' then - table.insert(result, v) - end +---@param tbl table +local function get_value_set(tbl) + local value_set = {} + for _, v in pairs(tbl) do + table.insert(value_set, v) end - table.sort(result) - return result + table.sort(value_set) + return value_set end -- Protocol for the Microsoft Language Server Protocol (mslsp) +local protocol = {} -local protocol = { +local constants = { --- @enum lsp.DiagnosticSeverity DiagnosticSeverity = { -- Reports an error. @@ -309,11 +306,13 @@ local protocol = { }, } --- TODO(mariasolos): Remove this reverse lookup. -for k, v in pairs(protocol) do - local tbl = vim.deepcopy(v, true) - vim.tbl_add_reverse_lookup(tbl) - protocol[k] = tbl +for k1, v1 in pairs(constants) do + local tbl = vim.deepcopy(v1, true) + for _, k2 in ipairs(vim.tbl_keys(tbl)) do + local v2 = tbl[k2] + tbl[v2] = k2 + end + protocol[k1] = tbl end --[=[ @@ -719,14 +718,7 @@ function protocol.make_client_capabilities() codeActionLiteralSupport = { codeActionKind = { - valueSet = (function() - local res = vim.iter.filter(function(value) - -- Filter out the keys that were added by the reverse lookup. - return value:match('^%l') - end, vim.tbl_values(protocol.CodeActionKind)) - table.sort(res) - return res - end)(), + valueSet = get_value_set(constants.CodeActionKind), }, }, isPreferredSupport = true, @@ -751,10 +743,10 @@ function protocol.make_client_capabilities() commitCharactersSupport = false, preselectSupport = false, deprecatedSupport = false, - documentationFormat = { protocol.MarkupKind.Markdown, protocol.MarkupKind.PlainText }, + documentationFormat = { constants.MarkupKind.Markdown, constants.MarkupKind.PlainText }, }, completionItemKind = { - valueSet = get_value_set(protocol.CompletionItemKind), + valueSet = get_value_set(constants.CompletionItemKind), }, completionList = { itemDefaults = { @@ -783,13 +775,13 @@ function protocol.make_client_capabilities() }, hover = { dynamicRegistration = true, - contentFormat = { protocol.MarkupKind.Markdown, protocol.MarkupKind.PlainText }, + contentFormat = { constants.MarkupKind.Markdown, constants.MarkupKind.PlainText }, }, signatureHelp = { dynamicRegistration = false, signatureInformation = { activeParameterSupport = true, - documentationFormat = { protocol.MarkupKind.Markdown, protocol.MarkupKind.PlainText }, + documentationFormat = { constants.MarkupKind.Markdown, constants.MarkupKind.PlainText }, parameterInformation = { labelOffsetSupport = true, }, @@ -804,7 +796,7 @@ function protocol.make_client_capabilities() documentSymbol = { dynamicRegistration = false, symbolKind = { - valueSet = get_value_set(protocol.SymbolKind), + valueSet = get_value_set(constants.SymbolKind), }, hierarchicalDocumentSymbolSupport = true, }, @@ -815,7 +807,7 @@ function protocol.make_client_capabilities() publishDiagnostics = { relatedInformation = true, tagSupport = { - valueSet = get_value_set(protocol.DiagnosticTag), + valueSet = get_value_set(constants.DiagnosticTag), }, dataSupport = true, }, @@ -827,7 +819,7 @@ function protocol.make_client_capabilities() symbol = { dynamicRegistration = false, symbolKind = { - valueSet = get_value_set(protocol.SymbolKind), + valueSet = get_value_set(constants.SymbolKind), }, }, configuration = true, @@ -867,9 +859,9 @@ end --- Creates a normalized object describing LSP server capabilities. ---@param server_capabilities table Table of capabilities supported by the server ----@return lsp.ServerCapabilities|nil Normalized table of capabilities +---@return lsp.ServerCapabilities|nil : Normalized table of capabilities function protocol.resolve_capabilities(server_capabilities) - local TextDocumentSyncKind = protocol.TextDocumentSyncKind + local TextDocumentSyncKind = protocol.TextDocumentSyncKind ---@type table local textDocumentSync = server_capabilities.textDocumentSync if textDocumentSync == nil then -- Defaults if omitted. diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 8e014b1063..984e4f040a 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -130,7 +130,7 @@ local M = {} --- Mapping of error codes used by the client --- @nodoc -M.client_errors = { +local client_errors = { INVALID_SERVER_MESSAGE = 1, INVALID_SERVER_JSON = 2, NO_RESULT_CALLBACK_FOUND = 3, @@ -140,7 +140,12 @@ M.client_errors = { SERVER_RESULT_CALLBACK_ERROR = 7, } -M.client_errors = vim.tbl_add_reverse_lookup(M.client_errors) +--- @type table +--- @nodoc +M.client_errors = vim.deepcopy(client_errors) +for k, v in pairs(client_errors) do + M.client_errors[v] = k +end --- Constructs an error message from an LSP error object. --- -- cgit From 649dd00fe2e54183cc210f24d36504a61e5ea605 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 8 Mar 2024 11:23:17 +0100 Subject: feat!: remove deprecated functions --- runtime/lua/vim/lsp/buf.lua | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index fd78a10672..50121f30b2 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -28,16 +28,6 @@ local function request(method, params, handler) return vim.lsp.buf_request(0, method, params, handler) end ---- Checks whether the language servers attached to the current buffer are ---- ready. ---- ----@return boolean : if server responds. ----@deprecated -function M.server_ready() - vim.deprecate('vim.lsp.buf.server_ready()', nil, '0.10') - return not not vim.lsp.buf_notify(0, 'window/progress', {}) -end - --- Displays hover information about the symbol under the cursor in a floating --- window. Calling the function twice will jump into the floating window. function M.hover() -- cgit From ade1b12f49c3b3914c74847d791eb90ea90b56b7 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 8 Mar 2024 12:25:18 +0000 Subject: docs: support inline markdown - Tags are now created with `[tag]()` - References are now created with `[tag]` - Code spans are no longer wrapped --- runtime/lua/vim/lsp/client.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/lsp') diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index d0054e073c..ff0db166d5 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -219,7 +219,7 @@ local validate = vim.validate --- checking. --- If {handler} is not specified and if there's no respective global --- handler, then an error will occur. ---- Returns: {status}, {[client_id]}. {status} is a boolean indicating if +--- Returns: {status}, {client_id}?. {status} is a boolean indicating if --- the notification was successful. If it is `false`, then it will always --- be `false` (the client has shutdown). --- If {status} is `true`, the function returns {request_id} as the second @@ -262,7 +262,7 @@ local validate = vim.validate --- --- Checks if a client supports a given method. --- Always returns true for unknown off-spec methods. ---- [opts] is a optional `{bufnr?: integer}` table. +--- {opts} is a optional `{bufnr?: integer}` table. --- Some language server capabilities can be file specific. --- @field supports_method fun(method: string, opts?: {bufnr: integer?}): boolean --- -- cgit