Skip to content

Commit 083035f

Browse files
committed
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)
1 parent 2f9f409 commit 083035f

File tree

1 file changed

+65
-6
lines changed

1 file changed

+65
-6
lines changed

crates/rust-analyzer/src/main_loop.rs

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ use std::{
1616

1717
use crossbeam_channel::{select, unbounded, RecvError, Sender};
1818
use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
19-
use lsp_types::{ClientCapabilities, NumberOrString};
19+
use lsp_types::{
20+
ClientCapabilities, NumberOrString, WorkDoneProgress, WorkDoneProgressBegin,
21+
WorkDoneProgressCreateParams, WorkDoneProgressEnd, WorkDoneProgressReport,
22+
};
2023
use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask};
2124
use ra_ide::{Canceled, FileId, InlayHintsOptions, LibraryData, SourceRootId};
2225
use ra_prof::profile;
@@ -329,6 +332,7 @@ struct LoopState {
329332
in_flight_libraries: usize,
330333
pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>,
331334
workspace_loaded: bool,
335+
roots_scanned_progress: Option<usize>,
332336
}
333337

334338
impl LoopState {
@@ -428,18 +432,14 @@ fn loop_turn(
428432
&& loop_state.in_flight_libraries == 0
429433
{
430434
loop_state.workspace_loaded = true;
431-
let n_packages: usize = world_state.workspaces.iter().map(|it| it.n_packages()).sum();
432-
if world_state.feature_flags.get("notifications.workspace-loaded") {
433-
let msg = format!("workspace loaded, {} rust packages", n_packages);
434-
show_message(req::MessageType::Info, msg, &connection.sender);
435-
}
436435
world_state.check_watcher.update();
437436
pool.execute({
438437
let subs = loop_state.subscriptions.subscriptions();
439438
let snap = world_state.snapshot();
440439
move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ())
441440
});
442441
}
442+
send_startup_progress(&connection.sender, loop_state, world_state);
443443

444444
if state_changed {
445445
update_file_notifications_on_threadpool(
@@ -703,6 +703,65 @@ fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state:
703703
}
704704
}
705705

706+
fn send_startup_progress(
707+
sender: &Sender<Message>,
708+
loop_state: &mut LoopState,
709+
world_state: &WorldState,
710+
) {
711+
if !world_state.feature_flags.get("notifications.workspace-loaded") {
712+
return;
713+
}
714+
let total: usize = world_state.workspaces.iter().map(|it| it.n_packages()).sum();
715+
let progress = total - world_state.roots_to_scan;
716+
if loop_state.roots_scanned_progress == Some(progress) {
717+
return;
718+
}
719+
loop_state.roots_scanned_progress = Some(progress);
720+
721+
match (progress, loop_state.workspace_loaded) {
722+
(0, false) => {
723+
let work_done_progress_create = request_new::<req::WorkDoneProgressCreate>(
724+
loop_state.next_request_id(),
725+
WorkDoneProgressCreateParams {
726+
token: req::ProgressToken::String("rustAnalyzer/startup".into()),
727+
},
728+
);
729+
sender.send(work_done_progress_create.into()).unwrap();
730+
send_startup_progress_notif(
731+
sender,
732+
WorkDoneProgress::Begin(WorkDoneProgressBegin {
733+
title: "rust-analyzer".into(),
734+
cancellable: None,
735+
message: Some(format!("{}/{} packages", progress, total)),
736+
percentage: Some(100 as f64 * progress as f64 / total as f64),
737+
}),
738+
);
739+
}
740+
(_, false) => send_startup_progress_notif(
741+
sender,
742+
WorkDoneProgress::Report(WorkDoneProgressReport {
743+
cancellable: None,
744+
message: Some(format!("{}/{} packages", progress, total)),
745+
percentage: Some(100 as f64 * progress as f64 / total as f64),
746+
}),
747+
),
748+
(_, true) => send_startup_progress_notif(
749+
sender,
750+
WorkDoneProgress::End(WorkDoneProgressEnd {
751+
message: Some(format!("rust-analyzer loaded, {} packages", progress)),
752+
}),
753+
),
754+
}
755+
}
756+
757+
fn send_startup_progress_notif(sender: &Sender<Message>, work_done_progress: WorkDoneProgress) {
758+
let notif = notification_new::<req::Progress>(req::ProgressParams {
759+
token: req::ProgressToken::String("rustAnalyzer/startup".into()),
760+
value: req::ProgressParamsValue::WorkDone(work_done_progress),
761+
});
762+
sender.send(notif.into()).unwrap();
763+
}
764+
706765
struct PoolDispatcher<'a> {
707766
req: Option<Request>,
708767
pool: &'a ThreadPool,

0 commit comments

Comments
 (0)