aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/rust-analyzer/src/main_loop.rs73
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/support.rs15
2 files changed, 77 insertions, 11 deletions
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index eb29e8322..1fefc66aa 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -16,7 +16,10 @@ use std::{
16 16
17use crossbeam_channel::{select, unbounded, RecvError, Sender}; 17use crossbeam_channel::{select, unbounded, RecvError, Sender};
18use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; 18use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
19use lsp_types::{ClientCapabilities, NumberOrString}; 19use lsp_types::{
20 ClientCapabilities, NumberOrString, WorkDoneProgress, WorkDoneProgressBegin,
21 WorkDoneProgressCreateParams, WorkDoneProgressEnd, WorkDoneProgressReport,
22};
20use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask}; 23use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask};
21use ra_ide::{Canceled, FileId, InlayHintsOptions, LibraryData, SourceRootId}; 24use ra_ide::{Canceled, FileId, InlayHintsOptions, LibraryData, SourceRootId};
22use ra_prof::profile; 25use ra_prof::profile;
@@ -330,6 +333,7 @@ struct LoopState {
330 in_flight_libraries: usize, 333 in_flight_libraries: usize,
331 pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>, 334 pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>,
332 workspace_loaded: bool, 335 workspace_loaded: bool,
336 roots_scanned_progress: Option<usize>,
333} 337}
334 338
335impl LoopState { 339impl LoopState {
@@ -429,17 +433,15 @@ fn loop_turn(
429 && loop_state.in_flight_libraries == 0 433 && loop_state.in_flight_libraries == 0
430 { 434 {
431 loop_state.workspace_loaded = true; 435 loop_state.workspace_loaded = true;
432 let n_packages: usize = world_state.workspaces.iter().map(|it| it.n_packages()).sum();
433 if world_state.feature_flags.get("notifications.workspace-loaded") {
434 let msg = format!("workspace loaded, {} rust packages", n_packages);
435 show_message(req::MessageType::Info, msg, &connection.sender);
436 }
437 world_state.check_watcher.update(); 436 world_state.check_watcher.update();
438 pool.execute({ 437 pool.execute({
439 let subs = loop_state.subscriptions.subscriptions(); 438 let subs = loop_state.subscriptions.subscriptions();
440 let snap = world_state.snapshot(); 439 let snap = world_state.snapshot();
441 move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ()) 440 move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ())
442 }); 441 });
442 send_startup_progress(&connection.sender, loop_state, world_state);
443 } else if !loop_state.workspace_loaded {
444 send_startup_progress(&connection.sender, loop_state, world_state);
443 } 445 }
444 446
445 if state_changed { 447 if state_changed {
@@ -704,6 +706,65 @@ fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state:
704 } 706 }
705} 707}
706 708
709fn send_startup_progress(
710 sender: &Sender<Message>,
711 loop_state: &mut LoopState,
712 world_state: &WorldState,
713) {
714 if !world_state.feature_flags.get("notifications.workspace-loaded") {
715 return;
716 }
717
718 let total: usize = world_state.workspaces.iter().map(|it| it.n_packages()).sum();
719 let prev_progress = loop_state.roots_scanned_progress;
720 let progress = total - world_state.roots_to_scan;
721 loop_state.roots_scanned_progress = Some(progress);
722
723 match (prev_progress, loop_state.workspace_loaded) {
724 (None, false) => {
725 let work_done_progress_create = request_new::<req::WorkDoneProgressCreate>(
726 loop_state.next_request_id(),
727 WorkDoneProgressCreateParams {
728 token: req::ProgressToken::String("rustAnalyzer/startup".into()),
729 },
730 );
731 sender.send(work_done_progress_create.into()).unwrap();
732 send_startup_progress_notif(
733 sender,
734 WorkDoneProgress::Begin(WorkDoneProgressBegin {
735 title: "rust-analyzer".into(),
736 cancellable: None,
737 message: Some(format!("{}/{} packages", progress, total)),
738 percentage: Some(100.0 * progress as f64 / total as f64),
739 }),
740 );
741 }
742 (Some(prev), false) if progress != prev => send_startup_progress_notif(
743 sender,
744 WorkDoneProgress::Report(WorkDoneProgressReport {
745 cancellable: None,
746 message: Some(format!("{}/{} packages", progress, total)),
747 percentage: Some(100.0 * progress as f64 / total as f64),
748 }),
749 ),
750 (_, true) => send_startup_progress_notif(
751 sender,
752 WorkDoneProgress::End(WorkDoneProgressEnd {
753 message: Some(format!("rust-analyzer loaded, {} packages", progress)),
754 }),
755 ),
756 _ => {}
757 }
758}
759
760fn send_startup_progress_notif(sender: &Sender<Message>, work_done_progress: WorkDoneProgress) {
761 let notif = notification_new::<req::Progress>(req::ProgressParams {
762 token: req::ProgressToken::String("rustAnalyzer/startup".into()),
763 value: req::ProgressParamsValue::WorkDone(work_done_progress),
764 });
765 sender.send(notif.into()).unwrap();
766}
767
707struct PoolDispatcher<'a> { 768struct PoolDispatcher<'a> {
708 req: Option<Request>, 769 req: Option<Request>,
709 pool: &'a ThreadPool, 770 pool: &'a ThreadPool,
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs
index e28ae61fe..1d7062bdf 100644
--- a/crates/rust-analyzer/tests/heavy_tests/support.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/support.rs
@@ -12,13 +12,14 @@ use lsp_types::{
12 notification::{DidOpenTextDocument, Exit}, 12 notification::{DidOpenTextDocument, Exit},
13 request::Shutdown, 13 request::Shutdown,
14 ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities, 14 ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities,
15 TextDocumentIdentifier, TextDocumentItem, Url, 15 TextDocumentIdentifier, TextDocumentItem, Url, WorkDoneProgress,
16}; 16};
17use serde::Serialize; 17use serde::Serialize;
18use serde_json::{to_string_pretty, Value}; 18use serde_json::{to_string_pretty, Value};
19use tempfile::TempDir; 19use tempfile::TempDir;
20use test_utils::{find_mismatch, parse_fixture}; 20use test_utils::{find_mismatch, parse_fixture};
21 21
22use req::{ProgressParams, ProgressParamsValue};
22use rust_analyzer::{main_loop, req, ServerConfig}; 23use rust_analyzer::{main_loop, req, ServerConfig};
23 24
24pub struct Project<'a> { 25pub struct Project<'a> {
@@ -201,10 +202,14 @@ impl Server {
201 } 202 }
202 pub fn wait_until_workspace_is_loaded(&self) { 203 pub fn wait_until_workspace_is_loaded(&self) {
203 self.wait_for_message_cond(1, &|msg: &Message| match msg { 204 self.wait_for_message_cond(1, &|msg: &Message| match msg {
204 Message::Notification(n) if n.method == "window/showMessage" => { 205 Message::Notification(n) if n.method == "$/progress" => {
205 let msg = 206 match n.clone().extract::<ProgressParams>("$/progress").unwrap() {
206 n.clone().extract::<req::ShowMessageParams>("window/showMessage").unwrap(); 207 ProgressParams {
207 msg.message.starts_with("workspace loaded") 208 token: req::ProgressToken::String(ref token),
209 value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(_)),
210 } if token == "rustAnalyzer/startup" => true,
211 _ => false,
212 }
208 } 213 }
209 _ => false, 214 _ => false,
210 }) 215 })