aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp.lua
diff options
context:
space:
mode:
authorMathias Fußenegger <mfussenegger@users.noreply.github.com>2023-06-09 11:32:43 +0200
committerGitHub <noreply@github.com>2023-06-09 11:32:43 +0200
commite5e0bda41b640d324350c5147b956e37e9f8b32c (patch)
treed546e647fcde46494740852171593e78101d9997 /runtime/lua/vim/lsp.lua
parentf31dba93f921891159eb707b185517648df00d6b (diff)
downloadrneovim-e5e0bda41b640d324350c5147b956e37e9f8b32c.tar.gz
rneovim-e5e0bda41b640d324350c5147b956e37e9f8b32c.tar.bz2
rneovim-e5e0bda41b640d324350c5147b956e37e9f8b32c.zip
feat(lsp)!: add vim.lsp.status, client.progress and promote LspProgressUpdate (#23958)
`client.messages` could grow unbounded because the default handler only added new messages, never removing them. A user either had to consume the messages by calling `vim.lsp.util.get_progress_messages` or by manually removing them from `client.messages.progress`. If they didn't do that, using LSP effectively leaked memory. To fix this, this deprecates the `messages` property and instead adds a `progress` ring buffer that only keeps at most 50 messages. In addition it deprecates `vim.lsp.util.get_progress_messages` in favour of a new `vim.lsp.status()` and also promotes the `LspProgressUpdate` user autocmd to a regular autocmd to allow users to pattern match on the progress kind. Also closes https://github.com/neovim/neovim/pull/20327
Diffstat (limited to 'runtime/lua/vim/lsp.lua')
-rw-r--r--runtime/lua/vim/lsp.lua62
1 files changed, 61 insertions, 1 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 532504a7db..6ddbfc6df7 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -807,6 +807,9 @@ end
---
--- - {server_capabilities} (table): Response from the server sent on
--- `initialize` describing the server's capabilities.
+---
+--- - {progress} A ring buffer (|vim.ringbuf()|) containing progress messages
+--- sent by the server.
function lsp.client()
error()
end
@@ -891,6 +894,50 @@ function lsp.start(config, opts)
return client_id
end
+--- Consumes the latest progress messages from all clients and formats them as a string.
+--- Empty if there are no clients or if no new messages
+---
+---@return string
+function lsp.status()
+ local percentage = nil
+ local groups = {}
+ for _, client in ipairs(vim.lsp.get_active_clients()) do
+ for progress in client.progress do
+ local value = progress.value
+ if type(value) == 'table' and value.kind then
+ local group = groups[progress.token]
+ if not group then
+ group = {}
+ groups[progress.token] = group
+ end
+ group.title = value.title or group.title
+ group.message = value.message or group.message
+ if value.percentage then
+ percentage = math.max(percentage or 0, value.percentage)
+ end
+ end
+ -- else: Doesn't look like work done progress and can be in any format
+ -- Just ignore it as there is no sensible way to display it
+ end
+ end
+ local messages = {}
+ for _, group in pairs(groups) do
+ if group.title then
+ table.insert(
+ messages,
+ group.message and (group.title .. ': ' .. group.message) or group.title
+ )
+ elseif group.message then
+ table.insert(messages, group.message)
+ end
+ end
+ local message = table.concat(messages, ', ')
+ if percentage then
+ return string.format('%03d: %s', percentage, message)
+ end
+ return message
+end
+
---@private
-- Determines whether the given option can be set by `set_defaults`.
local function is_empty_or_default(bufnr, option)
@@ -1266,10 +1313,23 @@ function lsp.start_client(config)
--- @type table<integer,{ type: string, bufnr: integer, method: string}>
requests = {},
- -- for $/progress report
+
+ --- Contains $/progress report messages.
+ --- They have the format {token: integer|string, value: any}
+ --- For "work done progress", value will be one of:
+ --- - lsp.WorkDoneProgressBegin,
+ --- - lsp.WorkDoneProgressReport (extended with title from Begin)
+ --- - lsp.WorkDoneProgressEnd (extended with title from Begin)
+ progress = vim.ringbuf(50),
+
+ ---@deprecated use client.progress instead
messages = { name = name, messages = {}, progress = {}, status = {} },
dynamic_capabilities = require('vim.lsp._dynamic').new(client_id),
}
+
+ ---@type table<string|integer, string> title of unfinished progress sequences by token
+ client.progress.pending = {}
+
--- @type lsp.ClientCapabilities
client.config.capabilities = config.capabilities or protocol.make_client_capabilities()