Migrate flycheck to fully-lsp-compatible progress reports (introduce ra_progress crate)
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
mod handlers;
|
||||
mod subscriptions;
|
||||
pub(crate) mod pending_requests;
|
||||
mod progress;
|
||||
mod lsp_utils;
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
@@ -44,6 +46,9 @@ use crate::{
|
||||
},
|
||||
Result,
|
||||
};
|
||||
pub use lsp_utils::show_message;
|
||||
use lsp_utils::{is_canceled, notification_cast, notification_is, notification_new, request_new};
|
||||
use progress::{IsDone, PrimeCachesProgressNotifier, WorkspaceAnalysisProgressNotifier};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LspError {
|
||||
@@ -90,6 +95,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
|
||||
}
|
||||
|
||||
let mut loop_state = LoopState::default();
|
||||
|
||||
let mut global_state = {
|
||||
let workspaces = {
|
||||
if config.linked_projects.is_empty() && config.notifications.cargo_toml_not_found {
|
||||
@@ -164,6 +170,12 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
|
||||
};
|
||||
|
||||
loop_state.roots_total = global_state.vfs.read().n_roots();
|
||||
loop_state.roots_scanned = 0;
|
||||
loop_state.roots_progress = Some(WorkspaceAnalysisProgressNotifier::begin(
|
||||
connection.sender.clone(),
|
||||
loop_state.next_request_id(),
|
||||
loop_state.roots_total,
|
||||
));
|
||||
|
||||
let pool = ThreadPool::default();
|
||||
let (task_sender, task_receiver) = unbounded::<Task>();
|
||||
@@ -271,7 +283,7 @@ struct LoopState {
|
||||
pending_requests: PendingRequests,
|
||||
subscriptions: Subscriptions,
|
||||
workspace_loaded: bool,
|
||||
roots_progress_reported: Option<usize>,
|
||||
roots_progress: Option<WorkspaceAnalysisProgressNotifier>,
|
||||
roots_scanned: usize,
|
||||
roots_total: usize,
|
||||
configuration_request_id: Option<RequestId>,
|
||||
@@ -372,7 +384,7 @@ fn loop_turn(
|
||||
}
|
||||
|
||||
if show_progress {
|
||||
send_startup_progress(&connection.sender, loop_state);
|
||||
send_workspace_analisys_progress(loop_state);
|
||||
}
|
||||
|
||||
if state_changed && loop_state.workspace_loaded {
|
||||
@@ -385,7 +397,22 @@ fn loop_turn(
|
||||
pool.execute({
|
||||
let subs = loop_state.subscriptions.subscriptions();
|
||||
let snap = global_state.snapshot();
|
||||
move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ())
|
||||
|
||||
let total = subs.len();
|
||||
|
||||
let mut progress = PrimeCachesProgressNotifier::begin(
|
||||
connection.sender.clone(),
|
||||
loop_state.next_request_id(),
|
||||
total,
|
||||
);
|
||||
|
||||
move || {
|
||||
snap.analysis()
|
||||
.prime_caches(subs, move |i| {
|
||||
progress.report(i + 1);
|
||||
})
|
||||
.unwrap_or_else(|_: Canceled| ());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -744,55 +771,12 @@ fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state:
|
||||
}
|
||||
}
|
||||
|
||||
fn send_startup_progress(sender: &Sender<Message>, loop_state: &mut LoopState) {
|
||||
let total: usize = loop_state.roots_total;
|
||||
let prev = loop_state.roots_progress_reported;
|
||||
let progress = loop_state.roots_scanned;
|
||||
loop_state.roots_progress_reported = Some(progress);
|
||||
|
||||
match (prev, loop_state.workspace_loaded) {
|
||||
(None, false) => {
|
||||
let work_done_progress_create = request_new::<lsp_types::request::WorkDoneProgressCreate>(
|
||||
loop_state.next_request_id(),
|
||||
WorkDoneProgressCreateParams {
|
||||
token: lsp_types::ProgressToken::String("rustAnalyzer/startup".into()),
|
||||
},
|
||||
);
|
||||
sender.send(work_done_progress_create.into()).unwrap();
|
||||
send_startup_progress_notif(
|
||||
sender,
|
||||
WorkDoneProgress::Begin(WorkDoneProgressBegin {
|
||||
title: "rust-analyzer".into(),
|
||||
cancellable: None,
|
||||
message: Some(format!("{}/{} packages", progress, total)),
|
||||
percentage: Some(100.0 * progress as f64 / total as f64),
|
||||
}),
|
||||
);
|
||||
fn send_workspace_analisys_progress(loop_state: &mut LoopState) {
|
||||
if let Some(progress) = &mut loop_state.roots_progress {
|
||||
if loop_state.workspace_loaded || progress.report(loop_state.roots_scanned) == IsDone(true)
|
||||
{
|
||||
loop_state.roots_progress = None;
|
||||
}
|
||||
(Some(prev), false) if progress != prev => send_startup_progress_notif(
|
||||
sender,
|
||||
WorkDoneProgress::Report(WorkDoneProgressReport {
|
||||
cancellable: None,
|
||||
message: Some(format!("{}/{} packages", progress, total)),
|
||||
percentage: Some(100.0 * progress as f64 / total as f64),
|
||||
}),
|
||||
),
|
||||
(_, true) => send_startup_progress_notif(
|
||||
sender,
|
||||
WorkDoneProgress::End(WorkDoneProgressEnd {
|
||||
message: Some(format!("rust-analyzer loaded, {} packages", progress)),
|
||||
}),
|
||||
),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
fn send_startup_progress_notif(sender: &Sender<Message>, work_done_progress: WorkDoneProgress) {
|
||||
let notif =
|
||||
notification_new::<lsp_types::notification::Progress>(lsp_types::ProgressParams {
|
||||
token: lsp_types::ProgressToken::String("rustAnalyzer/startup".into()),
|
||||
value: lsp_types::ProgressParamsValue::WorkDone(work_done_progress),
|
||||
});
|
||||
sender.send(notif.into()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,7 +902,7 @@ where
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if is_canceled(&e) {
|
||||
if is_canceled(&*e) {
|
||||
Response::new_err(
|
||||
id,
|
||||
ErrorCode::ContentModified as i32,
|
||||
@@ -945,7 +929,7 @@ fn update_file_notifications_on_threadpool(
|
||||
for file_id in subscriptions {
|
||||
match handlers::publish_diagnostics(&world, file_id) {
|
||||
Err(e) => {
|
||||
if !is_canceled(&e) {
|
||||
if !is_canceled(&*e) {
|
||||
log::error!("failed to compute diagnostics: {:?}", e);
|
||||
}
|
||||
}
|
||||
@@ -958,49 +942,6 @@ fn update_file_notifications_on_threadpool(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_message(
|
||||
typ: lsp_types::MessageType,
|
||||
message: impl Into<String>,
|
||||
sender: &Sender<Message>,
|
||||
) {
|
||||
let message = message.into();
|
||||
let params = lsp_types::ShowMessageParams { typ, message };
|
||||
let not = notification_new::<lsp_types::notification::ShowMessage>(params);
|
||||
sender.send(not.into()).unwrap();
|
||||
}
|
||||
|
||||
fn is_canceled(e: &Box<dyn std::error::Error + Send + Sync>) -> bool {
|
||||
e.downcast_ref::<Canceled>().is_some()
|
||||
}
|
||||
|
||||
fn notification_is<N: lsp_types::notification::Notification>(notification: &Notification) -> bool {
|
||||
notification.method == N::METHOD
|
||||
}
|
||||
|
||||
fn notification_cast<N>(notification: Notification) -> std::result::Result<N::Params, Notification>
|
||||
where
|
||||
N: lsp_types::notification::Notification,
|
||||
N::Params: DeserializeOwned,
|
||||
{
|
||||
notification.extract(N::METHOD)
|
||||
}
|
||||
|
||||
fn notification_new<N>(params: N::Params) -> Notification
|
||||
where
|
||||
N: lsp_types::notification::Notification,
|
||||
N::Params: Serialize,
|
||||
{
|
||||
Notification::new(N::METHOD.to_string(), params)
|
||||
}
|
||||
|
||||
fn request_new<R>(id: RequestId, params: R::Params) -> Request
|
||||
where
|
||||
R: lsp_types::request::Request,
|
||||
R::Params: Serialize,
|
||||
{
|
||||
Request::new(id, R::METHOD.to_string(), params)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::borrow::Cow;
|
||||
|
||||
Reference in New Issue
Block a user