-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement support for $/cancelRequest (for client requests) #231
Comments
Just to expand on this a bit, I think you could define use tokio::sync::watch;
#[derive(Debug, Clone)]
enum Signal {
Init,
Cancel,
}
struct CancellationToken {
tx: watch::Sender<Signal>,
pub rx: watch::Receiver<Signal>,
}
impl CancellationToken {
pub fn new() -> Self {
let (tx, rx) = watch::channel(Signal::Init);
CancellationToken {
tx,
rx,
}
}
pub fn cancel(&self) {
self.tx.broadcast(Signal::Cancel);
}
} The signature for async fn send_request<R>(&self, params: R::Params, token: Option<&CancellationToken>) -> Result<R::Result>
where
R: Request; The idea here is that you should be able to use the same cancellation token for multiple requests (by cloning |
After a bit more digging through the specification, I actually wonder whether a
|
I think there are a few possible ways forward with this task that may merit further discussion. First, I would like to reiterate my points from the comment above: we must adhere closely to the official LSP specification and signal cancellation to the client by emitting a real struct CancellationTokenInner {
request_id: Id,
is_canceled: AtomicBool,
client: Client,
}
#[derive(Clone)]
pub struct CancellationToken {
inner: Arc<CancellationTokenInner>,
}
impl CancellationToken {
pub fn is_canceled(&self) -> bool {
self.inner.is_canceled.load(Ordering::SeqCst)
}
pub async fn cancel(self) {
if self.inner.is_canceled.swap(true, Ordering::SeqCst) {
// Canceled already, should not send another notification.
return;
}
self.inner
.client
.send_notification::<Cancel>(CancelParams { id: id.into() })
.await;
}
} The real question is how to expose this to the user in an ergonomic way. I see two possible options here: Option 1:
|
Just letting you know that I like you how much thought you're putting into this. I would probably also lean to the latter pattern, but that is a very uninformed opinion, so just do whatever you think fits best. |
Support for canceling server requests (from the client to the server) was implemented when #145 was resolved.
However, the LSP spec for
$/cancelRequest
allows for server request (from the server to the client) to also be canceled.This would especially be useful with
send_custom_request
per #230.I'm not sure exactly how this would be implemented but I suppose the
ClientRequests
struct would need to be modified to work withfuture::AbortHandle
, similar toServerRequests
, and a correspondingcancel
method added to theimpl ClientRequests
.As far as actually canceling requests goes, it would probably be good to have an interface similar to how microsoft/vscode-languageserver-node does it (see here), to where you can create a "cancellation token" prior to sending the request, and then that token would become an argument to
send_request
(and its derivatives).The actual cancelation call would then be
token.cancel()
, which would cause the response to resolve as aRequestCancelled
error (after the client properly responds to$/cancelRequest
).Does that seem feasible?
The text was updated successfully, but these errors were encountered: