From 083035fd06d27487a976953ede615c4fa1755988 Mon Sep 17 00:00:00 2001 From: Steffen Lyngbaek Date: Fri, 13 Mar 2020 16:03:02 -0700 Subject: Use WorkDoneProgress LSP API for initial load Addresses #3283 Rather than using custom UI for showing the loaded state. Rely on the WorkDoneProgress API in 3.15.0 https://microsoft.github.io/language-server-protocol/specification#workDoneProgress. No client-side work was necessary. The UI is not exactly what is described in the issue but afaict that's how VS Code implements the LSP API. - The WorkDoneProgressEnd does not appear to display its message contents (controlled by vscode) --- crates/rust-analyzer/src/main_loop.rs | 71 ++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 2b3b16d35..eb41e3cda 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -16,7 +16,10 @@ use std::{ use crossbeam_channel::{select, unbounded, RecvError, Sender}; use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; -use lsp_types::{ClientCapabilities, NumberOrString}; +use lsp_types::{ + ClientCapabilities, NumberOrString, WorkDoneProgress, WorkDoneProgressBegin, + WorkDoneProgressCreateParams, WorkDoneProgressEnd, WorkDoneProgressReport, +}; use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask}; use ra_ide::{Canceled, FileId, InlayHintsOptions, LibraryData, SourceRootId}; use ra_prof::profile; @@ -329,6 +332,7 @@ struct LoopState { in_flight_libraries: usize, pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc)>)>, workspace_loaded: bool, + roots_scanned_progress: Option, } impl LoopState { @@ -428,11 +432,6 @@ fn loop_turn( && loop_state.in_flight_libraries == 0 { loop_state.workspace_loaded = true; - let n_packages: usize = world_state.workspaces.iter().map(|it| it.n_packages()).sum(); - if world_state.feature_flags.get("notifications.workspace-loaded") { - let msg = format!("workspace loaded, {} rust packages", n_packages); - show_message(req::MessageType::Info, msg, &connection.sender); - } world_state.check_watcher.update(); pool.execute({ let subs = loop_state.subscriptions.subscriptions(); @@ -440,6 +439,7 @@ fn loop_turn( move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ()) }); } + send_startup_progress(&connection.sender, loop_state, world_state); if state_changed { update_file_notifications_on_threadpool( @@ -703,6 +703,65 @@ fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender, state: } } +fn send_startup_progress( + sender: &Sender, + loop_state: &mut LoopState, + world_state: &WorldState, +) { + if !world_state.feature_flags.get("notifications.workspace-loaded") { + return; + } + let total: usize = world_state.workspaces.iter().map(|it| it.n_packages()).sum(); + let progress = total - world_state.roots_to_scan; + if loop_state.roots_scanned_progress == Some(progress) { + return; + } + loop_state.roots_scanned_progress = Some(progress); + + match (progress, loop_state.workspace_loaded) { + (0, false) => { + let work_done_progress_create = request_new::( + loop_state.next_request_id(), + WorkDoneProgressCreateParams { + token: req::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 as f64 * progress as f64 / total as f64), + }), + ); + } + (_, false) => send_startup_progress_notif( + sender, + WorkDoneProgress::Report(WorkDoneProgressReport { + cancellable: None, + message: Some(format!("{}/{} packages", progress, total)), + percentage: Some(100 as f64 * 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, work_done_progress: WorkDoneProgress) { + let notif = notification_new::(req::ProgressParams { + token: req::ProgressToken::String("rustAnalyzer/startup".into()), + value: req::ProgressParamsValue::WorkDone(work_done_progress), + }); + sender.send(notif.into()).unwrap(); +} + struct PoolDispatcher<'a> { req: Option, pool: &'a ThreadPool, -- cgit v1.2.3