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 /cli/lsp/tsc.rs | |
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.
Diffstat (limited to 'cli/lsp/tsc.rs')
-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)?) } } |