Auto merge of #13427 - Veykril:cancel-check, r=Veykril

feat: Make flycheck workdone progress reports cancellable

In clients that support this (like VSCode), the clients will now render a cancel button on the notification message which can be clicked to cancel the flycheck instead.

Closes https://github.com/rust-lang/rust-analyzer/issues/6895
![Code_VbXgP3SbFD](https://user-images.githubusercontent.com/3757771/196205329-2df93451-c143-4d1b-a700-d988edf55efa.gif)
This commit is contained in:
bors 2022-10-17 14:41:57 +00:00
commit 106285b5c4
2 changed files with 28 additions and 8 deletions

View File

@ -87,6 +87,7 @@ impl GlobalState {
state: Progress,
message: Option<String>,
fraction: Option<f64>,
cancel_token: Option<String>,
) {
if !self.config.work_done_progress() {
return;
@ -95,7 +96,10 @@ impl GlobalState {
assert!((0.0..=1.0).contains(&f));
(f * 100.0) as u32
});
let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title));
let cancellable = Some(cancel_token.is_some());
let token = lsp_types::ProgressToken::String(
cancel_token.unwrap_or_else(|| format!("rustAnalyzer/{}", title)),
);
let work_done_progress = match state {
Progress::Begin => {
self.send_request::<lsp_types::request::WorkDoneProgressCreate>(
@ -105,14 +109,14 @@ impl GlobalState {
lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin {
title: title.into(),
cancellable: None,
cancellable,
message,
percentage,
})
}
Progress::Report => {
lsp_types::WorkDoneProgress::Report(lsp_types::WorkDoneProgressReport {
cancellable: None,
cancellable,
message,
percentage,
})

View File

@ -257,7 +257,7 @@ impl GlobalState {
}
};
self.report_progress("Indexing", state, message, Some(fraction));
self.report_progress("Indexing", state, message, Some(fraction), None);
}
}
Event::Vfs(message) => {
@ -465,7 +465,7 @@ impl GlobalState {
}
};
self.report_progress("Fetching", state, msg, None);
self.report_progress("Fetching", state, msg, None, None);
}
Task::FetchBuildData(progress) => {
let (state, msg) = match progress {
@ -481,7 +481,7 @@ impl GlobalState {
};
if let Some(state) = state {
self.report_progress("Loading", state, msg, None);
self.report_progress("Loading", state, msg, None, None);
}
}
}
@ -518,6 +518,7 @@ impl GlobalState {
state,
Some(format!("{}/{}", n_done, n_total)),
Some(Progress::fraction(n_done, n_total)),
None,
)
}
}
@ -584,7 +585,13 @@ impl GlobalState {
} else {
format!("cargo check (#{})", id + 1)
};
self.report_progress(&title, state, message, None);
self.report_progress(
&title,
state,
message,
None,
Some(format!("rust-analyzer/checkOnSave/{}", id)),
);
}
}
}
@ -698,7 +705,16 @@ impl GlobalState {
this.cancel(id);
Ok(())
})?
.on::<lsp_types::notification::WorkDoneProgressCancel>(|_this, _params| {
.on::<lsp_types::notification::WorkDoneProgressCancel>(|this, params| {
if let lsp_types::NumberOrString::String(s) = &params.token {
if let Some(id) = s.strip_prefix("rust-analyzer/checkOnSave/") {
if let Ok(id) = u32::from_str_radix(id, 10) {
if let Some(flycheck) = this.flycheck.get(id as usize) {
flycheck.cancel();
}
}
}
}
// Just ignore this. It is OK to continue sending progress
// notifications for this token, as the client can't know when
// we accepted notification.