diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 98a0801013..581cfd5348 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -619,19 +619,54 @@ to the callback in the "data" table. The token fields are documented in Note: doing anything other than calling |vim.lsp.semantic_tokens.highlight_token()| is considered experimental. -Also the following |User| |autocommand|s are provided: + +LspRequest *LspRequest* + +For each request sent to an LSP server, this event is triggered for every +change to the request's status. The status can be one of `pending`, +`complete`, or `cancel` and is sent as the {type} on the "data" table passed +to the callback function. + +It triggers when the initial request is sent ({type} == `pending`) and when +the LSP server responds ({type} == `complete`). If a cancelation is requested +using `client.cancel_request(request_id)`, then this event will trigger with +{type} == `cancel`. + +When used from Lua, the client ID, request ID, and request are sent in the +"data" table. See {requests} in |vim.lsp.client| for details on the {request} +value. If the request type is `complete`, the request will be deleted from the +client's pending requests table immediately after calling the event's +callbacks. Example: >lua + + vim.api.nvim_create_autocmd('LspRequest', { + callback = function(args) + local bufnr = args.buf + local client_id = args.data.client_id + local request_id = args.data.request_id + local request = args.data.request + if request.type == 'pending' then + -- do something with pending requests + track_pending(client_id, bufnr, request_id, request) + elseif request.type == 'cancel' then + -- do something with pending cancel requests + track_canceling(client_id, bufnr, request_id, request) + elseif request.type == 'complete' then + -- do something with finished requests. this pending + -- request entry is about to be removed since it is complete + track_finish(client_id, bufnr, request_id, request) + end + end, + }) +< + +Also the following |User| |autocommand| is provided: LspProgressUpdate *LspProgressUpdate* Upon receipt of a progress notification from the server. See |vim.lsp.util.get_progress_messages()|. -LspRequest *LspRequest* - After a change to the active set of pending LSP requests. See {requests} - in |vim.lsp.client|. - Example: >vim autocmd User LspProgressUpdate redrawstatus - autocmd User LspRequest redrawstatus < ============================================================================== @@ -764,7 +799,9 @@ client() *vim.lsp.client* server. Entries are key-value pairs with the key being the request ID while the value is a table with `type`, `bufnr`, and `method` key-value pairs. `type` is either "pending" for an active request, or - "cancel" for a cancel request. + "cancel" for a cancel request. It will be "complete" ephemerally while + executing |LspRequest| autocmds when replies are received from the + server. • {config} (table): copy of the table that was passed by the user to |vim.lsp.start_client()|. • {server_capabilities} (table): Response from the server sent on diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index b6839ec692..72eb182fa5 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -31,6 +31,9 @@ The following changes may require adaptations in user config or plugins. set keymodel=startsel,stopsel < +• |LspRequest| autocmd was promoted from a |User| autocmd to a first class + citizen. + ============================================================================== ADDED FEATURES *news-added* @@ -80,6 +83,9 @@ The following changes to existing APIs or features add new behavior. • The `workspace/didChangeWatchedFiles` LSP client capability is now enabled by default. +• |LspRequest| autocmd callbacks now contain additional information about the LSP + request status update that occurred. + ============================================================================== REMOVED FEATURES *news-removed* diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 5337abea25..c9ca8cd224 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -799,7 +799,9 @@ end --- to the server. Entries are key-value pairs with the key --- being the request ID while the value is a table with `type`, --- `bufnr`, and `method` key-value pairs. `type` is either "pending" ---- for an active request, or "cancel" for a cancel request. +--- for an active request, or "cancel" for a cancel request. It will +--- be "complete" ephemerally while executing |LspRequest| autocmds +--- when replies are received from the server. --- --- - {config} (table): copy of the table that was passed by the user --- to |vim.lsp.start_client()|. @@ -1408,13 +1410,24 @@ function lsp.start_client(config) { method = method, client_id = client_id, bufnr = bufnr, params = params } ) end, function(request_id) + local request = client.requests[request_id] + request.type = 'complete' + nvim_exec_autocmds('LspRequest', { + buffer = bufnr, + modeline = false, + data = { client_id = client_id, request_id = request_id, request = request }, + }) client.requests[request_id] = nil - nvim_exec_autocmds('User', { pattern = 'LspRequest', modeline = false }) end) if success and request_id then - client.requests[request_id] = { type = 'pending', bufnr = bufnr, method = method } - nvim_exec_autocmds('User', { pattern = 'LspRequest', modeline = false }) + local request = { type = 'pending', bufnr = bufnr, method = method } + client.requests[request_id] = request + nvim_exec_autocmds('LspRequest', { + buffer = bufnr, + modeline = false, + data = { client_id = client_id, request_id = request_id, request = request }, + }) end return success, request_id @@ -1486,7 +1499,11 @@ function lsp.start_client(config) local request = client.requests[id] if request and request.type == 'pending' then request.type = 'cancel' - nvim_exec_autocmds('User', { pattern = 'LspRequest', modeline = false }) + nvim_exec_autocmds('LspRequest', { + buffer = request.bufnr, + modeline = false, + data = { client_id = client_id, request_id = id, request = request }, + }) end return rpc.notify('$/cancelRequest', { id = id }) end diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index aef08be820..048b8d6631 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -72,6 +72,7 @@ return { 'InsertLeavePre', -- just before leaving Insert mode 'LspAttach', -- after an LSP client attaches to a buffer 'LspDetach', -- after an LSP client detaches from a buffer + 'LspRequest', -- after an LSP request is started, canceled, or completed 'LspTokenUpdate', -- after a visible LSP token is updated 'MenuPopup', -- just before popup menu is displayed 'ModeChanged', -- after changing the mode @@ -152,6 +153,7 @@ return { DiagnosticChanged=true, LspAttach=true, LspDetach=true, + LspRequest=true, LspTokenUpdate=true, RecordingEnter=true, RecordingLeave=true, diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 1a7a656d1d..e0ce62c0db 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -948,7 +948,7 @@ describe('LSP', function() test_name = "check_tracked_requests_cleared"; on_init = function(_client) command('let g:requests = 0') - command('autocmd User LspRequest let g:requests+=1') + command('autocmd LspRequest * let g:requests+=1') client = _client client.request("slow_request") eq(1, eval('g:requests'))