aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-11-19 22:57:13 +0000
committerJosh Rahm <joshuarahm@gmail.com>2024-11-19 22:57:13 +0000
commit9be89f131f87608f224f0ee06d199fcd09d32176 (patch)
tree11022dcfa9e08cb4ac5581b16734196128688d48 /runtime/lua/vim/lsp
parentff7ed8f586589d620a806c3758fac4a47a8e7e15 (diff)
parent88085c2e80a7e3ac29aabb6b5420377eed99b8b6 (diff)
downloadrneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.gz
rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.bz2
rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.zip
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'runtime/lua/vim/lsp')
-rw-r--r--runtime/lua/vim/lsp/_completion.lua276
-rw-r--r--runtime/lua/vim/lsp/_dynamic.lua4
-rw-r--r--runtime/lua/vim/lsp/_meta/protocol.lua1556
-rw-r--r--runtime/lua/vim/lsp/_watchfiles.lua4
-rw-r--r--runtime/lua/vim/lsp/buf.lua71
-rw-r--r--runtime/lua/vim/lsp/client.lua53
-rw-r--r--runtime/lua/vim/lsp/codelens.lua8
-rw-r--r--runtime/lua/vim/lsp/completion.lua754
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua33
-rw-r--r--runtime/lua/vim/lsp/handlers.lua3
-rw-r--r--runtime/lua/vim/lsp/health.lua92
-rw-r--r--runtime/lua/vim/lsp/inlay_hint.lua41
-rw-r--r--runtime/lua/vim/lsp/log.lua4
-rw-r--r--runtime/lua/vim/lsp/protocol.lua382
-rw-r--r--runtime/lua/vim/lsp/rpc.lua16
-rw-r--r--runtime/lua/vim/lsp/semantic_tokens.lua16
-rw-r--r--runtime/lua/vim/lsp/sync.lua13
-rw-r--r--runtime/lua/vim/lsp/util.lua218
18 files changed, 2059 insertions, 1485 deletions
diff --git a/runtime/lua/vim/lsp/_completion.lua b/runtime/lua/vim/lsp/_completion.lua
deleted file mode 100644
index a169f96565..0000000000
--- a/runtime/lua/vim/lsp/_completion.lua
+++ /dev/null
@@ -1,276 +0,0 @@
-local M = {}
-local api = vim.api
-local lsp = vim.lsp
-local protocol = lsp.protocol
-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)
- local ok, parsed = pcall(function()
- return vim.lsp._snippet_grammar.parse(input)
- end)
- return ok and tostring(parsed) or input
-end
-
---- Returns text that should be inserted when selecting completion item. The
---- precedence is as follows: textEdit.newText > insertText > label
----
---- See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
----
----@param item lsp.CompletionItem
----@return string
-local function get_completion_word(item)
- if item.textEdit ~= nil and item.textEdit.newText ~= nil and item.textEdit.newText ~= '' then
- if item.insertTextFormat == protocol.InsertTextFormat.PlainText then
- return item.textEdit.newText
- else
- return parse_snippet(item.textEdit.newText)
- end
- elseif item.insertText ~= nil and item.insertText ~= '' then
- if item.insertTextFormat == protocol.InsertTextFormat.PlainText then
- return item.insertText
- else
- return parse_snippet(item.insertText)
- end
- end
- 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
-end
-
---- Turns the result of a `textDocument/completion` request into vim-compatible
---- |complete-items|.
----
----@param result vim.lsp.CompletionResult Result of `textDocument/completion`
----@param prefix string prefix to filter the completion items
----@return table[]
----@see complete-items
-function M._lsp_to_complete_items(result, prefix)
- local items = get_items(result)
- if vim.tbl_isempty(items) then
- return {}
- end
-
- local function matches_prefix(item)
- return vim.startswith(get_completion_word(item), prefix)
- end
-
- items = vim.tbl_filter(matches_prefix, items) --[[@as lsp.CompletionItem[]|]]
- table.sort(items, function(a, b)
- return (a.sortText or a.label) < (b.sortText or b.label)
- end)
-
- local matches = {}
- for _, item in ipairs(items) do
- local info = ''
- local documentation = item.documentation
- if documentation then
- if type(documentation) == 'string' and documentation ~= '' then
- info = documentation
- elseif type(documentation) == 'table' and type(documentation.value) == 'string' then
- info = documentation.value
- else
- vim.notify(
- ('invalid documentation value %s'):format(vim.inspect(documentation)),
- vim.log.levels.WARN
- )
- end
- end
- local word = get_completion_word(item)
- table.insert(matches, {
- word = word,
- abbr = item.label,
- kind = protocol.CompletionItemKind[item.kind] or 'Unknown',
- menu = item.detail or '',
- info = #info > 0 and info or nil,
- icase = 1,
- dup = 1,
- empty = 1,
- user_data = {
- nvim = {
- lsp = {
- completion_item = item,
- },
- },
- },
- })
- end
- return matches
-end
-
----@param lnum integer 0-indexed
----@param items lsp.CompletionItem[]
-local function adjust_start_col(lnum, line, items, encoding)
- local min_start_char = nil
- for _, item in pairs(items) do
- if item.textEdit and item.textEdit.range.start.line == lnum then
- if min_start_char and min_start_char ~= item.textEdit.range.start.character then
- return nil
- end
- min_start_char = item.textEdit.range.start.character
- end
- end
- if min_start_char then
- return vim.lsp.util._str_byteindex_enc(line, min_start_char, encoding)
- else
- return nil
- end
-end
-
----@private
----@param line string line content
----@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 vim.lsp.CompletionResult
----@param encoding string
----@return table[] matches
----@return integer? server_start_boundary
-function M._convert_results(
- line,
- lnum,
- cursor_col,
- client_start_boundary,
- server_start_boundary,
- result,
- encoding
-)
- -- Completion response items may be relative to a position different than `client_start_boundary`.
- -- Concrete example, with lua-language-server:
- --
- -- require('plenary.asy|
- -- ▲ ▲ ▲
- -- │ │ └── cursor_pos: 20
- -- │ └────── client_start_boundary: 17
- -- └────────────── textEdit.range.start.character: 9
- -- .newText = 'plenary.async'
- -- ^^^
- -- prefix (We'd remove everything not starting with `asy`,
- -- so we'd eliminate the `plenary.async` result
- --
- -- `adjust_start_col` is used to prefer the language server boundary.
- --
- local candidates = get_items(result)
- local curstartbyte = adjust_start_col(lnum, line, candidates, encoding)
- if server_start_boundary == nil then
- server_start_boundary = curstartbyte
- elseif curstartbyte ~= nil and curstartbyte ~= server_start_boundary then
- server_start_boundary = client_start_boundary
- end
- local prefix = line:sub((server_start_boundary or client_start_boundary) + 1, cursor_col)
- local matches = M._lsp_to_complete_items(result, prefix)
- return matches, server_start_boundary
-end
-
----@param findstart integer 0 or 1, decides behavior
----@param base integer findstart=0, text to match against
----@return integer|table Decided by {findstart}:
---- - findstart=0: column where the completion starts, or -2 or -3
---- - findstart=1: list of matches (actually just calls |complete()|)
-function M.omnifunc(findstart, base)
- assert(base) -- silence luals
- local bufnr = api.nvim_get_current_buf()
- local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion })
- local remaining = #clients
- if remaining == 0 then
- return findstart == 1 and -1 or {}
- end
-
- local win = api.nvim_get_current_win()
- local cursor = api.nvim_win_get_cursor(win)
- local lnum = cursor[1] - 1
- local cursor_col = cursor[2]
- local line = api.nvim_get_current_line()
- local line_to_cursor = line:sub(1, cursor_col)
- local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') --[[@as integer]]
- local server_start_boundary = nil
- local items = {}
-
- local function on_done()
- local mode = api.nvim_get_mode()['mode']
- if mode == 'i' or mode == 'ic' then
- vim.fn.complete((server_start_boundary or client_start_boundary) + 1, items)
- end
- end
-
- local util = vim.lsp.util
- for _, client in ipairs(clients) do
- local params = util.make_position_params(win, client.offset_encoding)
- client.request(ms.textDocument_completion, params, function(err, result)
- if err then
- vim.lsp.log.warn(err.message)
- end
- if result and vim.fn.mode() == 'i' then
- local matches
- matches, server_start_boundary = M._convert_results(
- line,
- lnum,
- cursor_col,
- client_start_boundary,
- server_start_boundary,
- result,
- client.offset_encoding
- )
- vim.list_extend(items, matches)
- end
- remaining = remaining - 1
- if remaining == 0 then
- vim.schedule(on_done)
- end
- end, bufnr)
- end
-
- -- Return -2 to signal that we should continue completion so that we can
- -- async complete.
- return -2
-end
-
-return M
diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua
index 819b03a63a..27113c0e74 100644
--- a/runtime/lua/vim/lsp/_dynamic.lua
+++ b/runtime/lua/vim/lsp/_dynamic.lua
@@ -24,7 +24,6 @@ function M:supports_registration(method)
end
--- @param registrations lsp.Registration[]
---- @package
function M:register(registrations)
-- remove duplicates
self:unregister(registrations)
@@ -38,7 +37,6 @@ function M:register(registrations)
end
--- @param unregisterations lsp.Unregistration[]
---- @package
function M:unregister(unregisterations)
for _, unreg in ipairs(unregisterations) do
local method = unreg.method
@@ -58,7 +56,6 @@ end
--- @param method string
--- @param opts? {bufnr: integer?}
--- @return lsp.Registration? (table|nil) the registration if found
---- @package
function M:get(method, opts)
opts = opts or {}
opts.bufnr = opts.bufnr or vim.api.nvim_get_current_buf()
@@ -78,7 +75,6 @@ end
--- @param method string
--- @param opts? {bufnr: integer?}
---- @package
function M:supports(method, opts)
return self:get(method, opts) ~= nil
end
diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua
index 9a11972007..d83c40a09f 100644
--- a/runtime/lua/vim/lsp/_meta/protocol.lua
+++ b/runtime/lua/vim/lsp/_meta/protocol.lua
@@ -134,7 +134,7 @@ error('Cannot require a meta file')
---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
+---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
@@ -681,6 +681,11 @@ error('Cannot require a meta file')
---of a notebook cell.
---@field cellTextDocuments lsp.TextDocumentItem[]
+---Registration options specific to a notebook.
+---
+---@since 3.17.0
+---@class lsp.NotebookDocumentSyncRegistrationOptions: lsp.NotebookDocumentSyncOptions, lsp.StaticRegistrationOptions
+
---The params sent in a change notebook document notification.
---
---@since 3.17.0
@@ -789,7 +794,7 @@ error('Cannot require a meta file')
---Information about the server.
---
---@since 3.15.0
----@field serverInfo? lsp._anonym1.serverInfo
+---@field serverInfo? lsp.ServerInfo
---The data type of the ResponseError if the
---initialize request fails.
@@ -1115,7 +1120,7 @@ error('Cannot require a meta file')
---capability.
---
---@since 3.17.0
----@field itemDefaults? lsp._anonym2.itemDefaults
+---@field itemDefaults? lsp.CompletionItemDefaults
---
---The completion items.
---@field items lsp.CompletionItem[]
@@ -1171,7 +1176,7 @@ error('Cannot require a meta file')
---
---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
+---if the client specifies the client capability
---`textDocument.signatureHelp.noActiveParameterSupport === true`
---
---If omitted or the value lies outside the range of
@@ -1307,6 +1312,12 @@ error('Cannot require a meta file')
---Title of the command, like `save`.
---@field title string
---
+---An optional tooltip.
+---
+---@since 3.18.0
+---@proposed
+---@field tooltip? string
+---
---The identifier of the actual command handler.
---@field command string
---
@@ -1355,7 +1366,7 @@ error('Cannot require a meta file')
--- error message with `reason` in the editor.
---
---@since 3.16.0
----@field disabled? lsp._anonym4.disabled
+---@field disabled? lsp.CodeActionDisabled
---
---The workspace edit this code action performs.
---@field edit? lsp.WorkspaceEdit
@@ -1379,6 +1390,12 @@ error('Cannot require a meta file')
---
---A query string to filter symbols by. Clients may send an empty
---string here to request all symbols.
+---
+---The `query`-parameter should be interpreted in a *relaxed way* as editors
+---will apply their own highlighting and scoring on the results. A good rule
+---of thumb is to match case-insensitive and to simply check that the
+---characters of *query* appear in their order in a candidate symbol.
+---Servers shouldn't use prefix, substring, or similar strict matching.
---@field query string
---A special workspace symbol that supports locations without a range.
@@ -1393,7 +1410,7 @@ error('Cannot require a meta file')
---capability `workspace.symbol.resolveSupport`.
---
---See SymbolInformation#location for more details.
----@field location lsp.Location|lsp._anonym5.location
+---@field location lsp.Location|lsp.LocationUriOnly
---
---A data entry field that is preserved on a workspace symbol between a
---workspace symbol request and a workspace symbol resolve request.
@@ -1566,6 +1583,12 @@ error('Cannot require a meta file')
---
---The edits to apply.
---@field edit lsp.WorkspaceEdit
+---
+---Additional data about the edit.
+---
+---@since 3.18.0
+---@proposed
+---@field metadata? lsp.WorkspaceEditMetadata
---The result returned from the apply workspace edit request.
---
@@ -1650,7 +1673,7 @@ error('Cannot require a meta file')
---@class lsp.SetTraceParams
---
----@field value lsp.TraceValues
+---@field value lsp.TraceValue
---@class lsp.LogTraceParams
---
@@ -1848,10 +1871,10 @@ error('Cannot require a meta file')
---
---Server supports providing semantic tokens for a specific range
---of a document.
----@field range? boolean|lsp._anonym6.range
+---@field range? boolean|lsp._anonym1.range
---
---Server supports providing semantic tokens for a full document.
----@field full? boolean|lsp._anonym7.full
+---@field full? boolean|lsp.SemanticTokensFullDelta
---@since 3.16.0
---@class lsp.SemanticTokensEdit
@@ -1888,7 +1911,10 @@ 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)[]
+---
+---@since 3.18.0 - support for SnippetTextEdit. This is guarded using a
+---client capability.
+---@field edits (lsp.TextEdit|lsp.AnnotatedTextEdit|lsp.SnippetTextEdit)[]
---Create file operation.
---@class lsp.CreateFile: lsp.ResourceOperation
@@ -2235,7 +2261,7 @@ error('Cannot require a meta file')
---@field uri lsp.DocumentUri
---
---The text document's language identifier.
----@field languageId string
+---@field languageId lsp.LanguageKind
---
---The version number of this document (it will increase after each
---change, including undo/redo).
@@ -2244,6 +2270,28 @@ error('Cannot require a meta file')
---The content of the opened text document.
---@field text string
+---Options specific to a notebook plus its cells
+---to be synced to the server.
+---
+---If a selector provides a notebook document
+---filter but no cell selector all cells of a
+---matching notebook document will be synced.
+---
+---If a selector provides no notebook document
+---filter but only a cell selector all notebook
+---document that contain at least one matching
+---cell will be synced.
+---
+---@since 3.17.0
+---@class lsp.NotebookDocumentSyncOptions
+---
+---The notebooks to be synced
+---@field notebookSelector (lsp.NotebookDocumentFilterWithNotebook|lsp.NotebookDocumentFilterWithCells)[]
+---
+---Whether save notification should be forwarded to
+---the server. Will only be honored if mode === `notebook`.
+---@field save? boolean
+
---A versioned notebook document identifier.
---
---@since 3.17.0
@@ -2266,7 +2314,7 @@ error('Cannot require a meta file')
---@field metadata? lsp.LSPObject
---
---Changes to cells
----@field cells? lsp._anonym8.cells
+---@field cells? lsp.NotebookDocumentCellChanges
---A literal to identify a notebook document in the client.
---
@@ -2348,7 +2396,7 @@ error('Cannot require a meta file')
---Information about the client
---
---@since 3.15.0
----@field clientInfo? lsp._anonym11.clientInfo
+---@field clientInfo? lsp.ClientInfo
---
---The locale the client is currently showing the user interface
---in. This must not necessarily be the locale of the operating
@@ -2380,7 +2428,7 @@ error('Cannot require a meta file')
---@field initializationOptions? lsp.LSPAny
---
---The initial trace setting. If omitted trace is disabled ('off').
----@field trace? lsp.TraceValues
+---@field trace? lsp.TraceValue
---@class lsp.WorkspaceFoldersInitializeParams
---
@@ -2534,18 +2582,24 @@ error('Cannot require a meta file')
---@proposed
---@field inlineCompletionProvider? boolean|lsp.InlineCompletionOptions
---
----Text document specific server capabilities.
----
----@since 3.18.0
----@proposed
----@field textDocument? lsp._anonym12.textDocument
----
---Workspace specific server capabilities.
----@field workspace? lsp._anonym14.workspace
+---@field workspace? lsp.WorkspaceOptions
---
---Experimental server capabilities.
---@field experimental? lsp.LSPAny
+---Information about the server
+---
+---@since 3.15.0
+---@since 3.18.0 ServerInfo type name added.
+---@class lsp.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
+
---A text document identifier to denote a specific version of a text document.
---@class lsp.VersionedTextDocumentIdentifier: lsp.TextDocumentIdentifier
---
@@ -2586,8 +2640,9 @@ error('Cannot require a meta file')
---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.
+---The diagnostic's severity. To avoid interpretation mismatches when a
+---server is used with different clients it is highly recommended that servers
+---always provide a severity value.
---@field severity? lsp.DiagnosticSeverity
---
---The diagnostic's code, which usually appear in the user interface.
@@ -2604,10 +2659,8 @@ error('Cannot require a meta file')
---appears in the user interface.
---@field source? string
---
----The diagnostic's message. It usually appears in the user interface.
----
----@since 3.18.0 - support for `MarkupContent`. This is guarded by the client capability `textDocument.diagnostic.markupMessageSupport`.
----@field message string|lsp.MarkupContent
+---The diagnostic's message. It usually appears in the user interface
+---@field message string
---
---Additional metadata about the diagnostic.
---
@@ -2661,6 +2714,46 @@ error('Cannot require a meta file')
---The range if the replace is requested.
---@field replace lsp.Range
+---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
+---be used if a completion item itself doesn't specify the value.
+---
+---If a completion list specifies a default value and a completion item
+---also specifies a corresponding value the one from the item is used.
+---
+---Servers are only allowed to return default values if the client
+---signals support for this via the `completionList.itemDefaults`
+---capability.
+---
+---@since 3.17.0
+---@class lsp.CompletionItemDefaults
+---
+---A default commit character set.
+---
+---@since 3.17.0
+---@field commitCharacters? string[]
+---
+---A default edit range.
+---
+---@since 3.17.0
+---@field editRange? lsp.Range|lsp.EditRangeWithInsertReplace
+---
+---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
+
---Completion options.
---@class lsp.CompletionOptions: lsp.WorkDoneProgressOptions
---
@@ -2692,7 +2785,7 @@ error('Cannot require a meta file')
---capabilities.
---
---@since 3.17.0
----@field completionItem? lsp._anonym15.completionItem
+---@field completionItem? lsp.ServerCompletionItemOptions
---Hover options.
---@class lsp.HoverOptions: lsp.WorkDoneProgressOptions
@@ -2742,7 +2835,7 @@ error('Cannot require a meta file')
---
---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
+---if the client specifies the client capability
---`textDocument.signatureHelp.noActiveParameterSupport === true`
---
---If provided (or `null`), this is used in place of
@@ -2819,8 +2912,6 @@ error('Cannot require a meta file')
---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.
----
----Note that the client should check the `textDocument.diagnostic.markupMessageSupport` server capability before sending diagnostics with markup messages to a server.
---@field diagnostics lsp.Diagnostic[]
---
---Requested kind of actions to return.
@@ -2834,6 +2925,16 @@ error('Cannot require a meta file')
---@since 3.17.0
---@field triggerKind? lsp.CodeActionTriggerKind
+---Captures why the code action is currently disabled.
+---
+---@since 3.18.0
+---@class lsp.CodeActionDisabled
+---
+---Human readable description of why the code action is currently disabled.
+---
+---This is displayed in the code actions UI.
+---@field reason string
+
---Provider options for a {@link CodeActionRequest}.
---@class lsp.CodeActionOptions: lsp.WorkDoneProgressOptions
---
@@ -2843,12 +2944,36 @@ error('Cannot require a meta file')
---may list out every specific kind they provide.
---@field codeActionKinds? lsp.CodeActionKind[]
---
+---Static documentation for a class of code actions.
+---
+---Documentation from the provider should be shown in the code actions menu if either:
+---
+---- Code actions of `kind` are requested by the editor. In this case, the editor will show the documentation that
+--- most closely matches the requested code action kind. For example, if a provider has documentation for
+--- both `Refactor` and `RefactorExtract`, when the user requests code actions for `RefactorExtract`,
+--- the editor will use the documentation for `RefactorExtract` instead of the documentation for `Refactor`.
+---
+---- Any code actions of `kind` are returned by the provider.
+---
+---At most one documentation entry should be shown per provider.
+---
+---@since 3.18.0
+---@proposed
+---@field documentation? lsp.CodeActionKindDocumentation[]
+---
---The server provides support to resolve additional
---information for a code action.
---
---@since 3.16.0
---@field resolveProvider? boolean
+---Location with only uri and does not include range.
+---
+---@since 3.18.0
+---@class lsp.LocationUriOnly
+---
+---@field uri lsp.DocumentUri
+
---Server capabilities for a {@link WorkspaceSymbolRequest}.
---@class lsp.WorkspaceSymbolOptions: lsp.WorkDoneProgressOptions
---
@@ -2923,12 +3048,33 @@ error('Cannot require a meta file')
---@since version 3.12.0
---@field prepareProvider? boolean
+---@since 3.18.0
+---@class lsp.PrepareRenamePlaceholder
+---
+---@field range lsp.Range
+---
+---@field placeholder string
+
+---@since 3.18.0
+---@class lsp.PrepareRenameDefaultBehavior
+---
+---@field defaultBehavior boolean
+
---The server capabilities of a {@link ExecuteCommandRequest}.
---@class lsp.ExecuteCommandOptions: lsp.WorkDoneProgressOptions
---
---The commands to be executed on the server
---@field commands string[]
+---Additional data about a workspace edit.
+---
+---@since 3.18.0
+---@proposed
+---@class lsp.WorkspaceEditMetadata
+---
+---Signal to the editor that this edit is a refactoring.
+---@field isRefactoring? boolean
+
---@since 3.16.0
---@class lsp.SemanticTokensLegend
---
@@ -2938,6 +3084,14 @@ error('Cannot require a meta file')
---The token modifiers a server uses.
---@field tokenModifiers string[]
+---Semantic tokens options to support deltas for full documents
+---
+---@since 3.18.0
+---@class lsp.SemanticTokensFullDelta
+---
+---The server supports deltas for full documents.
+---@field delta? boolean
+
---A text document identifier to optionally denote a specific version of a text document.
---@class lsp.OptionalVersionedTextDocumentIdentifier: lsp.TextDocumentIdentifier
---
@@ -2956,6 +3110,21 @@ error('Cannot require a meta file')
---The actual identifier of the change annotation
---@field annotationId lsp.ChangeAnnotationIdentifier
+---An interactive text edit.
+---
+---@since 3.18.0
+---@proposed
+---@class lsp.SnippetTextEdit
+---
+---The range of the text document to be manipulated.
+---@field range lsp.Range
+---
+---The snippet to be inserted.
+---@field snippet lsp.StringValue
+---
+---The actual identifier of the snippet edit.
+---@field annotationId? lsp.ChangeAnnotationIdentifier
+
---A generic resource operation.
---@class lsp.ResourceOperation
---
@@ -3066,20 +3235,43 @@ error('Cannot require a meta file')
---if supported by the client.
---@field executionSummary? lsp.ExecutionSummary
----A change describing how to move a `NotebookCell`
----array from state S to S'.
+---@since 3.18.0
+---@class lsp.NotebookDocumentFilterWithNotebook
---
----@since 3.17.0
----@class lsp.NotebookCellArrayChange
+---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 start oftest of the cell that changed.
----@field start uinteger
+---The cells of the matching notebook to be synced.
+---@field cells? lsp.NotebookCellLanguage[]
+
+---@since 3.18.0
+---@class lsp.NotebookDocumentFilterWithCells
---
----The deleted cells
----@field deleteCount uinteger
+---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 new cells, if any
----@field cells? lsp.NotebookCell[]
+---The cells of the matching notebook to be synced.
+---@field cells lsp.NotebookCellLanguage[]
+
+---Cell changes to a notebook document.
+---
+---@since 3.18.0
+---@class lsp.NotebookDocumentCellChanges
+---
+---Changes to the cell structure to add or
+---remove cells.
+---@field structure? lsp.NotebookDocumentCellChangeStructure
+---
+---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? lsp.NotebookDocumentCellContentChanges[]
---Describes the currently selected completion item.
---
@@ -3093,6 +3285,18 @@ error('Cannot require a meta file')
---The text the range will be replaced with if this completion is accepted.
---@field text string
+---Information about the client
+---
+---@since 3.15.0
+---@since 3.18.0 ClientInfo type name added.
+---@class lsp.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
+
---Defines the capabilities provided by the client.
---@class lsp.ClientCapabilities
---
@@ -3140,69 +3344,40 @@ error('Cannot require a meta file')
---sent.
---@field save? boolean|lsp.SaveOptions
----Options specific to a notebook plus its cells
----to be synced to the server.
+---Defines workspace specific capabilities of the server.
---
----If a selector provides a notebook document
----filter but no cell selector all cells of a
----matching notebook document will be synced.
+---@since 3.18.0
+---@class lsp.WorkspaceOptions
---
----If a selector provides no notebook document
----filter but only a cell selector all notebook
----document that contain at least one matching
----cell will be synced.
+---The server supports workspace folder.
---
----@since 3.17.0
----@class lsp.NotebookDocumentSyncOptions
+---@since 3.6.0
+---@field workspaceFolders? lsp.WorkspaceFoldersServerCapabilities
---
----The notebooks to be synced
----@field notebookSelector (lsp._anonym16.notebookSelector|lsp._anonym18.notebookSelector)[]
+---The server is interested in notifications/requests for operations on files.
---
----Whether save notification should be forwarded to
----the server. Will only be honored if mode === `notebook`.
----@field save? boolean
+---@since 3.16.0
+---@field fileOperations? lsp.FileOperationOptions
----Registration options specific to a notebook.
+---@since 3.18.0
+---@class lsp.TextDocumentContentChangePartial
---
----@since 3.17.0
----@class lsp.NotebookDocumentSyncRegistrationOptions: lsp.NotebookDocumentSyncOptions, lsp.StaticRegistrationOptions
-
----@class lsp.WorkspaceFoldersServerCapabilities
+---The range of the document that changed.
+---@field range lsp.Range
---
----The server has support for workspace folders
----@field supported? boolean
+---The optional length of the range that got replaced.
---
----Whether the server wants to receive workspace folder
----change notifications.
+---@deprecated use range instead.
+---@field rangeLength? uinteger
---
----If a string is provided the string is treated as an ID
----under which the notification is registered on the client
----side. The ID can be used to unregister for these events
----using the `client/unregisterCapability` request.
----@field changeNotifications? string|boolean
+---The new text for the provided range.
+---@field text string
----Options for notifications/requests for user operations on files.
----
----@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
+---@since 3.18.0
+---@class lsp.TextDocumentContentChangeWholeDocument
---
----The server is interested in receiving willDeleteFiles file requests.
----@field willDelete? lsp.FileOperationRegistrationOptions
+---The new text of the whole document.
+---@field text string
---Structure to capture a description for an error code.
---
@@ -3223,6 +3398,33 @@ error('Cannot require a meta file')
---The message of this related diagnostic information.
---@field message string
+---Edit range variant that includes ranges for insert and replace operations.
+---
+---@since 3.18.0
+---@class lsp.EditRangeWithInsertReplace
+---
+---@field insert lsp.Range
+---
+---@field replace lsp.Range
+
+---@since 3.18.0
+---@class lsp.ServerCompletionItemOptions
+---
+---The server has support for completion item label
+---details (see also `CompletionItemLabelDetails`) when
+---receiving a completion item in a resolve call.
+---
+---@since 3.17.0
+---@field labelDetailsSupport? boolean
+
+---@since 3.18.0
+---@deprecated use MarkupContent instead.
+---@class lsp.MarkedStringWithLanguage
+---
+---@field language string
+---
+---@field value string
+
---Represents a parameter of a callable-signature. A parameter can
---have a label and a doc-comment.
---@class lsp.ParameterInformation
@@ -3233,14 +3435,36 @@ error('Cannot require a meta file')
---signature label. (see SignatureInformation.label). The offsets are based on a UTF-16
---string representation as `Position` and `Range` does.
---
+---To avoid ambiguities a server should use the [start, end] offset value instead of using
+---a substring. Whether a client support this is controlled via `labelOffsetSupport` client
+---capability.
+---
---*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 }
+---@field label string|[uinteger, uinteger]
---
---The human-readable doc-comment of this parameter. Will be shown
---in the UI but can be omitted.
---@field documentation? string|lsp.MarkupContent
+---Documentation for a class of code actions.
+---
+---@since 3.18.0
+---@proposed
+---@class lsp.CodeActionKindDocumentation
+---
+---The kind of the code action being documented.
+---
+---If the kind is generic, such as `CodeActionKind.Refactor`, the documentation will be shown whenever any
+---refactorings are returned. If the kind if more specific, such as `CodeActionKind.RefactorExtract`, the
+---documentation will only be shown when extract refactoring code actions are returned.
+---@field kind lsp.CodeActionKind
+---
+---Command that is ued to display the documentation to the user.
+---
+---The title of this documentation code action is taken from {@linkcode Command.title}
+---@field command lsp.Command
+
---A notebook cell text document filter denotes a cell text
---document by different properties.
---
@@ -3278,6 +3502,34 @@ error('Cannot require a meta file')
---not if known by the client.
---@field success? boolean
+---@since 3.18.0
+---@class lsp.NotebookCellLanguage
+---
+---@field language string
+
+---Structural changes to cells in a notebook document.
+---
+---@since 3.18.0
+---@class lsp.NotebookDocumentCellChangeStructure
+---
+---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[]
+
+---Content changes to a cell in a notebook document.
+---
+---@since 3.18.0
+---@class lsp.NotebookDocumentCellContentChanges
+---
+---@field document lsp.VersionedTextDocumentIdentifier
+---
+---@field changes lsp.TextDocumentContentChangeEvent[]
+
---Workspace specific client capabilities.
---@class lsp.WorkspaceClientCapabilities
---
@@ -3524,7 +3776,7 @@ error('Cannot require a meta file')
---anymore since the information is outdated).
---
---@since 3.17.0
----@field staleRequestSupport? lsp._anonym20.staleRequestSupport
+---@field staleRequestSupport? lsp.StaleRequestSupportOptions
---
---Client capabilities specific to regular expressions.
---
@@ -3556,6 +3808,43 @@ error('Cannot require a meta file')
---@since 3.17.0
---@field positionEncodings? lsp.PositionEncodingKind[]
+---@class lsp.WorkspaceFoldersServerCapabilities
+---
+---The server has support for workspace folders
+---@field supported? boolean
+---
+---Whether the server wants to receive workspace folder
+---change notifications.
+---
+---If a string is provided the string is treated as an ID
+---under which the notification is registered on the client
+---side. The ID can be used to unregister for these events
+---using the `client/unregisterCapability` request.
+---@field changeNotifications? string|boolean
+
+---Options for notifications/requests for user operations on files.
+---
+---@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
+
---A relative pattern is a helper to construct glob patterns that are matched
---relatively to a base URI. The common value for a `baseUri` is a workspace
---folder root, but it can be another absolute URI as well.
@@ -3570,6 +3859,111 @@ error('Cannot require a meta file')
---The actual glob pattern;
---@field pattern lsp.Pattern
+---A document filter where `language` is required field.
+---
+---@since 3.18.0
+---@class lsp.TextDocumentFilterLanguage
+---
+---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.
+---
+---@since 3.18.0 - support for relative patterns.
+---@field pattern? lsp.GlobPattern
+
+---A document filter where `scheme` is required field.
+---
+---@since 3.18.0
+---@class lsp.TextDocumentFilterScheme
+---
+---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.
+---
+---@since 3.18.0 - support for relative patterns.
+---@field pattern? lsp.GlobPattern
+
+---A document filter where `pattern` is required field.
+---
+---@since 3.18.0
+---@class lsp.TextDocumentFilterPattern
+---
+---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.
+---
+---@since 3.18.0 - support for relative patterns.
+---@field pattern lsp.GlobPattern
+
+---A notebook document filter where `notebookType` is required field.
+---
+---@since 3.18.0
+---@class lsp.NotebookDocumentFilterNotebookType
+---
+---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? lsp.GlobPattern
+
+---A notebook document filter where `scheme` is required field.
+---
+---@since 3.18.0
+---@class lsp.NotebookDocumentFilterScheme
+---
+---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? lsp.GlobPattern
+
+---A notebook document filter where `pattern` is required field.
+---
+---@since 3.18.0
+---@class lsp.NotebookDocumentFilterPattern
+---
+---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 lsp.GlobPattern
+
+---A change describing how to move a `NotebookCell`
+---array from state S to S'.
+---
+---@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[]
+
---@class lsp.WorkspaceEditClientCapabilities
---
---The client supports versioned document changes in `WorkspaceEdit`s
@@ -3600,7 +3994,19 @@ error('Cannot require a meta file')
---create file, rename file and delete file changes.
---
---@since 3.16.0
----@field changeAnnotationSupport? lsp._anonym21.changeAnnotationSupport
+---@field changeAnnotationSupport? lsp.ChangeAnnotationsSupportOptions
+---
+---Whether the client supports `WorkspaceEditMetadata` in `WorkspaceEdit`s.
+---
+---@since 3.18.0
+---@proposed
+---@field metadataSupport? boolean
+---
+---Whether the client supports snippets as text edits.
+---
+---@since 3.18.0
+---@proposed
+---@field snippetEditSupport? boolean
---@class lsp.DidChangeConfigurationClientCapabilities
---
@@ -3627,20 +4033,20 @@ error('Cannot require a meta file')
---@field dynamicRegistration? boolean
---
---Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
----@field symbolKind? lsp._anonym22.symbolKind
+---@field symbolKind? lsp.ClientSymbolKindOptions
---
---The client supports tags on `SymbolInformation`.
---Clients supporting tags have to handle unknown tags gracefully.
---
---@since 3.16.0
----@field tagSupport? lsp._anonym23.tagSupport
+---@field tagSupport? lsp.ClientSymbolTagOptions
---
---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? lsp._anonym24.resolveSupport
+---@field resolveSupport? lsp.ClientSymbolResolveOptions
---The client capabilities of a {@link ExecuteCommandRequest}.
---@class lsp.ExecuteCommandClientCapabilities
@@ -3785,9 +4191,9 @@ error('Cannot require a meta file')
---
---The client supports the following `CompletionItem` specific
---capabilities.
----@field completionItem? lsp._anonym25.completionItem
+---@field completionItem? lsp.ClientCompletionItemOptions
---
----@field completionItemKind? lsp._anonym29.completionItemKind
+---@field completionItemKind? lsp.ClientCompletionItemOptionsKind
---
---Defines how the client handles whitespace and indentation
---when accepting a completion item that uses multi line
@@ -3804,7 +4210,7 @@ error('Cannot require a meta file')
---capabilities.
---
---@since 3.17.0
----@field completionList? lsp._anonym30.completionList
+---@field completionList? lsp.CompletionListCapabilities
---@class lsp.HoverClientCapabilities
---
@@ -3823,7 +4229,7 @@ error('Cannot require a meta file')
---
---The client supports the following `SignatureInformation`
---specific properties.
----@field signatureInformation? lsp._anonym31.signatureInformation
+---@field signatureInformation? lsp.ClientSignatureInformationOptions
---
---The client supports to send additional context information for a
---`textDocument/signatureHelp` request. A client that opts into
@@ -3901,7 +4307,7 @@ error('Cannot require a meta file')
---
---Specific capabilities for the `SymbolKind` in the
---`textDocument/documentSymbol` request.
----@field symbolKind? lsp._anonym33.symbolKind
+---@field symbolKind? lsp.ClientSymbolKindOptions
---
---The client supports hierarchical document symbols.
---@field hierarchicalDocumentSymbolSupport? boolean
@@ -3911,7 +4317,7 @@ error('Cannot require a meta file')
---Clients supporting tags have to handle unknown tags gracefully.
---
---@since 3.16.0
----@field tagSupport? lsp._anonym34.tagSupport
+---@field tagSupport? lsp.ClientSymbolTagOptions
---
---The client supports an additional label presented in the UI when
---registering a document symbol provider.
@@ -3930,7 +4336,7 @@ error('Cannot require a meta file')
---set the request can only return `Command` literals.
---
---@since 3.8.0
----@field codeActionLiteralSupport? lsp._anonym35.codeActionLiteralSupport
+---@field codeActionLiteralSupport? lsp.ClientCodeActionLiteralOptions
---
---Whether code action supports the `isPreferred` property.
---
@@ -3953,7 +4359,7 @@ error('Cannot require a meta file')
---properties via a separate `codeAction/resolve` request.
---
---@since 3.16.0
----@field resolveSupport? lsp._anonym37.resolveSupport
+---@field resolveSupport? lsp.ClientCodeActionResolveOptions
---
---Whether the client honors the change annotations in
---text edits and resource operations returned via the
@@ -3963,12 +4369,25 @@ error('Cannot require a meta file')
---
---@since 3.16.0
---@field honorsChangeAnnotations? boolean
+---
+---Whether the client supports documentation for a class of
+---code actions.
+---
+---@since 3.18.0
+---@proposed
+---@field documentationSupport? boolean
---The client capabilities of a {@link CodeLensRequest}.
---@class lsp.CodeLensClientCapabilities
---
---Whether code lens supports dynamic registration.
---@field dynamicRegistration? boolean
+---
+---Whether the client supports resolving additional code lens
+---properties via a separate `codeLens/resolve` request.
+---
+---@since 3.18.0
+---@field resolveSupport? lsp.ClientCodeLensResolveOptions
---The client capabilities of a {@link DocumentLinkRequest}.
---@class lsp.DocumentLinkClientCapabilities
@@ -4061,12 +4480,12 @@ error('Cannot require a meta file')
---Specific options for the folding range kind.
---
---@since 3.17.0
----@field foldingRangeKind? lsp._anonym38.foldingRangeKind
+---@field foldingRangeKind? lsp.ClientFoldingRangeKindOptions
---
---Specific options for the folding range.
---
---@since 3.17.0
----@field foldingRange? lsp._anonym39.foldingRange
+---@field foldingRange? lsp.ClientFoldingRangeOptions
---@class lsp.SelectionRangeClientCapabilities
---
@@ -4076,34 +4495,13 @@ error('Cannot require a meta file')
---@field dynamicRegistration? boolean
---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? lsp._anonym40.tagSupport
+---@class lsp.PublishDiagnosticsClientCapabilities: lsp.DiagnosticsCapabilities
---
---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.
----
----@since 3.16.0
----@field dataSupport? boolean
---@since 3.16.0
---@class lsp.CallHierarchyClientCapabilities
@@ -4129,7 +4527,7 @@ 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 lsp._anonym41.requests
+---@field requests lsp.ClientSemanticTokensRequestOptions
---
---The token types that the client supports.
---@field tokenTypes string[]
@@ -4212,12 +4610,12 @@ error('Cannot require a meta file')
---
---Indicates which properties a client can resolve lazily on an inlay
---hint.
----@field resolveSupport? lsp._anonym44.resolveSupport
+---@field resolveSupport? lsp.ClientInlayHintResolveOptions
---Client capabilities specific to diagnostic pull requests.
---
---@since 3.17.0
----@class lsp.DiagnosticClientCapabilities
+---@class lsp.DiagnosticClientCapabilities: lsp.DiagnosticsCapabilities
---
---Whether implementation supports dynamic registration. If this is set to `true`
---the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
@@ -4226,9 +4624,6 @@ error('Cannot require a meta file')
---
---Whether the clients supports related documents for document diagnostic pulls.
---@field relatedDocumentSupport? boolean
----
----Whether the client supports `MarkupContent` in diagnostic messages.
----@field markupMessageSupport? boolean
---Client capabilities specific to inline completions.
---
@@ -4257,7 +4652,7 @@ error('Cannot require a meta file')
---@class lsp.ShowMessageRequestClientCapabilities
---
---Capabilities specific to the `MessageActionItem` type.
----@field messageActionItem? lsp._anonym45.messageActionItem
+---@field messageActionItem? lsp.ClientShowMessageActionItemOptions
---Client capabilities for the showDocument request.
---
@@ -4268,13 +4663,24 @@ error('Cannot require a meta file')
---request.
---@field support boolean
+---@since 3.18.0
+---@class lsp.StaleRequestSupportOptions
+---
+---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[]
+
---Client capabilities specific to regular expressions.
---
---@since 3.16.0
---@class lsp.RegularExpressionsClientCapabilities
---
---The engine's name.
----@field engine string
+---@field engine lsp.RegularExpressionEngineKind
---
---The engine's version.
---@field version? string
@@ -4296,6 +4702,285 @@ error('Cannot require a meta file')
---@since 3.17.0
---@field allowedTags? string[]
+---@since 3.18.0
+---@class lsp.ChangeAnnotationsSupportOptions
+---
+---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
+
+---@since 3.18.0
+---@class lsp.ClientSymbolKindOptions
+---
+---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
+---to a default value when unknown.
+---
+---If this property is not present the client only supports
+---the symbol kinds from `File` to `Array` as defined in
+---the initial version of the protocol.
+---@field valueSet? lsp.SymbolKind[]
+
+---@since 3.18.0
+---@class lsp.ClientSymbolTagOptions
+---
+---The tags supported by the client.
+---@field valueSet lsp.SymbolTag[]
+
+---@since 3.18.0
+---@class lsp.ClientSymbolResolveOptions
+---
+---The properties that a client can resolve lazily. Usually
+---`location.range`
+---@field properties string[]
+
+---@since 3.18.0
+---@class lsp.ClientCompletionItemOptions
+---
+---Client supports snippets as insert text.
+---
+---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. 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? lsp.CompletionItemTagOptions
+---
+---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? lsp.ClientCompletionItemResolveOptions
+---
+---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? lsp.ClientCompletionItemInsertTextModeOptions
+---
+---The client has support for completion item label
+---details (see also `CompletionItemLabelDetails`).
+---
+---@since 3.17.0
+---@field labelDetailsSupport? boolean
+
+---@since 3.18.0
+---@class lsp.ClientCompletionItemOptionsKind
+---
+---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
+---to a default value when unknown.
+---
+---If this property is not present the client only supports
+---the completion items kinds from `Text` to `Reference` as defined in
+---the initial version of the protocol.
+---@field valueSet? lsp.CompletionItemKind[]
+
+---The client supports the following `CompletionList` specific
+---capabilities.
+---
+---@since 3.17.0
+---@class lsp.CompletionListCapabilities
+---
+---The client supports the following itemDefaults on
+---a completion list.
+---
+---The value lists the supported property names of the
+---`CompletionList.itemDefaults` object. If omitted
+---no properties are supported.
+---
+---@since 3.17.0
+---@field itemDefaults? string[]
+
+---@since 3.18.0
+---@class lsp.ClientSignatureInformationOptions
+---
+---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? lsp.ClientSignatureParameterInformationOptions
+---
+---The client supports the `activeParameter` property on `SignatureInformation`
+---literal.
+---
+---@since 3.16.0
+---@field activeParameterSupport? boolean
+---
+---The client supports the `activeParameter` property on
+---`SignatureHelp`/`SignatureInformation` being set to `null` to
+---indicate that no parameter should be active.
+---
+---@since 3.18.0
+---@proposed
+---@field noActiveParameterSupport? boolean
+
+---@since 3.18.0
+---@class lsp.ClientCodeActionLiteralOptions
+---
+---The code action kind is support with the following value
+---set.
+---@field codeActionKind lsp.ClientCodeActionKindOptions
+
+---@since 3.18.0
+---@class lsp.ClientCodeActionResolveOptions
+---
+---The properties that a client can resolve lazily.
+---@field properties string[]
+
+---@since 3.18.0
+---@class lsp.ClientCodeLensResolveOptions
+---
+---The properties that a client can resolve lazily.
+---@field properties string[]
+
+---@since 3.18.0
+---@class lsp.ClientFoldingRangeKindOptions
+---
+---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[]
+
+---@since 3.18.0
+---@class lsp.ClientFoldingRangeOptions
+---
+---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
+
+---General diagnostics capabilities for pull and push model.
+---@class lsp.DiagnosticsCapabilities
+---
+---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? lsp.ClientDiagnosticsTagOptions
+---
+---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.
+---
+---@since 3.16.0
+---@field dataSupport? boolean
+
+---@since 3.18.0
+---@class lsp.ClientSemanticTokensRequestOptions
+---
+---The client will send the `textDocument/semanticTokens/range` request if
+---the server provides a corresponding handler.
+---@field range? boolean|lsp._anonym2.range
+---
+---The client will send the `textDocument/semanticTokens/full` request if
+---the server provides a corresponding handler.
+---@field full? boolean|lsp.ClientSemanticTokensRequestFullDelta
+
+---@since 3.18.0
+---@class lsp.ClientInlayHintResolveOptions
+---
+---The properties that a client can resolve lazily.
+---@field properties string[]
+
+---@since 3.18.0
+---@class lsp.ClientShowMessageActionItemOptions
+---
+---Whether the client supports additional attributes which
+---are preserved and send back to the server in the
+---request's response.
+---@field additionalPropertiesSupport? boolean
+
+---@since 3.18.0
+---@class lsp.CompletionItemTagOptions
+---
+---The tags supported by the client.
+---@field valueSet lsp.CompletionItemTag[]
+
+---@since 3.18.0
+---@class lsp.ClientCompletionItemResolveOptions
+---
+---The properties that a client can resolve lazily.
+---@field properties string[]
+
+---@since 3.18.0
+---@class lsp.ClientCompletionItemInsertTextModeOptions
+---
+---@field valueSet lsp.InsertTextMode[]
+
+---@since 3.18.0
+---@class lsp.ClientSignatureParameterInformationOptions
+---
+---The client supports processing label offsets instead of a
+---simple label string.
+---
+---@since 3.14.0
+---@field labelOffsetSupport? boolean
+
+---@since 3.18.0
+---@class lsp.ClientCodeActionKindOptions
+---
+---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[]
+
+---@since 3.18.0
+---@class lsp.ClientDiagnosticsTagOptions
+---
+---The tags supported by the client.
+---@field valueSet lsp.DiagnosticTag[]
+
+---@since 3.18.0
+---@class lsp.ClientSemanticTokensRequestFullDelta
+---
+---The client will send the `textDocument/semanticTokens/full/delta` request if
+---the server provides a corresponding handler.
+---@field delta? boolean
+
---A set of predefined token types. This set is not fixed
---an clients can specify additional token types via the
---corresponding client capabilities.
@@ -4325,6 +5010,7 @@ error('Cannot require a meta file')
---| "regexp" # regexp
---| "operator" # operator
---| "decorator" # decorator
+---| "label" # label
---A set of predefined token modifiers. This set is not fixed
---an clients can specify additional token types via the
@@ -4515,12 +5201,14 @@ error('Cannot require a meta file')
---| "refactor" # Refactor
---| "refactor.extract" # RefactorExtract
---| "refactor.inline" # RefactorInline
+---| "refactor.move" # RefactorMove
---| "refactor.rewrite" # RefactorRewrite
---| "source" # Source
---| "source.organizeImports" # SourceOrganizeImports
---| "source.fixAll" # SourceFixAll
+---| "notebook" # Notebook
----@alias lsp.TraceValues
+---@alias lsp.TraceValue
---| "off" # Off
---| "messages" # Messages
---| "verbose" # Verbose
@@ -4534,13 +5222,79 @@ error('Cannot require a meta file')
---| "plaintext" # PlainText
---| "markdown" # Markdown
+---Predefined Language kinds
+---@since 3.18.0
+---@proposed
+---@alias lsp.LanguageKind
+---| "abap" # ABAP
+---| "bat" # WindowsBat
+---| "bibtex" # BibTeX
+---| "clojure" # Clojure
+---| "coffeescript" # Coffeescript
+---| "c" # C
+---| "cpp" # CPP
+---| "csharp" # CSharp
+---| "css" # CSS
+---| "d" # D
+---| "pascal" # Delphi
+---| "diff" # Diff
+---| "dart" # Dart
+---| "dockerfile" # Dockerfile
+---| "elixir" # Elixir
+---| "erlang" # Erlang
+---| "fsharp" # FSharp
+---| "git-commit" # GitCommit
+---| "rebase" # GitRebase
+---| "go" # Go
+---| "groovy" # Groovy
+---| "handlebars" # Handlebars
+---| "haskell" # Haskell
+---| "html" # HTML
+---| "ini" # Ini
+---| "java" # Java
+---| "javascript" # JavaScript
+---| "javascriptreact" # JavaScriptReact
+---| "json" # JSON
+---| "latex" # LaTeX
+---| "less" # Less
+---| "lua" # Lua
+---| "makefile" # Makefile
+---| "markdown" # Markdown
+---| "objective-c" # ObjectiveC
+---| "objective-cpp" # ObjectiveCPP
+---| "pascal" # Pascal
+---| "perl" # Perl
+---| "perl6" # Perl6
+---| "php" # PHP
+---| "powershell" # Powershell
+---| "jade" # Pug
+---| "python" # Python
+---| "r" # R
+---| "razor" # Razor
+---| "ruby" # Ruby
+---| "rust" # Rust
+---| "scss" # SCSS
+---| "sass" # SASS
+---| "scala" # Scala
+---| "shaderlab" # ShaderLab
+---| "shellscript" # ShellScript
+---| "sql" # SQL
+---| "swift" # Swift
+---| "typescript" # TypeScript
+---| "typescriptreact" # TypeScriptReact
+---| "tex" # TeX
+---| "vb" # VisualBasic
+---| "xml" # XML
+---| "xsl" # XSL
+---| "yaml" # YAML
+
---Describes how an {@link InlineCompletionItemProvider inline completion provider} was triggered.
---
---@since 3.18.0
---@proposed
---@alias lsp.InlineCompletionTriggerKind
----| 0 # Invoked
----| 1 # Automatic
+---| 1 # Invoked
+---| 2 # Automatic
---A set of predefined position encoding kinds.
---
@@ -4684,7 +5438,7 @@ error('Cannot require a meta file')
---@since 3.17.0
---@alias lsp.DocumentDiagnosticReport lsp.RelatedFullDocumentDiagnosticReport|lsp.RelatedUnchangedDocumentDiagnosticReport
----@alias lsp.PrepareRenameResult lsp.Range|lsp._anonym46.PrepareRenameResult|lsp._anonym47.PrepareRenameResult
+---@alias lsp.PrepareRenameResult lsp.Range|lsp.PrepareRenamePlaceholder|lsp.PrepareRenameDefaultBehavior
---A document selector is the combination of one or many document filters.
---
@@ -4705,7 +5459,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 lsp._anonym48.TextDocumentContentChangeEvent|lsp._anonym49.TextDocumentContentChangeEvent
+---@alias lsp.TextDocumentContentChangeEvent lsp.TextDocumentContentChangePartial|lsp.TextDocumentContentChangeWholeDocument
---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
@@ -4719,7 +5473,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|lsp._anonym50.MarkedString
+---@alias lsp.MarkedString string|lsp.MarkedStringWithLanguage
---A document filter describes a top level text document or
---a notebook cell document.
@@ -4752,14 +5506,14 @@ error('Cannot require a meta file')
---\@sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }`
---
---@since 3.17.0
----@alias lsp.TextDocumentFilter lsp._anonym51.TextDocumentFilter|lsp._anonym52.TextDocumentFilter|lsp._anonym53.TextDocumentFilter
+---@alias lsp.TextDocumentFilter lsp.TextDocumentFilterLanguage|lsp.TextDocumentFilterScheme|lsp.TextDocumentFilterPattern
---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 lsp._anonym54.NotebookDocumentFilter|lsp._anonym55.NotebookDocumentFilter|lsp._anonym56.NotebookDocumentFilter
+---@alias lsp.NotebookDocumentFilter lsp.NotebookDocumentFilterNotebookType|lsp.NotebookDocumentFilterScheme|lsp.NotebookDocumentFilterPattern
---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
@@ -4772,512 +5526,8 @@ error('Cannot require a meta file')
---@since 3.17.0
---@alias lsp.Pattern string
----@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 lsp._anonym3.itemDefaults.editRange
----
----@field insert lsp.Range
----
----@field replace lsp.Range
-
----@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|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 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 lsp._anonym5.location
----
----@field uri lsp.DocumentUri
-
----@class lsp._anonym6.range
-
----@class lsp._anonym7.full
----
----The server supports deltas for full documents.
----@field delta? boolean
-
----@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 lsp._anonym10.cells.textContent
----
----@field document lsp.VersionedTextDocumentIdentifier
----
----@field changes lsp.TextDocumentContentChangeEvent[]
-
----@class lsp._anonym8.cells
----
----Changes to the cell structure to add or
----remove cells.
----@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? lsp._anonym10.cells.textContent[]
-
----@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 lsp._anonym13.textDocument.diagnostic
----
----Whether the server supports `MarkupContent` in diagnostic messages.
----@field markupMessageSupport? boolean
-
----@class lsp._anonym12.textDocument
----
----Capabilities specific to the diagnostic pull model.
----
----@since 3.18.0
----@field diagnostic? lsp._anonym13.textDocument.diagnostic
-
----@class lsp._anonym14.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 lsp._anonym15.completionItem
----
----The server has support for completion item label
----details (see also `CompletionItemLabelDetails`) when
----receiving a completion item in a resolve call.
----
----@since 3.17.0
----@field labelDetailsSupport? boolean
-
----@class lsp._anonym17.notebookSelector.cells
----
----@field language string
-
----@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? lsp._anonym17.notebookSelector.cells[]
-
----@class lsp._anonym19.notebookSelector.cells
----
----@field language string
-
----@class lsp._anonym18.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 lsp._anonym19.notebookSelector.cells[]
-
----@class lsp._anonym20.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 lsp._anonym21.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
+---@alias lsp.RegularExpressionEngineKind string
----@class lsp._anonym22.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
----to a default value when unknown.
----
----If this property is not present the client only supports
----the symbol kinds from `File` to `Array` as defined in
----the initial version of the protocol.
----@field valueSet? lsp.SymbolKind[]
+---@class lsp._anonym1.range
----@class lsp._anonym23.tagSupport
----
----The tags supported by the client.
----@field valueSet lsp.SymbolTag[]
-
----@class lsp._anonym24.resolveSupport
----
----The properties that a client can resolve lazily. Usually
----`location.range`
----@field properties string[]
-
----@class lsp._anonym26.completionItem.tagSupport
----
----The tags supported by the client.
----@field valueSet lsp.CompletionItemTag[]
-
----@class lsp._anonym27.completionItem.resolveSupport
----
----The properties that a client can resolve lazily.
----@field properties string[]
-
----@class lsp._anonym28.completionItem.insertTextModeSupport
----
----@field valueSet lsp.InsertTextMode[]
-
----@class lsp._anonym25.completionItem
----
----Client supports snippets as insert text.
----
----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. 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? lsp._anonym26.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? lsp._anonym27.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? lsp._anonym28.completionItem.insertTextModeSupport
----
----The client has support for completion item label
----details (see also `CompletionItemLabelDetails`).
----
----@since 3.17.0
----@field labelDetailsSupport? boolean
-
----@class lsp._anonym29.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
----to a default value when unknown.
----
----If this property is not present the client only supports
----the completion items kinds from `Text` to `Reference` as defined in
----the initial version of the protocol.
----@field valueSet? lsp.CompletionItemKind[]
-
----@class lsp._anonym30.completionList
----
----The client supports the following itemDefaults on
----a completion list.
----
----The value lists the supported property names of the
----`CompletionList.itemDefaults` object. If omitted
----no properties are supported.
----
----@since 3.17.0
----@field itemDefaults? string[]
-
----@class lsp._anonym32.signatureInformation.parameterInformation
----
----The client supports processing label offsets instead of a
----simple label string.
----
----@since 3.14.0
----@field labelOffsetSupport? boolean
-
----@class lsp._anonym31.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? lsp._anonym32.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.
----
----@since 3.18.0
----@field noActiveParameterSupport? boolean
-
----@class lsp._anonym33.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
----to a default value when unknown.
----
----If this property is not present the client only supports
----the symbol kinds from `File` to `Array` as defined in
----the initial version of the protocol.
----@field valueSet? lsp.SymbolKind[]
-
----@class lsp._anonym34.tagSupport
----
----The tags supported by the client.
----@field valueSet lsp.SymbolTag[]
-
----@class lsp._anonym36.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 lsp._anonym35.codeActionLiteralSupport
----
----The code action kind is support with the following value
----set.
----@field codeActionKind lsp._anonym36.codeActionLiteralSupport.codeActionKind
-
----@class lsp._anonym37.resolveSupport
----
----The properties that a client can resolve lazily.
----@field properties string[]
-
----@class lsp._anonym38.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 lsp._anonym39.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 lsp._anonym40.tagSupport
----
----The tags supported by the client.
----@field valueSet lsp.DiagnosticTag[]
-
----@class lsp._anonym42.requests.range
-
----@class lsp._anonym43.requests.full
----
----The client will send the `textDocument/semanticTokens/full/delta` request if
----the server provides a corresponding handler.
----@field delta? boolean
-
----@class lsp._anonym41.requests
----
----The client will send the `textDocument/semanticTokens/range` request if
----the server provides a corresponding handler.
----@field range? boolean|lsp._anonym42.requests.range
----
----The client will send the `textDocument/semanticTokens/full` request if
----the server provides a corresponding handler.
----@field full? boolean|lsp._anonym43.requests.full
-
----@class lsp._anonym44.resolveSupport
----
----The properties that a client can resolve lazily.
----@field properties string[]
-
----@class lsp._anonym45.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 lsp._anonym46.PrepareRenameResult
----
----@field range lsp.Range
----
----@field placeholder string
-
----@class lsp._anonym47.PrepareRenameResult
----
----@field defaultBehavior boolean
-
----@class lsp._anonym48.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 lsp._anonym49.TextDocumentContentChangeEvent
----
----The new text of the whole document.
----@field text string
-
----@class lsp._anonym50.MarkedString
----
----@field language string
----
----@field value string
-
----@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.
----@field pattern? string
-
----@class lsp._anonym52.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.
----@field pattern? string
-
----@class lsp._anonym53.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.
----@field pattern string
-
----@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
-
----@class lsp._anonym55.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 lsp._anonym56.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 lsp._anonym2.range
diff --git a/runtime/lua/vim/lsp/_watchfiles.lua b/runtime/lua/vim/lsp/_watchfiles.lua
index 49328fbe9b..98e9818bcd 100644
--- a/runtime/lua/vim/lsp/_watchfiles.lua
+++ b/runtime/lua/vim/lsp/_watchfiles.lua
@@ -9,8 +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
+elseif vim.fn.executable('inotifywait') == 1 then
+ M._watchfunc = watch.inotify
else
M._watchfunc = watch.watchdirs
end
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 49833eaeec..301c1f0cb6 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -29,7 +29,12 @@ local function request(method, params, handler)
end
--- Displays hover information about the symbol under the cursor in a floating
---- window. Calling the function twice will jump into the floating window.
+--- window. The window will be dismissed on cursor move.
+--- Calling the function twice will jump into the floating window
+--- (thus by default, "KK" will open the hover window and focus it).
+--- In the floating window, all commands and mappings are available as usual,
+--- except that "q" dismisses the window.
+--- You can scroll the contents the same as you would any other buffer.
function M.hover()
local params = util.make_position_params()
request(ms.textDocument_hover, params)
@@ -135,7 +140,7 @@ end
---@param mode "v"|"V"
---@return table {start={row,col}, end={row,col}} using (1, 0) indexing
local function range_from_selection(bufnr, mode)
- -- TODO: Use `vim.region()` instead https://github.com/neovim/neovim/pull/13896
+ -- TODO: Use `vim.fn.getregionpos()` instead.
-- [bufnum, lnum, col, off]; both row and column 1-indexed
local start = vim.fn.getpos('v')
@@ -205,9 +210,11 @@ end
--- Range to format.
--- Table must contain `start` and `end` keys with {row,col} tuples using
--- (1,0) indexing.
+--- Can also be a list of tables that contain `start` and `end` keys as described above,
+--- in which case `textDocument/rangesFormatting` support is required.
--- (Default: current selection in visual mode, `nil` in other modes,
--- formatting the full buffer)
---- @field range? {start:integer[],end:integer[]}
+--- @field range? {start:[integer,integer],end:[integer, integer]}|{start:[integer,integer],end:[integer,integer]}[]
--- Formats a buffer using the attached (and optionally filtered) language
--- server clients.
@@ -218,10 +225,20 @@ function M.format(opts)
local bufnr = opts.bufnr or api.nvim_get_current_buf()
local mode = api.nvim_get_mode().mode
local range = opts.range
+ -- Try to use visual selection if no range is given
if not range and mode == 'v' or mode == 'V' then
range = range_from_selection(bufnr, mode)
end
- local method = range and ms.textDocument_rangeFormatting or ms.textDocument_formatting
+
+ local passed_multiple_ranges = (range and #range ~= 0 and type(range[1]) == 'table')
+ local method ---@type string
+ if passed_multiple_ranges then
+ method = ms.textDocument_rangesFormatting
+ elseif range then
+ method = ms.textDocument_rangeFormatting
+ else
+ method = ms.textDocument_formatting
+ end
local clients = vim.lsp.get_clients({
id = opts.id,
@@ -241,10 +258,14 @@ function M.format(opts)
--- @param params lsp.DocumentFormattingParams
--- @return lsp.DocumentFormattingParams
local function set_range(client, params)
- if range then
- local range_params =
- util.make_given_range_params(range.start, range['end'], bufnr, client.offset_encoding)
- params.range = range_params.range
+ local to_lsp_range = function(r) ---@return lsp.DocumentRangeFormattingParams|lsp.DocumentRangesFormattingParams
+ return util.make_given_range_params(r.start, r['end'], bufnr, client.offset_encoding).range
+ end
+
+ if passed_multiple_ranges then
+ params.ranges = vim.tbl_map(to_lsp_range, range)
+ elseif range then
+ params.range = to_lsp_range(range)
end
return params
end
@@ -431,11 +452,9 @@ function M.document_symbol(opts)
request_with_opts(ms.textDocument_documentSymbol, params, opts)
end
---- @param call_hierarchy_items lsp.CallHierarchyItem[]?
+--- @param call_hierarchy_items lsp.CallHierarchyItem[]
+--- @return lsp.CallHierarchyItem?
local function pick_call_hierarchy_item(call_hierarchy_items)
- if not call_hierarchy_items then
- return
- end
if #call_hierarchy_items == 1 then
return call_hierarchy_items[1]
end
@@ -448,7 +467,7 @@ local function pick_call_hierarchy_item(call_hierarchy_items)
if choice < 1 or choice > #items then
return
end
- return choice
+ return call_hierarchy_items[choice]
end
--- @param method string
@@ -460,7 +479,7 @@ local function call_hierarchy(method)
vim.notify(err.message, vim.log.levels.WARN)
return
end
- if not result then
+ if not result or vim.tbl_isempty(result) then
vim.notify('No item resolved', vim.log.levels.WARN)
return
end
@@ -836,14 +855,10 @@ function M.code_action(opts)
if opts.diagnostics or opts.only then
opts = { options = opts }
end
- local context = opts.context or {}
+ local context = opts.context and vim.deepcopy(opts.context) or {}
if not context.triggerKind then
context.triggerKind = vim.lsp.protocol.CodeActionTriggerKind.Invoked
end
- if not context.diagnostics then
- local bufnr = api.nvim_get_current_buf()
- context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr)
- end
local mode = api.nvim_get_mode().mode
local bufnr = api.nvim_get_current_buf()
local win = api.nvim_get_current_win()
@@ -885,7 +900,23 @@ function M.code_action(opts)
else
params = util.make_range_params(win, client.offset_encoding)
end
- params.context = context
+ if context.diagnostics then
+ params.context = context
+ else
+ local ns_push = vim.lsp.diagnostic.get_namespace(client.id, false)
+ local ns_pull = vim.lsp.diagnostic.get_namespace(client.id, true)
+ local diagnostics = {}
+ local lnum = api.nvim_win_get_cursor(0)[1] - 1
+ vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_pull, lnum = lnum }))
+ vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_push, lnum = lnum }))
+ params.context = vim.tbl_extend('force', context, {
+ ---@diagnostic disable-next-line: no-unknown
+ diagnostics = vim.tbl_map(function(d)
+ return d.user_data.lsp
+ end, diagnostics),
+ })
+ end
+
client.request(ms.textDocument_codeAction, params, on_result, bufnr)
end
end
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index 4beb7fefda..e3c82f4169 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -182,7 +182,7 @@ local validate = vim.validate
--- It can be `null` if the client supports workspace folders but none are
--- configured.
--- @field workspace_folders lsp.WorkspaceFolder[]?
---- @field root_dir string
+--- @field root_dir string?
---
--- @field attached_buffers table<integer,true>
---
@@ -233,11 +233,11 @@ local validate = vim.validate
---
--- 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`
+--- Returns: { err=err, result=result }, a dict, 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
+--- @field request_sync fun(method: string, params: table?, timeout_ms: integer?, bufnr: integer): {err: lsp.ResponseError|nil, result:any}|nil, string|nil err # a dict
---
--- Sends a notification to an LSP server.
--- Returns: a boolean to indicate if the notification was successful. If
@@ -436,7 +436,7 @@ local function ensure_list(x)
return { x }
end
---- @package
+--- @nodoc
--- @param config vim.lsp.ClientConfig
--- @return vim.lsp.Client?
function Client.create(config)
@@ -470,7 +470,6 @@ function Client.create(config)
_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.
@@ -536,7 +535,7 @@ function Client:_run_callbacks(cbs, error_id, ...)
end
end
---- @package
+--- @nodoc
function Client:initialize()
local config = self.config
@@ -657,7 +656,7 @@ end
--- @param method string LSP method name.
--- @param params? table LSP request params.
--- @param handler? lsp.Handler Response |lsp-handler| for this method.
---- @param bufnr? integer Buffer handle (0 for current).
+--- @param bufnr integer Buffer handle (0 for current).
--- @return boolean status, integer? 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
@@ -739,7 +738,7 @@ end
--- @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
+--- @return {err: lsp.ResponseError|nil, result:any}|nil, string|nil err # a dict, 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
@@ -862,14 +861,14 @@ function Client:_is_stopped()
return self.rpc.is_closing()
end
---- @package
--- 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)
+--- @param on_unsupported? function handler invoked when the command is not supported by the client.
+function Client:_exec_cmd(command, context, handler, on_unsupported)
context = vim.deepcopy(context or {}, true) --[[@as lsp.HandlerContext]]
context.bufnr = context.bufnr or api.nvim_get_current_buf()
context.client_id = self.id
@@ -883,14 +882,18 @@ function Client:_exec_cmd(command, context, handler)
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
- )
+ if on_unsupported then
+ on_unsupported()
+ else
+ 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
+ )
+ end
return
end
-- Not using command directly to exclude extra properties,
@@ -902,7 +905,6 @@ function Client:_exec_cmd(command, context, handler)
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
@@ -914,18 +916,16 @@ function Client:_text_document_did_open_handler(bufnr)
if not api.nvim_buf_is_loaded(bufnr) then
return
end
- local filetype = vim.bo[bufnr].filetype
- local params = {
+ local filetype = vim.bo[bufnr].filetype
+ self.notify(ms.textDocument_didOpen, {
textDocument = {
- version = 0,
+ version = lsp.util.buf_versions[bufnr],
uri = vim.uri_from_bufnr(bufnr),
languageId = self.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()
@@ -938,7 +938,6 @@ function Client:_text_document_did_open_handler(bufnr)
end)
end
---- @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)
@@ -1061,7 +1060,6 @@ function Client:_on_exit(code, signal)
)
end
---- @package
--- Add a directory to the workspace folders.
--- @param dir string?
function Client:_add_workspace_folder(dir)
@@ -1084,7 +1082,6 @@ function Client:_add_workspace_folder(dir)
vim.list_extend(self.workspace_folders, wf)
end
---- @package
--- Remove a directory to the workspace folders.
--- @param dir string?
function Client:_remove_workspace_folder(dir)
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index c85bb6aa32..c1b6bfb28c 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -307,7 +307,13 @@ function M.refresh(opts)
}
active_refreshes[buf] = true
- local request_ids = vim.lsp.buf_request(buf, ms.textDocument_codeLens, params, M.on_codelens)
+ local request_ids = vim.lsp.buf_request(
+ buf,
+ ms.textDocument_codeLens,
+ params,
+ M.on_codelens,
+ function() end
+ )
if vim.tbl_isempty(request_ids) then
active_refreshes[buf] = nil
end
diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua
new file mode 100644
index 0000000000..71ea2df100
--- /dev/null
+++ b/runtime/lua/vim/lsp/completion.lua
@@ -0,0 +1,754 @@
+local M = {}
+
+local api = vim.api
+local lsp = vim.lsp
+local protocol = lsp.protocol
+local ms = protocol.Methods
+
+local rtt_ms = 50
+local ns_to_ms = 0.000001
+
+--- @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).
+--- @nodoc
+--- @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
+
+--- @nodoc
+--- @class vim.lsp.completion.BufHandle
+--- @field clients table<integer, vim.lsp.Client>
+--- @field triggers table<string, vim.lsp.Client[]>
+--- @field convert? fun(item: lsp.CompletionItem): table
+
+--- @type table<integer, vim.lsp.completion.BufHandle>
+local buf_handles = {}
+
+--- @nodoc
+--- @class vim.lsp.completion.Context
+local Context = {
+ cursor = nil, --- @type [integer, integer]?
+ last_request_time = nil, --- @type integer?
+ pending_requests = {}, --- @type function[]
+ isIncomplete = false,
+}
+
+--- @nodoc
+function Context:cancel_pending()
+ for _, cancel in ipairs(self.pending_requests) do
+ cancel()
+ end
+
+ self.pending_requests = {}
+end
+
+--- @nodoc
+function Context:reset()
+ -- Note that the cursor isn't reset here, it needs to survive a `CompleteDone` event.
+ self.isIncomplete = false
+ self.last_request_time = nil
+ self:cancel_pending()
+end
+
+--- @type uv.uv_timer_t?
+local completion_timer = nil
+
+--- @return uv.uv_timer_t
+local function new_timer()
+ return assert(vim.uv.new_timer())
+end
+
+local function reset_timer()
+ if completion_timer then
+ completion_timer:stop()
+ completion_timer:close()
+ end
+
+ completion_timer = nil
+end
+
+--- @param window integer
+--- @param warmup integer
+--- @return fun(sample: number): number
+local function exp_avg(window, warmup)
+ local count = 0
+ local sum = 0
+ local value = 0
+
+ return function(sample)
+ if count < warmup then
+ count = count + 1
+ sum = sum + sample
+ value = sum / count
+ else
+ local factor = 2.0 / (window + 1)
+ value = value * (1 - factor) + sample * factor
+ end
+ return value
+ end
+end
+local compute_new_average = exp_avg(10, 10)
+
+--- @return number
+local function next_debounce()
+ if not Context.last_request_time then
+ return rtt_ms
+ end
+
+ local ms_since_request = (vim.uv.hrtime() - Context.last_request_time) * ns_to_ms
+ return math.max((ms_since_request - rtt_ms) * -1, 0)
+end
+
+--- @param input string Unparsed snippet
+--- @return string # Parsed snippet if successful, else returns its input
+local function parse_snippet(input)
+ local ok, parsed = pcall(function()
+ return lsp._snippet_grammar.parse(input)
+ end)
+ return ok and tostring(parsed) or input
+end
+
+--- @param item lsp.CompletionItem
+--- @param suffix? string
+local function apply_snippet(item, suffix)
+ if item.textEdit then
+ vim.snippet.expand(item.textEdit.newText .. suffix)
+ elseif item.insertText then
+ vim.snippet.expand(item.insertText .. suffix)
+ end
+end
+
+--- Returns text that should be inserted when a selecting completion item. The
+--- precedence is as follows: textEdit.newText > insertText > label
+---
+--- See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+---
+--- @param item lsp.CompletionItem
+--- @return string
+local function get_completion_word(item)
+ if item.insertTextFormat == protocol.InsertTextFormat.Snippet then
+ if item.textEdit then
+ -- Use label instead of text if text has different starting characters.
+ -- label is used as abbr (=displayed), but word is used for filtering
+ -- This is required for things like postfix completion.
+ -- E.g. in lua:
+ --
+ -- local f = {}
+ -- f@|
+ -- ▲
+ -- └─ cursor
+ --
+ -- item.textEdit.newText: table.insert(f, $0)
+ -- label: insert
+ --
+ -- Typing `i` would remove the candidate because newText starts with `t`.
+ local text = parse_snippet(item.insertText or item.textEdit.newText)
+ return #text < #item.label and vim.fn.matchstr(text, '\\k*') or item.label
+ elseif item.insertText and item.insertText ~= '' then
+ return parse_snippet(item.insertText)
+ else
+ return item.label
+ end
+ elseif item.textEdit then
+ local word = item.textEdit.newText
+ return word:match('^(%S*)') or word
+ elseif item.insertText and item.insertText ~= '' then
+ return item.insertText
+ end
+ 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 or item.label
+ 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
+ -- When we have a list, apply the defaults and return an array of items.
+ for _, item in ipairs(result.items) do
+ ---@diagnostic disable-next-line: param-type-mismatch
+ apply_defaults(item, result.itemDefaults)
+ end
+ return result.items
+ else
+ -- Else just return the items as they are.
+ return result
+ end
+end
+
+---@param item lsp.CompletionItem
+---@return string
+local function get_doc(item)
+ local doc = item.documentation
+ if not doc then
+ return ''
+ end
+ if type(doc) == 'string' then
+ return doc
+ end
+ if type(doc) == 'table' and type(doc.value) == 'string' then
+ return doc.value
+ end
+
+ vim.notify('invalid documentation value: ' .. vim.inspect(doc), vim.log.levels.WARN)
+ return ''
+end
+
+--- Turns the result of a `textDocument/completion` request into vim-compatible
+--- |complete-items|.
+---
+--- @private
+--- @param result vim.lsp.CompletionResult Result of `textDocument/completion`
+--- @param prefix string prefix to filter the completion items
+--- @param client_id integer? Client ID
+--- @return table[]
+--- @see complete-items
+function M._lsp_to_complete_items(result, prefix, client_id)
+ local items = get_items(result)
+ if vim.tbl_isempty(items) then
+ return {}
+ end
+
+ ---@type fun(item: lsp.CompletionItem):boolean
+ local matches
+ if not prefix:find('%w') then
+ matches = function(_)
+ return true
+ end
+ else
+ ---@param item lsp.CompletionItem
+ matches = function(item)
+ local text = item.filterText or item.label
+ return next(vim.fn.matchfuzzy({ text }, prefix)) ~= nil
+ end
+ end
+
+ local candidates = {}
+ local bufnr = api.nvim_get_current_buf()
+ local user_convert = vim.tbl_get(buf_handles, bufnr, 'convert')
+ for _, item in ipairs(items) do
+ if matches(item) then
+ local word = get_completion_word(item)
+ local hl_group = ''
+ if
+ item.deprecated
+ or vim.list_contains((item.tags or {}), protocol.CompletionTag.Deprecated)
+ then
+ hl_group = 'DiagnosticDeprecated'
+ end
+ local completion_item = {
+ word = word,
+ abbr = item.label,
+ kind = protocol.CompletionItemKind[item.kind] or 'Unknown',
+ menu = item.detail or '',
+ info = get_doc(item),
+ icase = 1,
+ dup = 1,
+ empty = 1,
+ hl_group = hl_group,
+ user_data = {
+ nvim = {
+ lsp = {
+ completion_item = item,
+ client_id = client_id,
+ },
+ },
+ },
+ }
+ if user_convert then
+ completion_item = vim.tbl_extend('keep', user_convert(item), completion_item)
+ end
+ table.insert(candidates, completion_item)
+ end
+ end
+ ---@diagnostic disable-next-line: no-unknown
+ table.sort(candidates, function(a, b)
+ ---@type lsp.CompletionItem
+ local itema = a.user_data.nvim.lsp.completion_item
+ ---@type lsp.CompletionItem
+ local itemb = b.user_data.nvim.lsp.completion_item
+ return (itema.sortText or itema.label) < (itemb.sortText or itemb.label)
+ end)
+
+ return candidates
+end
+
+--- @param lnum integer 0-indexed
+--- @param line string
+--- @param items lsp.CompletionItem[]
+--- @param encoding string
+--- @return integer?
+local function adjust_start_col(lnum, line, items, encoding)
+ local min_start_char = nil
+ for _, item in pairs(items) do
+ if item.textEdit and item.textEdit.range.start.line == lnum then
+ if min_start_char and min_start_char ~= item.textEdit.range.start.character then
+ return nil
+ end
+ min_start_char = item.textEdit.range.start.character
+ end
+ end
+ if min_start_char then
+ return lsp.util._str_byteindex_enc(line, min_start_char, encoding)
+ else
+ return nil
+ end
+end
+
+--- @private
+--- @param line string line content
+--- @param lnum integer 0-indexed line number
+--- @param cursor_col integer
+--- @param client_id integer client ID
+--- @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 vim.lsp.CompletionResult
+--- @param encoding string
+--- @return table[] matches
+--- @return integer? server_start_boundary
+function M._convert_results(
+ line,
+ lnum,
+ cursor_col,
+ client_id,
+ client_start_boundary,
+ server_start_boundary,
+ result,
+ encoding
+)
+ -- Completion response items may be relative to a position different than `client_start_boundary`.
+ -- Concrete example, with lua-language-server:
+ --
+ -- require('plenary.asy|
+ -- ▲ ▲ ▲
+ -- │ │ └── cursor_pos: 20
+ -- │ └────── client_start_boundary: 17
+ -- └────────────── textEdit.range.start.character: 9
+ -- .newText = 'plenary.async'
+ -- ^^^
+ -- prefix (We'd remove everything not starting with `asy`,
+ -- so we'd eliminate the `plenary.async` result
+ --
+ -- `adjust_start_col` is used to prefer the language server boundary.
+ --
+ local candidates = get_items(result)
+ local curstartbyte = adjust_start_col(lnum, line, candidates, encoding)
+ if server_start_boundary == nil then
+ server_start_boundary = curstartbyte
+ elseif curstartbyte ~= nil and curstartbyte ~= server_start_boundary then
+ server_start_boundary = client_start_boundary
+ end
+ local prefix = line:sub((server_start_boundary or client_start_boundary) + 1, cursor_col)
+ local matches = M._lsp_to_complete_items(result, prefix, client_id)
+ return matches, server_start_boundary
+end
+
+--- @param clients table<integer, vim.lsp.Client> # keys != client_id
+--- @param bufnr integer
+--- @param win integer
+--- @param callback fun(responses: table<integer, { err: lsp.ResponseError, result: vim.lsp.CompletionResult }>)
+--- @return function # Cancellation function
+local function request(clients, bufnr, win, callback)
+ local responses = {} --- @type table<integer, { err: lsp.ResponseError, result: any }>
+ local request_ids = {} --- @type table<integer, integer>
+ local remaining_requests = vim.tbl_count(clients)
+
+ for _, client in pairs(clients) do
+ local client_id = client.id
+ local params = lsp.util.make_position_params(win, client.offset_encoding)
+ local ok, request_id = client.request(ms.textDocument_completion, params, function(err, result)
+ responses[client_id] = { err = err, result = result }
+ remaining_requests = remaining_requests - 1
+ if remaining_requests == 0 then
+ callback(responses)
+ end
+ end, bufnr)
+
+ if ok then
+ request_ids[client_id] = request_id
+ end
+ end
+
+ return function()
+ for client_id, request_id in pairs(request_ids) do
+ local client = lsp.get_client_by_id(client_id)
+ if client then
+ client.cancel_request(request_id)
+ end
+ end
+ end
+end
+
+local function trigger(bufnr, clients)
+ reset_timer()
+ Context:cancel_pending()
+
+ if tonumber(vim.fn.pumvisible()) == 1 and not Context.isIncomplete then
+ return
+ end
+
+ local win = api.nvim_get_current_win()
+ local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer
+ local line = api.nvim_get_current_line()
+ local line_to_cursor = line:sub(1, cursor_col)
+ local word_boundary = vim.fn.match(line_to_cursor, '\\k*$')
+ local start_time = vim.uv.hrtime()
+ Context.last_request_time = start_time
+
+ local cancel_request = request(clients, bufnr, win, function(responses)
+ local end_time = vim.uv.hrtime()
+ rtt_ms = compute_new_average((end_time - start_time) * ns_to_ms)
+
+ Context.pending_requests = {}
+ Context.isIncomplete = false
+
+ local row_changed = api.nvim_win_get_cursor(win)[1] ~= cursor_row
+ local mode = api.nvim_get_mode().mode
+ if row_changed or not (mode == 'i' or mode == 'ic') then
+ return
+ end
+
+ local matches = {}
+ local server_start_boundary --- @type integer?
+ for client_id, response in pairs(responses) do
+ if response.err then
+ vim.notify_once(response.err.message, vim.log.levels.warn)
+ end
+
+ local result = response.result
+ if result then
+ Context.isIncomplete = Context.isIncomplete or result.isIncomplete
+ local client = lsp.get_client_by_id(client_id)
+ local encoding = client and client.offset_encoding or 'utf-16'
+ local client_matches
+ client_matches, server_start_boundary = M._convert_results(
+ line,
+ cursor_row - 1,
+ cursor_col,
+ client_id,
+ word_boundary,
+ nil,
+ result,
+ encoding
+ )
+ vim.list_extend(matches, client_matches)
+ end
+ end
+ local start_col = (server_start_boundary or word_boundary) + 1
+ vim.fn.complete(start_col, matches)
+ end)
+
+ table.insert(Context.pending_requests, cancel_request)
+end
+
+--- @param handle vim.lsp.completion.BufHandle
+local function on_insert_char_pre(handle)
+ if tonumber(vim.fn.pumvisible()) == 1 then
+ if Context.isIncomplete then
+ reset_timer()
+
+ local debounce_ms = next_debounce()
+ if debounce_ms == 0 then
+ vim.schedule(M.trigger)
+ else
+ completion_timer = new_timer()
+ completion_timer:start(debounce_ms, 0, vim.schedule_wrap(M.trigger))
+ end
+ end
+
+ return
+ end
+
+ local char = api.nvim_get_vvar('char')
+ if not completion_timer and handle.triggers[char] then
+ completion_timer = assert(vim.uv.new_timer())
+ completion_timer:start(25, 0, function()
+ reset_timer()
+ vim.schedule(M.trigger)
+ end)
+ end
+end
+
+local function on_insert_leave()
+ reset_timer()
+ Context.cursor = nil
+ Context:reset()
+end
+
+local function on_complete_done()
+ local completed_item = api.nvim_get_vvar('completed_item')
+ if not completed_item or not completed_item.user_data or not completed_item.user_data.nvim then
+ Context:reset()
+ return
+ end
+
+ local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(0)) --- @type integer, integer
+ cursor_row = cursor_row - 1
+ local completion_item = completed_item.user_data.nvim.lsp.completion_item --- @type lsp.CompletionItem
+ local client_id = completed_item.user_data.nvim.lsp.client_id --- @type integer
+ if not completion_item or not client_id then
+ Context:reset()
+ return
+ end
+
+ local bufnr = api.nvim_get_current_buf()
+ local expand_snippet = completion_item.insertTextFormat == protocol.InsertTextFormat.Snippet
+ and (completion_item.textEdit ~= nil or completion_item.insertText ~= nil)
+
+ Context:reset()
+
+ local client = lsp.get_client_by_id(client_id)
+ if not client then
+ return
+ end
+
+ local offset_encoding = client.offset_encoding or 'utf-16'
+ local resolve_provider = (client.server_capabilities.completionProvider or {}).resolveProvider
+
+ local function clear_word()
+ if not expand_snippet then
+ return nil
+ end
+
+ -- Remove the already inserted word.
+ local start_char = cursor_col - #completed_item.word
+ local line = api.nvim_buf_get_lines(bufnr, cursor_row, cursor_row + 1, true)[1]
+ api.nvim_buf_set_text(bufnr, cursor_row, start_char, cursor_row, #line, { '' })
+ return line:sub(cursor_col + 1)
+ end
+
+ --- @param suffix? string
+ local function apply_snippet_and_command(suffix)
+ if expand_snippet then
+ apply_snippet(completion_item, suffix)
+ end
+
+ local command = completion_item.command
+ if command then
+ client:_exec_cmd(command, { bufnr = bufnr }, nil, function()
+ vim.lsp.log.warn(
+ string.format(
+ 'Language server `%s` does not support command `%s`. This command may require a client extension.',
+ client.name,
+ command.command
+ )
+ )
+ end)
+ end
+ end
+
+ if completion_item.additionalTextEdits and next(completion_item.additionalTextEdits) then
+ local suffix = clear_word()
+ lsp.util.apply_text_edits(completion_item.additionalTextEdits, bufnr, offset_encoding)
+ apply_snippet_and_command(suffix)
+ elseif resolve_provider and type(completion_item) == 'table' then
+ local changedtick = vim.b[bufnr].changedtick
+
+ --- @param result lsp.CompletionItem
+ client.request(ms.completionItem_resolve, completion_item, function(err, result)
+ if changedtick ~= vim.b[bufnr].changedtick then
+ return
+ end
+
+ local suffix = clear_word()
+ if err then
+ vim.notify_once(err.message, vim.log.levels.WARN)
+ elseif result and result.additionalTextEdits then
+ lsp.util.apply_text_edits(result.additionalTextEdits, bufnr, offset_encoding)
+ if result.command then
+ completion_item.command = result.command
+ end
+ end
+
+ apply_snippet_and_command(suffix)
+ end, bufnr)
+ else
+ local suffix = clear_word()
+ apply_snippet_and_command(suffix)
+ end
+end
+
+--- @class vim.lsp.completion.BufferOpts
+--- @field autotrigger? boolean Whether to trigger completion automatically. Default: false
+--- @field convert? fun(item: lsp.CompletionItem): table Transforms an LSP CompletionItem to |complete-items|.
+
+---@param client_id integer
+---@param bufnr integer
+---@param opts vim.lsp.completion.BufferOpts
+local function enable_completions(client_id, bufnr, opts)
+ local buf_handle = buf_handles[bufnr]
+ if not buf_handle then
+ buf_handle = { clients = {}, triggers = {}, convert = opts.convert }
+ buf_handles[bufnr] = buf_handle
+
+ -- Attach to buffer events.
+ api.nvim_buf_attach(bufnr, false, {
+ on_detach = function(_, buf)
+ buf_handles[buf] = nil
+ end,
+ on_reload = function(_, buf)
+ M.enable(true, client_id, buf, opts)
+ end,
+ })
+
+ -- Set up autocommands.
+ local group =
+ api.nvim_create_augroup(string.format('vim/lsp/completion-%d', bufnr), { clear = true })
+ api.nvim_create_autocmd('CompleteDone', {
+ group = group,
+ buffer = bufnr,
+ callback = function()
+ local reason = api.nvim_get_vvar('event').reason --- @type string
+ if reason == 'accept' then
+ on_complete_done()
+ end
+ end,
+ })
+ if opts.autotrigger then
+ api.nvim_create_autocmd('InsertCharPre', {
+ group = group,
+ buffer = bufnr,
+ callback = function()
+ on_insert_char_pre(buf_handles[bufnr])
+ end,
+ })
+ api.nvim_create_autocmd('InsertLeave', {
+ group = group,
+ buffer = bufnr,
+ callback = on_insert_leave,
+ })
+ end
+ end
+
+ if not buf_handle.clients[client_id] then
+ local client = lsp.get_client_by_id(client_id)
+ assert(client, 'invalid client ID')
+
+ -- Add the new client to the buffer's clients.
+ buf_handle.clients[client_id] = client
+
+ -- Add the new client to the clients that should be triggered by its trigger characters.
+ --- @type string[]
+ local triggers = vim.tbl_get(
+ client.server_capabilities,
+ 'completionProvider',
+ 'triggerCharacters'
+ ) or {}
+ for _, char in ipairs(triggers) do
+ local clients_for_trigger = buf_handle.triggers[char]
+ if not clients_for_trigger then
+ clients_for_trigger = {}
+ buf_handle.triggers[char] = clients_for_trigger
+ end
+ local client_exists = vim.iter(clients_for_trigger):any(function(c)
+ return c.id == client_id
+ end)
+ if not client_exists then
+ table.insert(clients_for_trigger, client)
+ end
+ end
+ end
+end
+
+--- @param client_id integer
+--- @param bufnr integer
+local function disable_completions(client_id, bufnr)
+ local handle = buf_handles[bufnr]
+ if not handle then
+ return
+ end
+
+ handle.clients[client_id] = nil
+ if not next(handle.clients) then
+ buf_handles[bufnr] = nil
+ api.nvim_del_augroup_by_name(string.format('vim/lsp/completion-%d', bufnr))
+ else
+ for char, clients in pairs(handle.triggers) do
+ --- @param c vim.lsp.Client
+ handle.triggers[char] = vim.tbl_filter(function(c)
+ return c.id ~= client_id
+ end, clients)
+ end
+ end
+end
+
+--- Enables or disables completions from the given language client in the given buffer.
+---
+--- @param enable boolean True to enable, false to disable
+--- @param client_id integer Client ID
+--- @param bufnr integer Buffer handle, or 0 for the current buffer
+--- @param opts? vim.lsp.completion.BufferOpts
+function M.enable(enable, client_id, bufnr, opts)
+ bufnr = (bufnr == 0 and api.nvim_get_current_buf()) or bufnr
+
+ if enable then
+ enable_completions(client_id, bufnr, opts or {})
+ else
+ disable_completions(client_id, bufnr)
+ end
+end
+
+--- Trigger LSP completion in the current buffer.
+function M.trigger()
+ local bufnr = api.nvim_get_current_buf()
+ local clients = (buf_handles[bufnr] or {}).clients or {}
+ trigger(bufnr, clients)
+end
+
+--- Implements 'omnifunc' compatible LSP completion.
+---
+--- @see |complete-functions|
+--- @see |complete-items|
+--- @see |CompleteDone|
+---
+--- @param findstart integer 0 or 1, decides behavior
+--- @param base integer findstart=0, text to match against
+---
+--- @return integer|table Decided by {findstart}:
+--- - findstart=0: column where the completion starts, or -2 or -3
+--- - findstart=1: list of matches (actually just calls |complete()|)
+function M._omnifunc(findstart, base)
+ vim.lsp.log.debug('omnifunc.findstart', { findstart = findstart, base = base })
+ assert(base) -- silence luals
+ local bufnr = api.nvim_get_current_buf()
+ local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion })
+ local remaining = #clients
+ if remaining == 0 then
+ return findstart == 1 and -1 or {}
+ end
+
+ trigger(bufnr, clients)
+
+ -- Return -2 to signal that we should continue completion so that we can
+ -- async complete.
+ return -2
+end
+
+return M
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index 08cea13548..c10312484b 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -110,6 +110,14 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)
return vim.tbl_map(function(diagnostic)
local start = diagnostic.range.start
local _end = diagnostic.range['end']
+ local message = diagnostic.message
+ if type(message) ~= 'string' then
+ vim.notify_once(
+ string.format('Unsupported Markup message from LSP client %d', client_id),
+ vim.lsp.log_levels.ERROR
+ )
+ message = diagnostic.message.value
+ end
--- @type vim.Diagnostic
return {
lnum = start.line,
@@ -117,18 +125,12 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)
end_lnum = _end.line,
end_col = line_byte_from_position(buf_lines, _end.line, _end.character, offset_encoding),
severity = severity_lsp_to_vim(diagnostic.severity),
- message = diagnostic.message,
+ message = message,
source = diagnostic.source,
code = diagnostic.code,
_tags = tags_lsp_to_vim(diagnostic, client_id),
user_data = {
- lsp = {
- -- usage of user_data.lsp.code is deprecated in favor of the top-level code field
- code = diagnostic.code,
- codeDescription = diagnostic.codeDescription,
- relatedInformation = diagnostic.relatedInformation,
- data = diagnostic.data,
- },
+ lsp = diagnostic,
},
}
end, diagnostics)
@@ -151,14 +153,18 @@ local function tags_vim_to_lsp(diagnostic)
return tags
end
+--- Converts the input `vim.Diagnostic`s to LSP diagnostics.
--- @param diagnostics vim.Diagnostic[]
--- @return lsp.Diagnostic[]
-local function diagnostic_vim_to_lsp(diagnostics)
+function M.from(diagnostics)
---@param diagnostic vim.Diagnostic
---@return lsp.Diagnostic
return vim.tbl_map(function(diagnostic)
- return vim.tbl_extend('keep', {
- -- "keep" the below fields over any duplicate fields in diagnostic.user_data.lsp
+ local user_data = diagnostic.user_data or {}
+ if user_data.lsp then
+ return user_data.lsp
+ end
+ return {
range = {
start = {
line = diagnostic.lnum,
@@ -174,7 +180,7 @@ local function diagnostic_vim_to_lsp(diagnostics)
source = diagnostic.source,
code = diagnostic.code,
tags = tags_vim_to_lsp(diagnostic),
- }, diagnostic.user_data and (diagnostic.user_data.lsp or {}) or {})
+ }
end, diagnostics)
end
@@ -366,6 +372,7 @@ end
--- Structured: { [1] = {...}, [5] = {.... } }
---@private
function M.get_line_diagnostics(bufnr, line_nr, opts, client_id)
+ vim.deprecate('vim.lsp.diagnostic.get_line_diagnostics', 'vim.diagnostic.get', '0.12')
convert_severity(opts)
local diag_opts = {} --- @type vim.diagnostic.GetOpts
@@ -379,7 +386,7 @@ function M.get_line_diagnostics(bufnr, line_nr, opts, client_id)
diag_opts.lnum = line_nr or (api.nvim_win_get_cursor(0)[1] - 1)
- return diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, diag_opts))
+ return M.from(vim.diagnostic.get(bufnr, diag_opts))
end
--- Clear diagnostics from pull based clients
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index f9d394642c..44548fec92 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -3,7 +3,7 @@ local protocol = require('vim.lsp.protocol')
local ms = protocol.Methods
local util = require('vim.lsp.util')
local api = vim.api
-local completion = require('vim.lsp._completion')
+local completion = require('vim.lsp.completion')
--- @type table<string,lsp.Handler>
local M = {}
@@ -646,6 +646,7 @@ M[ms.window_showMessage] = function(_, result, ctx, _)
if message_type == protocol.MessageType.Error then
err_message('LSP[', client_name, '] ', message)
else
+ --- @type string
local message_type_name = protocol.MessageType[message_type]
api.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message))
end
diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua
index a79ae76eb9..18066a84db 100644
--- a/runtime/lua/vim/lsp/health.lua
+++ b/runtime/lua/vim/lsp/health.lua
@@ -33,16 +33,25 @@ local function check_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 {}), ',')
- report_info(
+ local cmd ---@type string
+ if type(client.config.cmd) == 'table' then
+ cmd = table.concat(client.config.cmd --[[@as table]], ' ')
+ elseif type(client.config.cmd) == 'function' then
+ cmd = tostring(client.config.cmd)
+ end
+ report_info(table.concat({
+ string.format('%s (id: %d)', client.name, client.id),
string.format(
- '%s (id=%s, root_dir=%s, attached_to=[%s])',
- client.name,
- client.id,
- vim.fn.fnamemodify(client.root_dir, ':~'),
- attached_to
- )
- )
+ ' Root directory: %s',
+ client.root_dir and vim.fn.fnamemodify(client.root_dir, ':~') or nil
+ ),
+ string.format(' Command: %s', cmd),
+ string.format(' Settings: %s', vim.inspect(client.settings, { newline = '\n ' })),
+ string.format(
+ ' Attached buffers: %s',
+ vim.iter(pairs(client.attached_buffers)):map(tostring):join(', ')
+ ),
+ }, '\n'))
end
else
report_info('No active clients')
@@ -50,7 +59,7 @@ local function check_active_clients()
end
local function check_watcher()
- vim.health.start('vim.lsp: File watcher')
+ vim.health.start('vim.lsp: File Watcher')
-- Only run the check if file watching has been enabled by a client.
local clients = vim.lsp.get_clients()
@@ -81,8 +90,8 @@ local function check_watcher()
watchfunc_name = 'libuv-watch'
elseif watchfunc == vim._watch.watchdirs then
watchfunc_name = 'libuv-watchdirs'
- elseif watchfunc == vim._watch.fswatch then
- watchfunc_name = 'fswatch'
+ elseif watchfunc == vim._watch.inotifywait then
+ watchfunc_name = 'inotifywait'
else
local nm = debug.getinfo(watchfunc, 'S').source
watchfunc_name = string.format('Custom (%s)', nm)
@@ -90,7 +99,63 @@ local function check_watcher()
report_info('File watch backend: ' .. watchfunc_name)
if watchfunc_name == 'libuv-watchdirs' then
- report_warn('libuv-watchdirs has known performance issues. Consider installing fswatch.')
+ report_warn('libuv-watchdirs has known performance issues. Consider installing inotify-tools.')
+ end
+end
+
+local function check_position_encodings()
+ vim.health.start('vim.lsp: Position Encodings')
+ local clients = vim.lsp.get_clients()
+ if next(clients) then
+ local position_encodings = {} ---@type table<integer, table<string, integer[]>>
+ for _, client in pairs(clients) do
+ for bufnr in pairs(client.attached_buffers) do
+ if not position_encodings[bufnr] then
+ position_encodings[bufnr] = {}
+ end
+ if not position_encodings[bufnr][client.offset_encoding] then
+ position_encodings[bufnr][client.offset_encoding] = {}
+ end
+ table.insert(position_encodings[bufnr][client.offset_encoding], client.id)
+ end
+ end
+
+ -- Check if any buffers are attached to multiple clients with different position encodings
+ local buffers = {} ---@type integer[]
+ for bufnr, encodings in pairs(position_encodings) do
+ local list = {} ---@type string[]
+ for k in pairs(encodings) do
+ list[#list + 1] = k
+ end
+
+ if #list > 1 then
+ buffers[#buffers + 1] = bufnr
+ end
+ end
+
+ if #buffers > 0 then
+ local lines =
+ { 'Found buffers attached to multiple clients with different position encodings.' }
+ for _, bufnr in ipairs(buffers) do
+ local encodings = position_encodings[bufnr]
+ local parts = {}
+ for encoding, client_ids in pairs(encodings) do
+ table.insert(
+ parts,
+ string.format('%s (client id(s): %s)', encoding:upper(), table.concat(client_ids, ', '))
+ )
+ end
+ table.insert(lines, string.format('- Buffer %d: %s', bufnr, table.concat(parts, ', ')))
+ end
+ report_warn(
+ table.concat(lines, '\n'),
+ 'Use the positionEncodings client capability to ensure all clients use the same position encoding'
+ )
+ else
+ report_info('No buffers contain mixed position encodings')
+ end
+ else
+ report_info('No active clients')
end
end
@@ -99,6 +164,7 @@ function M.check()
check_log()
check_active_clients()
check_watcher()
+ check_position_encodings()
end
return M
diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua
index f98496456b..61059180fe 100644
--- a/runtime/lua/vim/lsp/inlay_hint.lua
+++ b/runtime/lua/vim/lsp/inlay_hint.lua
@@ -43,17 +43,16 @@ function M.on_inlayhint(err, result, ctx, _)
return
end
local bufnr = assert(ctx.bufnr)
- if util.buf_versions[bufnr] ~= ctx.version then
+ if
+ util.buf_versions[bufnr] ~= ctx.version
+ or not result
+ or not api.nvim_buf_is_loaded(bufnr)
+ or not bufstates[bufnr].enabled
+ then
return
end
local client_id = ctx.client_id
- if not result then
- return
- end
local bufstate = bufstates[bufnr]
- if not bufstate.enabled then
- return
- end
if not (bufstate.client_hints and bufstate.version) then
bufstate.client_hints = vim.defaulttable()
bufstate.version = ctx.version
@@ -77,12 +76,7 @@ function M.on_inlayhint(err, result, ctx, _)
local col = position.character
if col > 0 then
local line = lines[position.line + 1] or ''
- local ok, convert_result
- ok, convert_result = pcall(util._str_byteindex_enc, line, col, client.offset_encoding)
- if ok then
- return convert_result
- end
- return math.min(#line, col)
+ return util._str_byteindex_enc(line, col, client.offset_encoding)
end
return col
end
@@ -336,6 +330,8 @@ api.nvim_set_decoration_provider(namespace, {
for lnum = topline, botline do
if bufstate.applied[lnum] ~= bufstate.version then
api.nvim_buf_clear_namespace(bufnr, namespace, lnum, lnum + 1)
+
+ local hint_virtual_texts = {} --- @type table<integer, [string, string?][]>
for _, lnum_hints in pairs(client_hints) do
local hints = lnum_hints[lnum] or {}
for _, hint in pairs(hints) do
@@ -348,7 +344,7 @@ api.nvim_set_decoration_provider(namespace, {
text = text .. part.value
end
end
- local vt = {} --- @type {[1]: string, [2]: string?}[]
+ local vt = hint_virtual_texts[hint.position.character] or {}
if hint.paddingLeft then
vt[#vt + 1] = { ' ' }
end
@@ -356,13 +352,18 @@ api.nvim_set_decoration_provider(namespace, {
if hint.paddingRight then
vt[#vt + 1] = { ' ' }
end
- api.nvim_buf_set_extmark(bufnr, namespace, lnum, hint.position.character, {
- virt_text_pos = 'inline',
- ephemeral = false,
- virt_text = vt,
- })
+ hint_virtual_texts[hint.position.character] = vt
end
end
+
+ for pos, vt in pairs(hint_virtual_texts) do
+ api.nvim_buf_set_extmark(bufnr, namespace, lnum, pos, {
+ virt_text_pos = 'inline',
+ ephemeral = false,
+ virt_text = vt,
+ })
+ end
+
bufstate.applied[lnum] = bufstate.version
end
end
@@ -370,7 +371,7 @@ api.nvim_set_decoration_provider(namespace, {
})
--- Query whether inlay hint is enabled in the {filter}ed scope
---- @param filter vim.lsp.inlay_hint.enable.Filter
+--- @param filter? vim.lsp.inlay_hint.enable.Filter
--- @return boolean
--- @since 12
function M.is_enabled(filter)
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 9f2bd71158..4f177b47fd 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -9,7 +9,7 @@ local log_levels = vim.log.levels
--- 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<string|integer, string|integer>
+--- @type table<string,integer> | table<integer, string>
--- @nodoc
log.levels = vim.deepcopy(log_levels)
@@ -19,7 +19,7 @@ local current_log_level = log_levels.WARN
local log_date_format = '%F %H:%M:%S'
local function format_func(arg)
- return vim.inspect(arg, { newline = '' })
+ return vim.inspect(arg, { newline = ' ', indent = '' })
end
local function notify(msg, level)
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index 419c2ff644..1699fff0c1 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -12,9 +12,6 @@ end
local sysname = vim.uv.os_uname().sysname
--- Protocol for the Microsoft Language Server Protocol (mslsp)
-local protocol = {}
-
local constants = {
--- @enum lsp.DiagnosticSeverity
DiagnosticSeverity = {
@@ -46,6 +43,8 @@ local constants = {
Info = 3,
-- A log message.
Log = 4,
+ -- A debug message.
+ Debug = 5,
},
-- The file event type.
@@ -100,6 +99,13 @@ local constants = {
TriggerForIncompleteCompletions = 3,
},
+ -- Completion item tags are extra annotations that tweak the rendering of a
+ -- completion item
+ CompletionTag = {
+ -- Render a completion as obsolete, usually using a strike-out.
+ Deprecated = 1,
+ },
+
-- A document highlight kind.
DocumentHighlightKind = {
-- A textual occurrence.
@@ -308,326 +314,18 @@ local constants = {
},
}
-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
+-- Protocol for the Microsoft Language Server Protocol (mslsp)
+local protocol = {}
+
+--- @diagnostic disable:no-unknown
+for k1, v1 in pairs(vim.deepcopy(constants, true)) do
+ for _, k2 in ipairs(vim.tbl_keys(v1)) do
+ local v2 = v1[k2]
+ v1[v2] = k2
end
- protocol[k1] = tbl
+ protocol[k1] = v1
end
-
---[=[
---Text document specific client capabilities.
-export interface TextDocumentClientCapabilities {
- synchronization?: {
- --Whether text document synchronization supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports sending will save notifications.
- 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.
- willSaveWaitUntil?: boolean;
- --The client supports did save notifications.
- didSave?: boolean;
- }
- --Capabilities specific to the `textDocument/completion`
- completion?: {
- --Whether completion supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports the following `CompletionItem` specific
- --capabilities.
- completionItem?: {
- --The client supports snippets as insert text.
- --
- --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. Placeholders with equal identifiers are linked,
- --that is typing in one will update others too.
- snippetSupport?: boolean;
- --The client supports commit characters on a completion item.
- commitCharactersSupport?: boolean
- --The client supports the following content formats for the documentation
- --property. The order describes the preferred format of the client.
- documentationFormat?: MarkupKind[];
- --The client supports the deprecated property on a completion item.
- deprecatedSupport?: boolean;
- --The client supports the preselect property on a completion item.
- preselectSupport?: boolean;
- }
- 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
- --to a default value when unknown.
- --
- --If this property is not present the client only supports
- --the completion items kinds from `Text` to `Reference` as defined in
- --the initial version of the protocol.
- valueSet?: CompletionItemKind[];
- },
- --The client supports to send additional context information for a
- --`textDocument/completion` request.
- contextSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/hover`
- hover?: {
- --Whether hover supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports the follow content formats for the content
- --property. The order describes the preferred format of the client.
- contentFormat?: MarkupKind[];
- };
- --Capabilities specific to the `textDocument/signatureHelp`
- signatureHelp?: {
- --Whether signature help supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports the following `SignatureInformation`
- --specific properties.
- signatureInformation?: {
- --The client supports the follow content formats for the documentation
- --property. The order describes the preferred format of the client.
- documentationFormat?: MarkupKind[];
- --Client capabilities specific to parameter information.
- parameterInformation?: {
- --The client supports processing label offsets instead of a
- --simple label string.
- --
- --Since 3.14.0
- labelOffsetSupport?: boolean;
- }
- };
- };
- --Capabilities specific to the `textDocument/references`
- references?: {
- --Whether references supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/documentHighlight`
- documentHighlight?: {
- --Whether document highlight supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/documentSymbol`
- documentSymbol?: {
- --Whether document symbol supports dynamic registration.
- dynamicRegistration?: boolean;
- --Specific capabilities for the `SymbolKind`.
- 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
- --to a default value when unknown.
- --
- --If this property is not present the client only supports
- --the symbol kinds from `File` to `Array` as defined in
- --the initial version of the protocol.
- valueSet?: SymbolKind[];
- }
- --The client supports hierarchical document symbols.
- hierarchicalDocumentSymbolSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/formatting`
- formatting?: {
- --Whether formatting supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/rangeFormatting`
- rangeFormatting?: {
- --Whether range formatting supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/onTypeFormatting`
- onTypeFormatting?: {
- --Whether on type formatting supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/declaration`
- declaration?: {
- --Whether declaration 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.
- dynamicRegistration?: boolean;
- --The client supports additional metadata in the form of declaration links.
- --
- --Since 3.14.0
- linkSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/definition`.
- --
- --Since 3.14.0
- definition?: {
- --Whether definition supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports additional metadata in the form of definition links.
- linkSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/typeDefinition`
- --
- --Since 3.6.0
- typeDefinition?: {
- --Whether typeDefinition 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.
- dynamicRegistration?: boolean;
- --The client supports additional metadata in the form of definition links.
- --
- --Since 3.14.0
- linkSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/implementation`.
- --
- --Since 3.6.0
- implementation?: {
- --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.
- dynamicRegistration?: boolean;
- --The client supports additional metadata in the form of definition links.
- --
- --Since 3.14.0
- linkSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/codeAction`
- codeAction?: {
- --Whether code action supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client support code action literals as a valid
- --response of the `textDocument/codeAction` request.
- --
- --Since 3.8.0
- codeActionLiteralSupport?: {
- --The code action kind is support with the following value
- --set.
- 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.
- valueSet: CodeActionKind[];
- };
- };
- };
- --Capabilities specific to the `textDocument/codeLens`
- codeLens?: {
- --Whether code lens supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/documentLink`
- documentLink?: {
- --Whether document link supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/documentColor` and the
- --`textDocument/colorPresentation` request.
- --
- --Since 3.6.0
- colorProvider?: {
- --Whether colorProvider supports dynamic registration. If this is set to `true`
- --the client supports the new `(ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
- --return value for the corresponding server capability as well.
- dynamicRegistration?: boolean;
- }
- --Capabilities specific to the `textDocument/rename`
- rename?: {
- --Whether rename supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports testing for validity of rename operations
- --before execution.
- prepareSupport?: boolean;
- };
- --Capabilities specific to `textDocument/publishDiagnostics`.
- publishDiagnostics?: {
- --Whether the clients accepts diagnostics with related information.
- 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
- tagSupport?: {
- --The tags supported by this client
- valueSet: DiagnosticTag[];
- };
- };
- --Capabilities specific to `textDocument/foldingRange` requests.
- --
- --Since 3.10.0
- foldingRange?: {
- --Whether implementation supports dynamic registration for folding range providers. If this is set to `true`
- --the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
- --return value for the corresponding server capability as well.
- 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.
- rangeLimit?: number;
- --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.
- lineFoldingOnly?: boolean;
- };
-}
---]=]
-
---[=[
---Workspace specific client capabilities.
-export interface WorkspaceClientCapabilities {
- --The client supports applying batch edits to the workspace by supporting
- --the request 'workspace/applyEdit'
- applyEdit?: boolean;
- --Capabilities specific to `WorkspaceEdit`s
- workspaceEdit?: {
- --The client supports versioned document changes in `WorkspaceEdit`s
- documentChanges?: boolean;
- --The resource operations the client supports. Clients should at least
- --support 'create', 'rename' and 'delete' files and folders.
- resourceOperations?: ResourceOperationKind[];
- --The failure handling strategy of a client if applying the workspace edit
- --fails.
- failureHandling?: FailureHandlingKind;
- };
- --Capabilities specific to the `workspace/didChangeConfiguration` notification.
- didChangeConfiguration?: {
- --Did change configuration notification supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `workspace/didChangeWatchedFiles` notification.
- didChangeWatchedFiles?: {
- --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.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `workspace/symbol` request.
- symbol?: {
- --Symbol request supports dynamic registration.
- dynamicRegistration?: boolean;
- --Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
- 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
- --to a default value when unknown.
- --
- --If this property is not present the client only supports
- --the symbol kinds from `File` to `Array` as defined in
- --the initial version of the protocol.
- valueSet?: SymbolKind[];
- }
- };
- --Capabilities specific to the `workspace/executeCommand` request.
- executeCommand?: {
- --Execute command supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --The client has support for workspace folders.
- --
- --Since 3.6.0
- workspaceFolders?: boolean;
- --The client supports `workspace/configuration` requests.
- --
- --Since 3.6.0
- configuration?: boolean;
-}
---]=]
+--- @diagnostic enable:no-unknown
--- Gets a new ClientCapabilities object describing the LSP client
--- capabilities.
@@ -729,23 +427,35 @@ function protocol.make_client_capabilities()
properties = { 'edit' },
},
},
+ codeLens = {
+ dynamicRegistration = false,
+ resolveSupport = {
+ properties = { 'command' },
+ },
+ },
formatting = {
dynamicRegistration = true,
},
rangeFormatting = {
dynamicRegistration = true,
+ rangesSupport = true,
},
completion = {
dynamicRegistration = false,
completionItem = {
- -- Until we can actually expand snippet, move cursor and allow for true snippet experience,
- -- this should be disabled out of the box.
- -- However, users can turn this back on if they have a snippet plugin.
- snippetSupport = false,
+ snippetSupport = true,
commitCharactersSupport = false,
preselectSupport = false,
- deprecatedSupport = false,
+ deprecatedSupport = true,
documentationFormat = { constants.MarkupKind.Markdown, constants.MarkupKind.PlainText },
+ resolveSupport = {
+ properties = {
+ 'additionalTextEdits',
+ },
+ },
+ tagSupport = {
+ valueSet = get_value_set(constants.CompletionTag),
+ },
},
completionItemKind = {
valueSet = get_value_set(constants.CompletionItemKind),
@@ -852,7 +562,7 @@ function protocol.make_client_capabilities()
workDoneProgress = true,
showMessage = {
messageActionItem = {
- additionalPropertiesSupport = false,
+ additionalPropertiesSupport = true,
},
},
showDocument = {
@@ -905,9 +615,10 @@ function protocol.resolve_capabilities(server_capabilities)
end
-- Generated by gen_lsp.lua, keep at end of file.
---- LSP method names.
---
+---@enum vim.lsp.protocol.Methods
---@see https://microsoft.github.io/language-server-protocol/specification/#metaModel
+--- LSP method names.
protocol.Methods = {
--- A request to resolve the incoming calls for a given `CallHierarchyItem`.
--- @since 3.16.0
@@ -1170,14 +881,14 @@ protocol.Methods = {
--- symbol's location.
--- @since 3.17.0
workspaceSymbol_resolve = 'workspaceSymbol/resolve',
- --- A request sent from the server to the client to modify certain resources.
+ --- A request sent from the server to the client to modified 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 where the client signaled configuration change via an
+ --- This pull model replaces the old push model were 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.
@@ -1210,7 +921,7 @@ protocol.Methods = {
--- files were renamed from within the client.
--- @since 3.16.0
workspace_didRenameFiles = 'workspace/didRenameFiles',
- --- A request sent from the client to the server to execute a command. The request might return
+ --- A request send 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
@@ -1248,14 +959,5 @@ protocol.Methods = {
--- The `workspace/workspaceFolders` is sent from the server to the client to fetch the open workspace folders.
workspace_workspaceFolders = 'workspace/workspaceFolders',
}
-local function freeze(t)
- return setmetatable({}, {
- __index = t,
- __newindex = function()
- error('cannot modify immutable table')
- end,
- })
-end
-protocol.Methods = freeze(protocol.Methods)
return protocol
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 3c63a12da2..e79dbd2db3 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -3,7 +3,7 @@ local log = require('vim.lsp.log')
local protocol = require('vim.lsp.protocol')
local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap
-local is_win = uv.os_uname().version:find('Windows')
+local is_win = vim.fn.has('win32') == 1
--- Checks whether a given path exists and is a directory.
---@param filename string path to check
@@ -140,7 +140,7 @@ local client_errors = {
SERVER_RESULT_CALLBACK_ERROR = 7,
}
---- @type table<string|integer, string|integer>
+--- @type table<string,integer> | table<integer,string>
--- @nodoc
M.client_errors = vim.deepcopy(client_errors)
for k, v in pairs(client_errors) do
@@ -407,7 +407,9 @@ function Client:handle_body(body)
end
log.debug('rpc.receive', decoded)
- if type(decoded.method) == 'string' and decoded.id then
+ if type(decoded) ~= 'table' then
+ self:on_error(M.client_errors.INVALID_SERVER_MESSAGE, decoded)
+ elseif type(decoded.method) == 'string' and decoded.id then
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.
@@ -502,7 +504,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,
@@ -548,7 +550,7 @@ local function new_client(dispatchers, transport)
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 request fun(method: string, params: table?, callback: fun(err: lsp.ResponseError|nil, result: any), notify_reply_callback: fun(message_id: 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()
@@ -701,7 +703,9 @@ function M.connect(host_or_path, port)
if port == nil then
handle:connect(host_or_path, on_connect)
else
- handle:connect(host_or_path, port, on_connect)
+ local info = uv.getaddrinfo(host_or_path, nil)
+ local resolved_host = info and info[1] and info[1].addr or host_or_path
+ handle:connect(resolved_host, port, on_connect)
end
return public_client(client)
diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua
index ef2502b12e..8182457dd0 100644
--- a/runtime/lua/vim/lsp/semantic_tokens.lua
+++ b/runtime/lua/vim/lsp/semantic_tokens.lua
@@ -140,12 +140,7 @@ local function tokens_to_ranges(data, bufnr, client, request)
local function _get_byte_pos(col)
if col > 0 then
local buf_line = lines[line + 1] or ''
- local ok, result
- ok, result = pcall(util._str_byteindex_enc, buf_line, col, client.offset_encoding)
- if ok then
- return result
- end
- return math.min(#buf_line, col)
+ return util._str_byteindex_enc(buf_line, col, client.offset_encoding)
end
return col
end
@@ -197,12 +192,6 @@ function STHighlighter.new(bufnr)
highlighter:send_request()
end
end,
- on_detach = function(_, buf)
- local highlighter = STHighlighter.active[buf]
- if highlighter then
- highlighter:destroy()
- end
- end,
})
api.nvim_create_autocmd({ 'BufWinEnter', 'InsertLeave' }, {
@@ -418,7 +407,7 @@ end
function STHighlighter:on_win(topline, botline)
for client_id, state in pairs(self.client_state) do
local current_result = state.current_result
- if current_result.version and current_result.version == util.buf_versions[self.bufnr] then
+ if current_result.version == util.buf_versions[self.bufnr] then
if not current_result.namespace_cleared then
api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1)
current_result.namespace_cleared = true
@@ -779,7 +768,6 @@ 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
diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua
index 936579e003..bdfe8d51b8 100644
--- a/runtime/lua/vim/lsp/sync.lua
+++ b/runtime/lua/vim/lsp/sync.lua
@@ -212,7 +212,8 @@ end
---@param lastline integer
---@param new_lastline integer
---@param offset_encoding string
----@return vim.lsp.sync.Range, vim.lsp.sync.Range
+---@return vim.lsp.sync.Range prev_end_range
+---@return vim.lsp.sync.Range curr_end_range
local function compute_end_range(
prev_lines,
curr_lines,
@@ -222,6 +223,16 @@ local function compute_end_range(
new_lastline,
offset_encoding
)
+ -- A special case for the following `firstline == new_lastline` case where lines are deleted.
+ -- Even if the buffer has become empty, nvim behaves as if it has an empty line with eol.
+ if #curr_lines == 1 and curr_lines[1] == '' then
+ local prev_line = prev_lines[lastline - 1]
+ return {
+ line_idx = lastline - 1,
+ byte_idx = #prev_line + 1,
+ char_idx = compute_line_length(prev_line, offset_encoding) + 1,
+ }, { line_idx = 1, byte_idx = 1, char_idx = 1 }
+ end
-- If firstline == new_lastline, the first change occurred on a line that was deleted.
-- In this case, the last_byte...
if firstline == new_lastline then
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 5a229a1169..882ec22ca6 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -99,9 +99,26 @@ local function get_border_size(opts)
return { height = height, width = width }
end
-local function split_lines(value)
- value = string.gsub(value, '\r\n?', '\n')
- return split(value, '\n', { plain = true, trimempty = true })
+--- Splits string at newlines, optionally removing unwanted blank lines.
+---
+--- @param s string Multiline string
+--- @param no_blank boolean? Drop blank lines for each @param/@return (except one empty line
+--- separating each). Workaround for https://github.com/LuaLS/lua-language-server/issues/2333
+local function split_lines(s, no_blank)
+ s = string.gsub(s, '\r\n?', '\n')
+ local lines = {}
+ local in_desc = true -- Main description block, before seeing any @foo.
+ for line in vim.gsplit(s, '\n', { plain = true, trimempty = true }) do
+ local start_annotation = not not line:find('^ ?%@.?[pr]')
+ in_desc = (not start_annotation) and in_desc or false
+ if start_annotation and no_blank and not (lines[#lines] or ''):find('^%s*$') then
+ table.insert(lines, '') -- Separate each @foo with a blank line.
+ end
+ if in_desc or not no_blank or not line:find('^%s*$') then
+ table.insert(lines, line)
+ end
+ end
+ return lines
end
local function create_window_without_focus()
@@ -116,9 +133,10 @@ end
--- Convenience wrapper around vim.str_utfindex
---@param line string line to be indexed
---@param index integer|nil byte index (utf-8), or `nil` for length
----@param encoding string|nil utf-8|utf-16|utf-32|nil defaults to utf-16
+---@param encoding 'utf-8'|'utf-16'|'utf-32'|nil defaults to utf-16
---@return integer `encoding` index of `index` in `line`
function M._str_utfindex_enc(line, index, encoding)
+ local len32, len16 = vim.str_utfindex(line)
if not encoding then
encoding = 'utf-16'
end
@@ -129,9 +147,15 @@ function M._str_utfindex_enc(line, index, encoding)
return #line
end
elseif encoding == 'utf-16' then
+ if not index or index > len16 then
+ return len16
+ end
local _, col16 = vim.str_utfindex(line, index)
return col16
elseif encoding == 'utf-32' then
+ if not index or index > len32 then
+ return len32
+ end
local col32, _ = vim.str_utfindex(line, index)
return col32
else
@@ -147,6 +171,12 @@ end
---@param encoding string utf-8|utf-16|utf-32| defaults to utf-16
---@return integer byte (utf-8) index of `encoding` index `index` in `line`
function M._str_byteindex_enc(line, index, encoding)
+ local len = #line
+ if index > len then
+ -- LSP spec: if character > line length, default to the line length.
+ -- https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
+ return len
+ end
if not encoding then
encoding = 'utf-16'
end
@@ -154,7 +184,7 @@ function M._str_byteindex_enc(line, index, encoding)
if index then
return index
else
- return #line
+ return len
end
elseif encoding == 'utf-16' then
return vim.str_byteindex(line, index, true)
@@ -165,19 +195,16 @@ function M._str_byteindex_enc(line, index, encoding)
end
end
-local _str_utfindex_enc = M._str_utfindex_enc
-local _str_byteindex_enc = M._str_byteindex_enc
-
--- Replaces text in a range with new text.
---
--- CAUTION: Changes in-place!
---
---@deprecated
----@param lines (table) Original list of strings
----@param A (table) Start position; a 2-tuple of {line,col} numbers
----@param B (table) End position; a 2-tuple of {line,col} numbers
----@param new_lines (table) list of strings to replace the original
----@return table The modified {lines} object
+---@param lines string[] Original list of strings
+---@param A [integer, integer] Start position; a 2-tuple of {line,col} numbers
+---@param B [integer, integer] End position; a 2-tuple {line,col} numbers
+---@param new_lines string[] list of strings to replace the original
+---@return string[] 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
@@ -238,6 +265,7 @@ end
---@param rows integer[] zero-indexed line numbers
---@return table<integer, string>|string a table mapping rows to lines
local function get_lines(bufnr, rows)
+ --- @type integer[]
rows = type(rows) == 'table' and rows or { rows }
-- This is needed for bufload and bufloaded
@@ -246,7 +274,7 @@ local function get_lines(bufnr, rows)
end
local function buf_lines()
- local lines = {}
+ local lines = {} --- @type table<integer,string>
for _, row in ipairs(rows) do
lines[row] = (api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1]
end
@@ -268,17 +296,20 @@ local function get_lines(bufnr, rows)
end
local filename = api.nvim_buf_get_name(bufnr)
+ if vim.fn.isdirectory(filename) ~= 0 then
+ return {}
+ end
-- get the data from the file
local fd = uv.fs_open(filename, 'r', 438)
if not fd then
return ''
end
- local stat = uv.fs_fstat(fd)
- local data = uv.fs_read(fd, stat.size, 0)
+ local stat = assert(uv.fs_fstat(fd))
+ local data = assert(uv.fs_read(fd, stat.size, 0))
uv.fs_close(fd)
- local lines = {} -- rows we need to retrieve
+ local lines = {} --- @type table<integer,true|string> rows we need to retrieve
local need = 0 -- keep track of how many unique rows we need
for _, row in pairs(rows) do
if not lines[row] then
@@ -307,7 +338,7 @@ local function get_lines(bufnr, rows)
lines[i] = ''
end
end
- return lines
+ return lines --[[@as table<integer,string>]]
end
--- Gets the zero-indexed line from the given buffer.
@@ -322,7 +353,8 @@ local function get_line(bufnr, row)
end
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
----@param offset_encoding string|nil utf-8|utf-16|utf-32
+---@param position lsp.Position
+---@param offset_encoding? string utf-8|utf-16|utf-32
---@return integer
local function get_line_byte_from_position(bufnr, position, offset_encoding)
-- LSP's line and characters are 0-indexed
@@ -332,18 +364,13 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding)
-- character
if col > 0 then
local line = get_line(bufnr, position.line) or ''
- local ok, result
- ok, result = pcall(_str_byteindex_enc, line, col, offset_encoding)
- if ok then
- return result
- end
- return math.min(#line, col)
+ return M._str_byteindex_enc(line, col, offset_encoding or 'utf-16')
end
return col
end
--- Applies a list of text edits to a buffer.
----@param text_edits table list of `TextEdit` objects
+---@param text_edits lsp.TextEdit[]
---@param bufnr integer Buffer id
---@param offset_encoding string utf-8|utf-16|utf-32
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
@@ -366,6 +393,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
-- Fix reversed range and indexing each text_edits
local index = 0
+ --- @param text_edit lsp.TextEdit
text_edits = vim.tbl_map(function(text_edit)
index = index + 1
text_edit._index = index
@@ -383,6 +411,9 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
end, text_edits)
-- Sort text_edits
+ ---@param a lsp.TextEdit | { _index: integer }
+ ---@param b lsp.TextEdit | { _index: integer }
+ ---@return boolean
table.sort(text_edits, function(a, b)
if a.range.start.line ~= b.range.start.line then
return a.range.start.line > b.range.start.line
@@ -390,13 +421,11 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
if a.range.start.character ~= b.range.start.character then
return a.range.start.character > b.range.start.character
end
- if a._index ~= b._index then
- return a._index > b._index
- end
+ return a._index > b._index
end)
-- save and restore local marks since they get deleted by nvim_buf_set_lines
- local marks = {}
+ local marks = {} --- @type table<string,[integer,integer]>
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
@@ -432,14 +461,15 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
e.end_col = last_line_len
has_eol_text_edit = true
else
- -- If the replacement is over the end of a line (i.e. e.end_col is out of bounds and the
+ -- If the replacement is over the end of a line (i.e. e.end_col is equal to the line length and the
-- replacement text ends with a newline We can likely assume that the replacement is assumed
-- to be meant to replace the newline with another newline and we need to make sure this
-- doesn't add an extra empty line. E.g. when the last line to be replaced contains a '\r'
-- in the file some servers (clangd on windows) will include that character in the line
-- while nvim_buf_set_text doesn't count it as part of the line.
if
- e.end_col > last_line_len
+ e.end_col >= last_line_len
+ and text_edit.range['end'].character > e.end_col
and #text_edit.newText > 0
and string.sub(text_edit.newText, -1) == '\n'
then
@@ -481,8 +511,8 @@ end
--- Applies a `TextDocumentEdit`, which is a list of changes to a single
--- document.
---
----@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 text_document_edit lsp.TextDocumentEdit
+---@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)
@@ -509,7 +539,6 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding)
and (
text_document.version
and text_document.version > 0
- and M.buf_versions[bufnr]
and M.buf_versions[bufnr] > text_document.version
)
then
@@ -534,6 +563,7 @@ local function path_under_prefix(path, prefix)
end
--- Get list of buffers whose filename matches the given path prefix (normalized full path)
+---@param prefix string
---@return integer[]
local function get_bufs_with_prefix(prefix)
prefix = path_components(prefix)
@@ -616,7 +646,7 @@ function M.rename(old_fname, new_fname, opts)
buf_rename[b] = { from = old_bname, to = new_bname }
end
- local newdir = assert(vim.fs.dirname(new_fname))
+ local newdir = vim.fs.dirname(new_fname)
vim.fn.mkdir(newdir, 'p')
local ok, err = os.rename(old_fname_full, new_fname)
@@ -625,7 +655,7 @@ function M.rename(old_fname, new_fname, opts)
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')
+ vim.fn.mkdir(vim.fs.dirname(new_undofile), 'p')
os.rename(old_undofile, new_undofile)
end
@@ -633,7 +663,7 @@ function M.rename(old_fname, new_fname, opts)
-- 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._with({ buf = 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
@@ -642,6 +672,7 @@ function M.rename(old_fname, new_fname, opts)
end
end
+--- @param change lsp.CreateFile
local function create_file(change)
local opts = change.options or {}
-- from spec: Overwrite wins over `ignoreIfExists`
@@ -656,29 +687,21 @@ local function create_file(change)
vim.fn.bufadd(fname)
end
+--- @param change lsp.DeleteFile
local function delete_file(change)
local opts = change.options or {}
local fname = vim.uri_to_fname(change.uri)
- local stat = uv.fs_stat(fname)
- if opts.ignoreIfNotExists and not stat then
- return
- end
- assert(stat, 'Cannot delete not existing file or folder ' .. fname)
- local flags
- if stat and stat.type == 'directory' then
- flags = opts.recursive and 'rf' or 'd'
- else
- flags = ''
- end
local bufnr = vim.fn.bufadd(fname)
- local result = tonumber(vim.fn.delete(fname, flags))
- assert(result == 0, 'Could not delete file: ' .. fname .. ', stat: ' .. vim.inspect(stat))
+ vim.fs.rm(fname, {
+ force = opts.ignoreIfNotExists,
+ recursive = opts.recursive,
+ })
api.nvim_buf_delete(bufnr, { force = true })
end
--- Applies a `WorkspaceEdit`.
---
----@param workspace_edit table `WorkspaceEdit`
+---@param workspace_edit lsp.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
function M.apply_workspace_edit(workspace_edit, offset_encoding)
@@ -724,21 +747,21 @@ 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 (lsp.MarkedString | lsp.MarkedString[] | lsp.MarkupContent)
----@param contents (table|nil) List of strings to extend with converted lines. Defaults to {}.
+---@param input lsp.MarkedString|lsp.MarkedString[]|lsp.MarkupContent
+---@param contents string[]|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
function M.convert_input_to_markdown_lines(input, contents)
contents = contents or {}
-- MarkedString variation 1
if type(input) == 'string' then
- list_extend(contents, split_lines(input))
+ list_extend(contents, split_lines(input, true))
else
assert(type(input) == 'table', 'Expected a table for LSP input')
-- MarkupContent
if input.kind then
local value = input.value or ''
- list_extend(contents, split_lines(value))
+ list_extend(contents, split_lines(value, true))
-- MarkupString variation 2
elseif input.language then
table.insert(contents, '```' .. input.language)
@@ -760,11 +783,11 @@ end
--- Converts `textDocument/signatureHelp` response to markdown lines.
---
----@param signature_help table Response of `textDocument/SignatureHelp`
+---@param signature_help lsp.SignatureHelp Response of `textDocument/SignatureHelp`
---@param ft string|nil filetype that will be use as the `lang` for the label markdown code block
---@param triggers table|nil list of trigger characters from the lsp server. used to better determine parameter offsets
----@return table|nil table list of lines of converted markdown.
----@return table|nil table of active hl
+---@return string[]|nil table list of lines of converted markdown.
+---@return number[]|nil table of active hl
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers)
if not signature_help.signatures then
@@ -961,7 +984,7 @@ end
--- Shows document and optionally jumps to the location.
---
----@param location table (`Location`|`LocationLink`)
+---@param location lsp.Location|lsp.LocationLink
---@param offset_encoding string|nil utf-8|utf-16|utf-32
---@param opts table|nil options
--- - reuse_win (boolean) Jump to existing window if buffer is already open.
@@ -1007,7 +1030,7 @@ function M.show_document(location, offset_encoding, opts)
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 })
- api.nvim_win_call(win, function()
+ vim._with({ win = win }, function()
-- Open folds under the cursor
vim.cmd('normal! zv')
end)
@@ -1018,7 +1041,7 @@ end
--- Jumps to a location.
---
----@param location table (`Location`|`LocationLink`)
+---@param location lsp.Location|lsp.LocationLink
---@param offset_encoding string|nil utf-8|utf-16|utf-32
---@param reuse_win boolean|nil Jump to existing window if buffer is already open.
---@return boolean `true` if the jump succeeded
@@ -1039,7 +1062,7 @@ end
--- - for Location, range is shown (e.g., function definition)
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
---
----@param location table a single `Location` or `LocationLink`
+---@param location lsp.Location|lsp.LocationLink
---@param opts table
---@return integer|nil buffer id of float window
---@return integer|nil window id of float window
@@ -1155,7 +1178,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 contents string[] of lines to show in window
---@param opts table with optional fields
--- - height of floating window
--- - width of floating window
@@ -1327,7 +1350,7 @@ function M.stylize_markdown(bufnr, contents, opts)
end
-- needs to run in the buffer for the regions to work
- api.nvim_buf_call(bufnr, function()
+ vim._with({ buf = bufnr }, function()
-- we need to apply lsp_markdown regions speperately, since otherwise
-- markdown regions can "bleed" through the other syntax regions
-- and mess up the formatting
@@ -1438,7 +1461,7 @@ end
--- Computes size of float needed to show contents (with optional wrapping)
---
---@param contents table of lines to show in window
----@param opts table with optional fields
+---@param opts? table with optional fields
--- - height of floating window
--- - width of floating window
--- - wrap_at character to wrap at for computing height
@@ -1630,10 +1653,9 @@ function M.open_floating_preview(contents, syntax, opts)
if do_stylize then
vim.wo[floating_winnr].conceallevel = 2
end
- -- disable folding
- vim.wo[floating_winnr].foldenable = false
- -- soft wrapping
- vim.wo[floating_winnr].wrap = opts.wrap
+ vim.wo[floating_winnr].foldenable = false -- Disable folding.
+ vim.wo[floating_winnr].wrap = opts.wrap -- Soft wrapping.
+ vim.wo[floating_winnr].breakindent = true -- Slightly better list presentation.
vim.bo[floating_bufnr].modifiable = false
vim.bo[floating_bufnr].bufhidden = 'wipe'
@@ -1670,7 +1692,7 @@ do --[[ References ]]
--- Shows a list of document highlights for a certain buffer.
---
---@param bufnr integer Buffer id
- ---@param references table List of `DocumentHighlight` objects to highlight
+ ---@param references lsp.DocumentHighlight[] objects to highlight
---@param offset_encoding string One of "utf-8", "utf-16", "utf-32".
---@see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent
function M.buf_highlight_references(bufnr, references, offset_encoding)
@@ -1721,7 +1743,9 @@ end)
---@inlinedoc
---@field filename string
---@field lnum integer 1-indexed line number
+---@field end_lnum integer 1-indexed end line number
---@field col integer 1-indexed column
+---@field end_col integer 1-indexed end column
---@field text string
---@field user_data lsp.Location|lsp.LocationLink
@@ -1748,7 +1772,7 @@ function M.locations_to_items(locations, offset_encoding)
end
local items = {}
- ---@type table<string, {start: lsp.Position, location: lsp.Location|lsp.LocationLink}[]>
+ ---@type table<string, {start: lsp.Position, end: lsp.Position, location: lsp.Location|lsp.LocationLink}[]>
local grouped = setmetatable({}, {
__index = function(t, k)
local v = {}
@@ -1760,7 +1784,7 @@ function M.locations_to_items(locations, offset_encoding)
-- locations may be Location or LocationLink
local uri = d.uri or d.targetUri
local range = d.range or d.targetSelectionRange
- table.insert(grouped[uri], { start = range.start, location = d })
+ table.insert(grouped[uri], { start = range.start, ['end'] = range['end'], location = d })
end
---@type string[]
@@ -1775,6 +1799,9 @@ function M.locations_to_items(locations, offset_encoding)
local line_numbers = {}
for _, temp in ipairs(rows) do
table.insert(line_numbers, temp.start.line)
+ if temp.start.line ~= temp['end'].line then
+ table.insert(line_numbers, temp['end'].line)
+ end
end
-- get all the lines for this uri
@@ -1782,13 +1809,20 @@ function M.locations_to_items(locations, offset_encoding)
for _, temp in ipairs(rows) do
local pos = temp.start
+ local end_pos = temp['end']
local row = pos.line
+ local end_row = end_pos.line
local line = lines[row] or ''
+ local end_line = lines[end_row] or ''
local col = M._str_byteindex_enc(line, pos.character, offset_encoding)
+ local end_col = M._str_byteindex_enc(end_line, end_pos.character, offset_encoding)
+
table.insert(items, {
filename = filename,
lnum = row + 1,
+ end_lnum = end_row + 1,
col = col + 1,
+ end_col = end_col + 1,
text = line,
user_data = temp.location,
})
@@ -1807,7 +1841,7 @@ end
--- Converts symbols to quickfix list items.
---
---@param symbols table DocumentSymbol[] or SymbolInformation[]
----@param bufnr integer
+---@param bufnr? integer
function M.symbols_to_items(symbols, bufnr)
local function _symbols_to_items(_symbols, _items, _bufnr)
for _, symbol in ipairs(_symbols) do
@@ -1874,7 +1908,7 @@ end
--- CAUTION: Modifies the input in-place!
---
---@deprecated
----@param lines table list of lines
+---@param lines string[] 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')
@@ -1899,7 +1933,7 @@ function M.try_trim_markdown_code_blocks(lines)
end
---@param window integer|nil: window handle or 0 for current, defaults to current
----@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
+---@param offset_encoding? string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
local function make_position_param(window, offset_encoding)
window = window or 0
local buf = api.nvim_win_get_buf(window)
@@ -1911,7 +1945,7 @@ local function make_position_param(window, offset_encoding)
return { line = 0, character = 0 }
end
- col = _str_utfindex_enc(line, col, offset_encoding)
+ col = M._str_utfindex_enc(line, col, offset_encoding)
return { line = row, character = col }
end
@@ -1920,7 +1954,7 @@ end
---
---@param window integer|nil: window handle or 0 for current, defaults to current
---@param offset_encoding string|nil utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
----@return table `TextDocumentPositionParams` object
+---@return lsp.TextDocumentPositionParams
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params(window, offset_encoding)
window = window or 0
@@ -1933,7 +1967,7 @@ function M.make_position_params(window, offset_encoding)
end
--- Utility function for getting the encoding of the first LSP client on the given buffer.
----@param bufnr (integer) buffer handle or 0 for current, defaults to current
+---@param bufnr integer buffer handle or 0 for current, defaults to current
---@return string encoding first client if there is one, nil otherwise
function M._get_offset_encoding(bufnr)
validate({
@@ -2034,15 +2068,16 @@ end
--- Creates a `TextDocumentIdentifier` object for the current buffer.
---
---@param bufnr integer|nil: Buffer handle, defaults to current
----@return table `TextDocumentIdentifier`
+---@return lsp.TextDocumentIdentifier
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
function M.make_text_document_params(bufnr)
return { uri = vim.uri_from_bufnr(bufnr or 0) }
end
--- Create the workspace params
----@param added table
----@param removed table
+---@param added lsp.WorkspaceFolder[]
+---@param removed lsp.WorkspaceFolder[]
+---@return lsp.WorkspaceFoldersChangeEvent
function M.make_workspace_params(added, removed)
return { event = { added = added, removed = removed } }
end
@@ -2050,8 +2085,8 @@ end
--- Returns indentation size.
---
---@see 'shiftwidth'
----@param bufnr (integer|nil): Buffer handle, defaults to current
----@return (integer) indentation size
+---@param bufnr integer|nil: Buffer handle, defaults to current
+---@return integer indentation size
function M.get_effective_tabstop(bufnr)
validate({ bufnr = { bufnr, 'n', true } })
local bo = bufnr and vim.bo[bufnr] or vim.bo
@@ -2061,7 +2096,7 @@ end
--- Creates a `DocumentFormattingParams` object for the current buffer and cursor position.
---
----@param options table|nil with valid `FormattingOptions` entries
+---@param options lsp.FormattingOptions|nil with valid `FormattingOptions` entries
---@return lsp.DocumentFormattingParams object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
function M.make_formatting_params(options)
@@ -2092,11 +2127,7 @@ function M.character_offset(buf, row, col, offset_encoding)
)
offset_encoding = vim.lsp.get_clients({ bufnr = buf })[1].offset_encoding
end
- -- If the col is past the EOL, use the line length.
- if col > #line then
- return _str_utfindex_enc(line, nil, offset_encoding)
- end
- return _str_utfindex_enc(line, col, offset_encoding)
+ return M._str_utfindex_enc(line, col, offset_encoding)
end
--- Helper function to return nested values in language server settings
@@ -2203,6 +2234,11 @@ end
M._get_line_byte_from_position = get_line_byte_from_position
---@nodoc
-M.buf_versions = {} ---@type table<integer,integer>
+---@type table<integer,integer>
+M.buf_versions = setmetatable({}, {
+ __index = function(t, bufnr)
+ return rawget(t, bufnr) or 0
+ end,
+})
return M