summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/lsp/tsc.rs21
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)?)
}
}