use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use ls_types::{
ProgressParams, ProgressParamsValue, ProgressToken, WorkDoneProgress, WorkDoneProgressBegin,
WorkDoneProgressEnd, WorkDoneProgressReport, notification::Progress as ProgressNotification,
};
use super::Client;
#[doc(hidden)]
#[derive(Debug)]
pub enum Bounded {}
#[doc(hidden)]
#[derive(Debug)]
pub enum Unbounded {}
#[doc(hidden)]
#[derive(Debug)]
pub enum Cancellable {}
#[doc(hidden)]
#[derive(Debug)]
pub enum NotCancellable {}
#[must_use = "progress is not reported until `.begin()` is called"]
pub struct Progress<B = Unbounded, C = NotCancellable> {
client: Client,
token: ProgressToken,
begin_msg: WorkDoneProgressBegin,
_kind: PhantomData<(B, C)>,
}
impl Progress {
pub(crate) const fn new(client: Client, token: ProgressToken, title: String) -> Self {
Self {
client,
token,
begin_msg: WorkDoneProgressBegin {
title,
cancellable: Some(false),
message: None,
percentage: None,
},
_kind: PhantomData,
}
}
}
impl<C> Progress<Unbounded, C> {
pub fn with_percentage(self, start_percentage: u32) -> Progress<Bounded, C> {
Progress {
client: self.client,
token: self.token,
begin_msg: WorkDoneProgressBegin {
percentage: Some(start_percentage),
..self.begin_msg
},
_kind: PhantomData,
}
}
}
impl<B> Progress<B, NotCancellable> {
pub fn with_cancel_button(self) -> Progress<B, Cancellable> {
Progress {
client: self.client,
token: self.token,
begin_msg: WorkDoneProgressBegin {
cancellable: Some(true),
..self.begin_msg
},
_kind: PhantomData,
}
}
}
impl<B, C> Progress<B, C> {
pub fn with_message<M>(mut self, message: M) -> Self
where
M: Into<String>,
{
self.begin_msg.message = Some(message.into());
self
}
pub async fn begin(self) -> OngoingProgress<B, C> {
self.client
.send_notification::<ProgressNotification>(ProgressParams {
token: self.token.clone(),
value: ProgressParamsValue::WorkDone(WorkDoneProgress::Begin(self.begin_msg)),
})
.await;
OngoingProgress {
client: self.client,
token: self.token,
_kind: PhantomData,
}
}
}
impl<B, C> Debug for Progress<B, C> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct(stringify!(Progress))
.field("token", &self.token)
.field("properties", &self.begin_msg)
.finish_non_exhaustive()
}
}
#[must_use = "ongoing progress is not reported until `.report()` and/or `.finish()` is called"]
pub struct OngoingProgress<B, C> {
client: Client,
token: ProgressToken,
_kind: PhantomData<(B, C)>,
}
impl<B: Sync, C: Sync> OngoingProgress<B, C> {
async fn send_progress_report(&self, report: WorkDoneProgressReport) {
self.client
.send_notification::<ProgressNotification>(ProgressParams {
token: self.token.clone(),
value: ProgressParamsValue::WorkDone(WorkDoneProgress::Report(report)),
})
.await;
}
}
impl OngoingProgress<Unbounded, NotCancellable> {
pub async fn report<M>(&self, message: M)
where
M: Into<String>,
{
self.send_progress_report(WorkDoneProgressReport {
message: Some(message.into()),
..Default::default()
})
.await;
}
}
impl OngoingProgress<Unbounded, Cancellable> {
pub async fn report(&self, enable_cancel_btn: bool) {
self.send_progress_report(WorkDoneProgressReport {
cancellable: Some(enable_cancel_btn),
..Default::default()
})
.await;
}
pub async fn report_with_message<M>(&self, message: M, enable_cancel_btn: Option<bool>)
where
M: Into<String>,
{
self.send_progress_report(WorkDoneProgressReport {
cancellable: enable_cancel_btn,
message: Some(message.into()),
..Default::default()
})
.await;
}
}
impl OngoingProgress<Bounded, NotCancellable> {
pub async fn report(&self, percentage: u32) {
self.send_progress_report(WorkDoneProgressReport {
percentage: Some(percentage),
..Default::default()
})
.await;
}
pub async fn report_with_message<M>(&self, message: M, percentage: u32)
where
M: Into<String>,
{
self.send_progress_report(WorkDoneProgressReport {
message: Some(message.into()),
percentage: Some(percentage),
..Default::default()
})
.await;
}
}
impl OngoingProgress<Bounded, Cancellable> {
pub async fn report(&self, percentage: u32, enable_cancel_btn: Option<bool>) {
self.send_progress_report(WorkDoneProgressReport {
cancellable: enable_cancel_btn,
message: None,
percentage: Some(percentage),
})
.await;
}
pub async fn report_with_message<M>(
&self,
message: M,
percentage: u32,
enable_cancel_btn: Option<bool>,
) where
M: Into<String>,
{
self.send_progress_report(WorkDoneProgressReport {
cancellable: enable_cancel_btn,
message: Some(message.into()),
percentage: Some(percentage),
})
.await;
}
}
impl<C> OngoingProgress<Bounded, C> {
pub fn into_unbounded(self) -> OngoingProgress<Unbounded, C> {
OngoingProgress {
client: self.client,
token: self.token,
_kind: PhantomData,
}
}
}
impl<B, C> OngoingProgress<B, C> {
pub async fn finish(self) {
self.finish_inner(None).await;
}
pub async fn finish_with_message<M>(self, message: M)
where
M: Into<String>,
{
self.finish_inner(Some(message.into())).await;
}
async fn finish_inner(self, message: Option<String>) {
self.client
.send_notification::<ProgressNotification>(ProgressParams {
token: self.token,
value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(WorkDoneProgressEnd {
message,
})),
})
.await;
}
#[must_use]
pub const fn token(&self) -> &ProgressToken {
&self.token
}
}
impl<B, C> Debug for OngoingProgress<B, C> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct(stringify!(OngoingProgress))
.field("token", &self.token)
.finish_non_exhaustive()
}
}