diff options
author | Nayeem Rahman <nayeemrmn99@gmail.com> | 2023-11-30 03:35:39 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-30 03:35:39 +0000 |
commit | 595a2be024b3523197557a8b122e3ce77f1dae3c (patch) | |
tree | dc47ae9b95dd56b8f488b3939e493b175bc32e2b | |
parent | 6718be87c8468b8ed27548e350c62ad86287a900 (diff) |
perf(lsp): cancel ts requests on future drop (#21387)
When an old request is obsoleted while the user is typing, the client
will say so to the server and tower-lsp will drop the future associated
with that request.
This wires that up to the ts server by having any request's token be
cancelled when the surrounding state is dropped.
-rw-r--r-- | cli/lsp/tsc.rs | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index b67b634e1..a907292e0 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -231,8 +231,12 @@ impl TsServer { start(&mut ts_runtime, false).unwrap(); started = true; } - let value = request(&mut ts_runtime, state_snapshot, req, token); - if tx.send(value).is_err() { + let value = + request(&mut ts_runtime, state_snapshot, req, token.clone()); + let was_sent = tx.send(value).is_ok(); + // Don't print the send error if the token is cancelled, it's expected + // to fail in that case and this commonly occurs. + if !was_sent && !token.is_cancelled() { lsp_warn!("Unable to send result to client."); } } @@ -968,11 +972,24 @@ impl TsServer { where R: de::DeserializeOwned, { + // When an LSP request is cancelled by the client, the future this is being + // executed under and any local variables here will be dropped at the next + // await point. To pass on that cancellation to the TS thread, we make this + // wrapper which cancels the request's token on drop. + struct DroppableToken(CancellationToken); + impl Drop for DroppableToken { + fn drop(&mut self) { + self.0.cancel(); + } + } + let token = token.child_token(); + let droppable_token = DroppableToken(token.clone()); let (tx, rx) = oneshot::channel::<Result<Value, AnyError>>(); if self.sender.send((req, snapshot, tx, token)).is_err() { return Err(anyhow!("failed to send request to tsc thread")); } let value = rx.await??; + drop(droppable_token); Ok(serde_json::from_value::<R>(value)?) } } |