-
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 $/progress #176
Comments
Thanks for opening this issue! It's a good idea to track this for the sake of completeness, regardless of priority. |
I think it should be pretty trivial to expose a server-to-client progress notification API in the form of a new #[derive(Default)]
pub struct ProgressDetails {
pub title: String,
pub message: Option<String>,
pub cancellable: Option<bool>,
}
impl Client {
/// Wraps a stream and reports `$/progress` notifications to the client, using `count` to calculate percentage.
pub fn progress_count<T, S>(&self, stream: S, count: u64, details: ProgressDetails) -> impl Stream<Item = T> + Send + Unpin + '_
where
S: Stream<Item = T> + Send + Unpin;
} EDIT: Learned some more about the API, and I realize that this snippet isn't really suitable for all use cases. It would have to be redesigned to be like this instead: #[derive(Default)]
pub struct ProgressDetails {
pub title: String,
pub message: Option<String>,
pub cancellable: Option<bool>,
}
impl Client {
/// Wraps a stream and reports `$/progress` notifications to the client, using `count` to calculate percentage.
pub fn progress_count<T, S, F>(&self, stream: S, count: u64, details: F) -> impl Stream<Item = T> + Send + Unpin + '_
where
S: Stream<Item = T> + Send + Unpin,
F: FnMut(&T) -> ProgressDetails;
} |
Just mentioning that this would be super helpful for my project. |
In addition, perhaps we could return a more manual API like this: impl Client {
pub fn progress<T, M>(&self, title: T, message: M) -> Progress
where
T: Into<String>,
M: Into<Option<String>>;
}
pub struct Progress<P = Infinite, C = NotCancelable> { ... }
impl<C> Progress<Infinite, C> {
pub fn bounded(self, start_percentage: u32) -> Progress<Bounded, C>;
}
impl<P> Progress<P, NotCancelable> {
pub fn cancelable(self, show_cancel_btn: bool) -> Progress<P, Cancelable>;
}
impl<P, C> Progress<P, C> {
pub async fn begin(self) -> ProgressStarted<P, C>;
}
pub struct ProgressStarted<P, C> { ... }
impl ProgressStarted<Infinite, NotCancelable> {
pub async fn report<M>(&self, message: M)
where
M: Into<Option<String>>;
}
impl ProgressStarted<Infinite, Cancelable> {
pub async fn report<M>(&self, message: M, show_cancel_btn: bool)
where
M: Into<Option<String>>;
}
impl ProgressStarted<Bounded, NotCancelable> {
pub async fn report<M>(&self, percentage: u32, message: M)
where
M: Into<Option<String>>;
}
impl ProgressStarted<Bounded, Cancellable> {
pub async fn report<M>(&self, percentage: u32, message: M, show_cancel_btn: bool)
where
M: Into<Option<String>>;
}
impl<P, C> ProgressStarted<P, C> {
pub fn token(&self) -> &ProgressToken;
pub async fn finish(self, message: M)
where
M: Into<Option<String>>;
} The final usage would be quite ergonomic, and also type safe: impl LanguageServer for Backend {
async fn completion(&self, _: CompletionParams) -> Result<Option<CompletionResponse>> {
let progress = self
.client
.progress("retrieving completions", "starting work...".into())
.bounded(0)
.begin()
.await;
for x in something {
// Do some work...
let percentage = ...
progress.report(percentage, "reticulating splines".into()).await;
}
progress.finish("done!".into()).await;
// ...
} I'm sure we could bikeshed whether the Any feedback, @silvanshade @wiseman? |
Now, according to the specification, it's technically possible for a As such, maybe we could also add methods to the impl<C> ProgressStarted<Bounded, C> {
pub fn infinite(self) -> ProgressStarted<Infinite, C>;
}
impl<P> ProgressStarted<P, Cancellable> {
pub fn not_cancellable(self) -> ProgressStarted<P, NotCancellable>;
} These methods would allow the user to switch an active progress bar over to being infinite and/or not cancellable at any point, and this would downgrade the |
If you're looking for contributions, I'd be interested in taking a stab at implementing this. |
FWIW, I implemented it in the following commit just using send_request/send_notification + lsp-types API. |
Is there any progress to this? This functionality is quite necessary when the loading costs more than seconds. |
@oxalica I assume it might not be a high priority since you can implement it in terms of the following without the additional ergonomics/friendlier API, as in the commit referenced in my previous comment here.
So if it is really necessary it isn't too difficult to implement on top of what is already working today without the details discussed above. |
I implemented progress by reference to nimbleparse_lsp. ( Thanks @ratmice ! ) The implementation is very simple.
|
This ticket is currently conflating two different types of progress described by the LSP specification:
I'm thinking this issue should be split into two separate tickets for better tracking:
Does this sound reasonable to you folks? |
Seems good to me, I wasn't actually aware of client side progress! |
It would be nice to be able to support progress notifications. I haven't looked into what sort of modifications would be needed for this but it seems like it should have an issue for the sake of completeness.
The text was updated successfully, but these errors were encountered: