From 1a6cd7333429d0b102eaaa30ff96841ed46569b7 Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Fri, 19 Jan 2024 16:28:27 +0100 Subject: [PATCH] Cancel language server requests if request is dropped Before this change, we would send requests to language servers without canceling them even if we never wait for their response. Example: when doing document highlights, we'd send a request (modulo debouncing) whenever a change was made, ignoring previously sent requests that might still be in-flight. With this change, we now send a Cancel request (from the LSP spec) to the language server in case no one listens to the response anymore (which is what happens when the `Future` returned by `request_internal`) is dropped. --- crates/lsp/src/lsp.rs | 14 ++++++++++++++ crates/util/src/util.rs | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index a70422008c..31b85b180b 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -863,17 +863,31 @@ impl LanguageServer { .try_send(message) .context("failed to write to language server's stdin"); + let outbound_tx = outbound_tx.downgrade(); let mut timeout = executor.timer(LSP_REQUEST_TIMEOUT).fuse(); let started = Instant::now(); async move { handle_response?; send?; + let cancel_on_drop = util::defer(move || { + if let Some(outbound_tx) = outbound_tx.upgrade() { + Self::notify_internal::( + &outbound_tx, + CancelParams { + id: NumberOrString::Number(id as i32), + }, + ) + .log_err(); + } + }); + let method = T::METHOD; futures::select! { response = rx.fuse() => { let elapsed = started.elapsed(); log::trace!("Took {elapsed:?} to receive response to {method:?} id {id}"); + cancel_on_drop.abort(); response? } diff --git a/crates/util/src/util.rs b/crates/util/src/util.rs index a2f8b87fee..ccf612e16a 100644 --- a/crates/util/src/util.rs +++ b/crates/util/src/util.rs @@ -299,7 +299,7 @@ pub struct Deferred(Option); impl Deferred { /// Drop without running the deferred function. - pub fn cancel(mut self) { + pub fn abort(mut self) { self.0.take(); } }