diff options
Diffstat (limited to 'runtime/lua/vim')
| -rw-r--r-- | runtime/lua/vim/_editor.lua | 2 | ||||
| -rw-r--r-- | runtime/lua/vim/_meta/vvars.lua | 23 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp.lua | 114 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/_meta.lua | 3 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 6 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/codelens.lua | 14 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/diagnostic.lua | 9 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/handlers.lua | 92 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/inlay_hint.lua | 28 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/log.lua | 4 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/protocol.lua | 2 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/rpc.lua | 192 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/semantic_tokens.lua | 58 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/sync.lua | 28 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/util.lua | 4 |
15 files changed, 354 insertions, 225 deletions
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 6cccbe8313..0bb1becf58 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -478,7 +478,7 @@ do end vim.g = make_dict_accessor('g', false) - vim.v = make_dict_accessor('v', false) + vim.v = make_dict_accessor('v', false) --[[@as vim.v]] vim.b = make_dict_accessor('b') vim.w = make_dict_accessor('w') vim.t = make_dict_accessor('t') diff --git a/runtime/lua/vim/_meta/vvars.lua b/runtime/lua/vim/_meta/vvars.lua new file mode 100644 index 0000000000..059ef04203 --- /dev/null +++ b/runtime/lua/vim/_meta/vvars.lua @@ -0,0 +1,23 @@ +--- @meta _ + +-- TODO(lewis6991): generate this and `:help vim-variable` + +--- @class vim.v +--- The count given for the last Normal mode command. Can be used +--- to get the count before a mapping. Read-only. Example: +--- ```vim +--- :map _x :<C-U>echo "the count is " .. v:count<CR> +--- ``` +--- Note: The <C-U> is required to remove the line range that you +--- get when typing ':' after a count. +--- When there are two counts, as in "3d2w", they are multiplied, +--- just like what happens in the command, "d6w" for the example. +--- Also used for evaluating the 'formatexpr' option. +--- @field count integer +--- +--- Line number for the 'foldexpr' |fold-expr|, 'formatexpr', +--- 'indentexpr' and 'statuscolumn' expressions, tab page number +--- for 'guitablabel' and 'guitabtooltip'. Only valid while one of +--- these expressions is being evaluated. Read-only when in the |sandbox|. +--- @field lnum integer +vim.v = ... diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 261a3aa5de..31aacd668b 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -257,7 +257,7 @@ end --- Validates a client configuration as given to |vim.lsp.start_client()|. --- ---@param config (lsp.ClientConfig) ----@return (string|fun(dispatchers:table):table) Command +---@return (string|fun(dispatchers:vim.rpc.Dispatchers):RpcClientPublic?) Command ---@return string[] Arguments ---@return string Encoding. local function validate_client_config(config) @@ -290,7 +290,7 @@ local function validate_client_config(config) 'flags.debounce_text_changes must be a number with the debounce time in milliseconds' ) - local cmd, cmd_args --- @type (string|fun(dispatchers:table):table), string[] + local cmd, cmd_args --- @type (string|fun(dispatchers:vim.rpc.Dispatchers):RpcClientPublic), string[] local config_cmd = config.cmd if type(config_cmd) == 'function' then cmd = config_cmd @@ -397,13 +397,14 @@ do end, }) + ---@param client lsp.Client ---@return CTGroup local function get_group(client) local allow_inc_sync = 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 + sync_kind = protocol.TextDocumentSyncKind.Full --[[@as integer]] end return { sync_kind = sync_kind, @@ -572,7 +573,7 @@ do return end - local changes + local changes --- @type lsp.TextDocumentContentChangeEvent[] if sync_kind == protocol.TextDocumentSyncKind.None then return elseif sync_kind == protocol.TextDocumentSyncKind.Incremental then @@ -650,6 +651,7 @@ do end ---@private + ---@param buf_state CTBufferState function changetracking._reset_timer(buf_state) local timer = buf_state.timer if timer then @@ -663,6 +665,8 @@ do --- Flushes any outstanding change notification. ---@private + ---@param client lsp.Client + ---@param bufnr? integer function changetracking.flush(client, bufnr) local group = get_group(client) local state = state_by_group[group] @@ -685,7 +689,7 @@ end --- Default handler for the 'textDocument/didOpen' LSP notification. --- ---@param bufnr integer Number of the buffer, or 0 for current ----@param client table Client object +---@param client lsp.Client Client object local function text_document_did_open_handler(bufnr, client) changetracking.init(client, bufnr) if not vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then @@ -890,7 +894,7 @@ end ---@return string function lsp.status() local percentage = nil - local messages = {} + local messages = {} --- @type string[] for _, client in ipairs(vim.lsp.get_clients()) do for progress in client.progress do local value = progress.value @@ -913,12 +917,15 @@ function lsp.status() end -- Determines whether the given option can be set by `set_defaults`. +---@param bufnr integer +---@param option string +---@return boolean local function is_empty_or_default(bufnr, option) if vim.bo[bufnr][option] == '' then return true end - local info = vim.api.nvim_get_option_info2(option, { buf = bufnr }) + local info = api.nvim_get_option_info2(option, { buf = bufnr }) local scriptinfo = vim.tbl_filter(function(e) return e.sid == info.last_set_sid end, vim.fn.getscriptinfo()) @@ -932,6 +939,7 @@ end ---@private ---@param client lsp.Client +---@param bufnr integer function lsp._set_defaults(client, bufnr) if client.supports_method(ms.textDocument_definition) and is_empty_or_default(bufnr, 'tagfunc') @@ -1131,7 +1139,7 @@ function lsp.start_client(config) --- Returns the default handler if the user hasn't set a custom one. --- ---@param method (string) LSP method name - ---@return lsp-handler|nil The handler for the given method, if defined, or the default from |vim.lsp.handlers| + ---@return lsp.Handler|nil handler for the given method, if defined, or the default from |vim.lsp.handlers| local function resolve_handler(method) return handlers[method] or default_handlers[method] end @@ -1189,7 +1197,7 @@ function lsp.start_client(config) --- Invoked when the client operation throws an error. --- ---@param code (integer) Error code - ---@param err (...) Other arguments may be passed depending on the error kind + ---@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 dispatch.on_error(code, err) @@ -1197,7 +1205,9 @@ function lsp.start_client(config) if config.on_error then local status, usererr = pcall(config.on_error, code, err) if not status then - local _ = log.error() and log.error(log_prefix, 'user on_error failed', { err = usererr }) + if log.error() then + log.error(log_prefix, 'user on_error failed', { err = usererr }) + end err_message(log_prefix, ' user on_error failed: ', tostring(usererr)) end end @@ -1283,7 +1293,7 @@ function lsp.start_client(config) end -- Start the RPC client. - local rpc + local rpc --- @type RpcClientPublic? if type(cmd) == 'function' then rpc = cmd(dispatch) else @@ -1306,9 +1316,10 @@ function lsp.start_client(config) rpc = rpc, offset_encoding = offset_encoding, config = config, - attached_buffers = {}, + attached_buffers = {}, --- @type table<integer,true> handlers = handlers, + --- @type table<string,function> commands = config.commands or {}, --- @type table<integer,{ type: string, bufnr: integer, method: string}> @@ -1346,7 +1357,7 @@ function lsp.start_client(config) verbose = 'verbose', } - local workspace_folders --- @type table[]? + 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 @@ -1426,7 +1437,9 @@ function lsp.start_client(config) end end - local _ = log.trace() and log.trace(log_prefix, 'initialize_params', initialize_params) + if log.trace() then + log.trace(log_prefix, 'initialize_params', initialize_params) + end rpc.request('initialize', initialize_params, function(init_err, result) assert(not init_err, tostring(init_err)) assert(result, 'server sent empty result') @@ -1439,7 +1452,7 @@ function lsp.start_client(config) -- when to send certain events to clients. client.server_capabilities = assert(result.capabilities, "initialize result doesn't contain capabilities") - client.server_capabilities = protocol.resolve_capabilities(client.server_capabilities) + client.server_capabilities = assert(protocol.resolve_capabilities(client.server_capabilities)) if client.server_capabilities.positionEncoding then client.offset_encoding = client.server_capabilities.positionEncoding @@ -1455,12 +1468,13 @@ function lsp.start_client(config) write_error(lsp.client_errors.ON_INIT_CALLBACK_ERROR, err) end end - local _ = log.info() - and log.info( + if log.info() then + log.info( log_prefix, 'server_capabilities', { server_capabilities = client.server_capabilities } ) + end -- Only assign after initialized. active_clients[client_id] = client @@ -1483,7 +1497,7 @@ function lsp.start_client(config) --- ---@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 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 @@ -1677,9 +1691,9 @@ function lsp.start_client(config) --- ---@param command lsp.Command ---@param context? {bufnr: integer} - ---@param handler? lsp-handler only called if a server command + ---@param handler? lsp.Handler only called if a server command function client._exec_cmd(command, context, handler) - context = vim.deepcopy(context or {}) + context = vim.deepcopy(context or {}) --[[@as lsp.HandlerContext]] context.bufnr = context.bufnr or api.nvim_get_current_buf() context.client_id = client.id local cmdname = command.command @@ -1749,29 +1763,32 @@ function lsp.start_client(config) return client_id end ----@private ----@fn text_document_did_change_handler(_, bufnr, changedtick, firstline, lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size) --- Notify all attached clients that a buffer has changed. -local text_document_did_change_handler -do - text_document_did_change_handler = function( - _, - bufnr, - changedtick, - firstline, - lastline, - new_lastline - ) - -- Detach (nvim_buf_attach) via returning True to on_lines if no clients are attached - if tbl_isempty(all_buffer_active_clients[bufnr] or {}) then - return true - end - util.buf_versions[bufnr] = changedtick - changetracking.send_changes(bufnr, firstline, lastline, new_lastline) +---@param _ integer +---@param bufnr integer +---@param changedtick integer +---@param firstline integer +---@param lastline integer +---@param new_lastline integer +---@return true? +local function text_document_did_change_handler( + _, + bufnr, + changedtick, + firstline, + lastline, + new_lastline +) + -- Detach (nvim_buf_attach) via returning True to on_lines if no clients are attached + if tbl_isempty(all_buffer_active_clients[bufnr] or {}) then + return true end + util.buf_versions[bufnr] = changedtick + changetracking.send_changes(bufnr, firstline, lastline, new_lastline) end ---Buffer lifecycle handler for textDocument/didSave +--- @param bufnr integer local function text_document_did_save_handler(bufnr) bufnr = resolve_bufnr(bufnr) local uri = vim.uri_from_bufnr(bufnr) @@ -1797,7 +1814,7 @@ local function text_document_did_save_handler(bufnr) end local save_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'save') if save_capability then - local included_text + local included_text --- @type string? if type(save_capability) == 'table' and save_capability.includeText then included_text = text(bufnr) end @@ -1826,8 +1843,9 @@ function lsp.buf_attach_client(bufnr, client_id) }) bufnr = resolve_bufnr(bufnr) if not api.nvim_buf_is_loaded(bufnr) then - local _ = log.warn() - and log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr)) + if log.warn() then + log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr)) + end return false end local buffer_client_ids = all_buffer_active_clients[bufnr] @@ -2087,7 +2105,7 @@ api.nvim_create_autocmd('VimLeavePre', { client.stop() end - local timeouts = {} + local timeouts = {} --- @type table<integer,integer> local max_timeout = 0 local send_kill = false @@ -2134,7 +2152,7 @@ api.nvim_create_autocmd('VimLeavePre', { ---@param bufnr (integer) Buffer handle, or 0 for current. ---@param method (string) LSP method name ---@param params table|nil Parameters to send to the server ----@param handler? lsp-handler See |lsp-handler| +---@param handler? lsp.Handler See |lsp-handler| --- If nil, follows resolution strategy defined in |lsp-handler-configuration| --- ---@return table<integer, integer> client_request_ids Map of client-id:request-id pairs @@ -2152,7 +2170,7 @@ function lsp.buf_request(bufnr, method, params, handler) bufnr = resolve_bufnr(bufnr) local method_supported = false local clients = lsp.get_clients({ bufnr = bufnr }) - local client_request_ids = {} + local client_request_ids = {} --- @type table<integer,integer> for _, client in ipairs(clients) do if client.supports_method(method, { bufnr = bufnr }) then method_supported = true @@ -2194,7 +2212,7 @@ end --- a `client_id:result` map. ---@return function cancel Function that cancels all requests. function lsp.buf_request_all(bufnr, method, params, handler) - local results = {} + local results = {} --- @type table<integer,{error:string, result:any}> local result_count = 0 local expected_result_count = 0 @@ -2324,6 +2342,7 @@ function lsp.formatexpr(opts) local params = util.make_formatting_params() local end_line = vim.fn.getline(end_lnum) --[[@as string]] local end_col = util._str_utfindex_enc(end_line, nil, client.offset_encoding) + --- @cast params +lsp.DocumentRangeFormattingParams params.range = { start = { line = start_lnum - 1, @@ -2378,7 +2397,7 @@ end ---@return table result is table of (client_id, client) pairs ---@deprecated Use |vim.lsp.get_clients()| instead. function lsp.buf_get_clients(bufnr) - local result = {} + local result = {} --- @type table<integer,lsp.Client> for _, client in ipairs(lsp.get_clients({ bufnr = resolve_bufnr(bufnr) })) do result[client.id] = client end @@ -2432,7 +2451,7 @@ function lsp.for_each_buffer_client(bufnr, fn) end --- Function to manage overriding defaults for LSP handlers. ----@param handler (function) See |lsp-handler| +---@param handler (lsp.Handler) See |lsp-handler| ---@param override_config (table) Table containing the keys to override behavior of the {handler} function lsp.with(handler, override_config) return function(err, result, ctx, config) @@ -2497,6 +2516,7 @@ end --- arguments?: any[] --- --- The second argument is the `ctx` of |lsp-handler| +--- @type table<string,function> lsp.commands = setmetatable({}, { __newindex = function(tbl, key, value) assert(type(key) == 'string', 'The key for commands in `vim.lsp.commands` must be a string') 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<integer,true> ---@type table<integer, table<integer, lsp.CodeLens[]>> --- 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<string,lsp.Handler> 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 |