Skip to content

Commit 39cd4a1

Browse files
committed
fix: Allow multiple discover operations
Previously, rust-analyzer would drop discover requests that arrived before we'd finished processing the previous request. Fix this by allowing multiple discover requests to be active. Keep track of the number of discover operations for the quiescence check, and keep the process handles until they terminate.
1 parent ad61e76 commit 39cd4a1

File tree

5 files changed

+69
-30
lines changed

5 files changed

+69
-30
lines changed

src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,22 @@ impl<T: Sized + Send + 'static> CommandHandle<T> {
197197
)))
198198
}
199199
}
200+
201+
pub(crate) fn has_exited(&mut self) -> bool {
202+
match self.child.0.try_wait() {
203+
Ok(Some(_exit_code)) => {
204+
// We have an exit code.
205+
true
206+
}
207+
Ok(None) => {
208+
// Hasn't exited yet.
209+
false
210+
}
211+
Err(_) => {
212+
// Couldn't get an exit code. Assume that we've
213+
// exited.
214+
true
215+
}
216+
}
217+
}
200218
}

src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ impl DiscoverCommand {
6767
cmd.args(args);
6868

6969
Ok(DiscoverHandle {
70-
_handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone(), None)?,
70+
handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone(), None)?,
7171
span: info_span!("discover_command").entered(),
7272
})
7373
}
@@ -76,7 +76,7 @@ impl DiscoverCommand {
7676
/// A handle to a spawned [Discover].
7777
#[derive(Debug)]
7878
pub(crate) struct DiscoverHandle {
79-
_handle: CommandHandle<DiscoverProjectMessage>,
79+
pub(crate) handle: CommandHandle<DiscoverProjectMessage>,
8080
#[allow(dead_code)] // not accessed, but used to log on drop.
8181
span: EnteredSpan,
8282
}

src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,10 @@ pub(crate) struct GlobalState {
121121
pub(crate) test_run_remaining_jobs: usize,
122122

123123
// Project loading
124-
pub(crate) discover_handle: Option<discover::DiscoverHandle>,
124+
pub(crate) discover_handles: Vec<discover::DiscoverHandle>,
125125
pub(crate) discover_sender: Sender<discover::DiscoverProjectMessage>,
126126
pub(crate) discover_receiver: Receiver<discover::DiscoverProjectMessage>,
127+
pub(crate) discover_jobs_active: u32,
127128

128129
// Debouncing channel for fetching the workspace
129130
// we want to delay it until the VFS looks stable-ish (and thus is not currently in the middle
@@ -175,7 +176,6 @@ pub(crate) struct GlobalState {
175176
pub(crate) fetch_build_data_queue: OpQueue<(), FetchBuildDataResponse>,
176177
pub(crate) fetch_proc_macros_queue: OpQueue<(ChangeWithProcMacros, Vec<ProcMacroPaths>), bool>,
177178
pub(crate) prime_caches_queue: OpQueue,
178-
pub(crate) discover_workspace_queue: OpQueue,
179179

180180
/// A deferred task queue.
181181
///
@@ -291,9 +291,10 @@ impl GlobalState {
291291
test_run_receiver,
292292
test_run_remaining_jobs: 0,
293293

294-
discover_handle: None,
294+
discover_handles: vec![],
295295
discover_sender,
296296
discover_receiver,
297+
discover_jobs_active: 0,
297298

298299
fetch_ws_receiver: None,
299300

@@ -312,7 +313,6 @@ impl GlobalState {
312313
fetch_proc_macros_queue: OpQueue::default(),
313314

314315
prime_caches_queue: OpQueue::default(),
315-
discover_workspace_queue: OpQueue::default(),
316316

317317
deferred_task_queue: task_queue,
318318
incomplete_crate_graph: false,

src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,8 @@ impl GlobalState {
531531
}
532532
}
533533

534+
self.cleanup_discover_handles();
535+
534536
if let Some(diagnostic_changes) = self.diagnostics.take_changes() {
535537
for file_id in diagnostic_changes {
536538
let uri = file_id_to_url(&self.vfs.read().0, file_id);
@@ -806,33 +808,34 @@ impl GlobalState {
806808
self.report_progress("Fetching", state, msg, None, None);
807809
}
808810
Task::DiscoverLinkedProjects(arg) => {
809-
if let Some(cfg) = self.config.discover_workspace_config()
810-
&& !self.discover_workspace_queue.op_in_progress()
811-
{
811+
if let Some(cfg) = self.config.discover_workspace_config() {
812812
// the clone is unfortunately necessary to avoid a borrowck error when
813813
// `self.report_progress` is called later
814814
let title = &cfg.progress_label.clone();
815815
let command = cfg.command.clone();
816816
let discover = DiscoverCommand::new(self.discover_sender.clone(), command);
817817

818-
self.report_progress(title, Progress::Begin, None, None, None);
819-
self.discover_workspace_queue
820-
.request_op("Discovering workspace".to_owned(), ());
821-
let _ = self.discover_workspace_queue.should_start_op();
818+
if self.discover_jobs_active == 0 {
819+
self.report_progress(title, Progress::Begin, None, None, None);
820+
}
821+
self.discover_jobs_active += 1;
822822

823823
let arg = match arg {
824824
DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it),
825825
DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it),
826826
};
827827

828-
let handle = discover.spawn(
829-
arg,
830-
&std::env::current_dir()
831-
.expect("Failed to get cwd during project discovery"),
832-
);
833-
self.discover_handle = Some(handle.unwrap_or_else(|e| {
834-
panic!("Failed to spawn project discovery command: {e}")
835-
}));
828+
let handle = discover
829+
.spawn(
830+
arg,
831+
&std::env::current_dir()
832+
.expect("Failed to get cwd during project discovery"),
833+
)
834+
.unwrap_or_else(|e| {
835+
panic!("Failed to spawn project discovery command: {e}")
836+
});
837+
838+
self.discover_handles.push(handle);
836839
}
837840
}
838841
Task::FetchBuildData(progress) => {
@@ -1036,25 +1039,43 @@ impl GlobalState {
10361039
.expect("No title could be found; this is a bug");
10371040
match message {
10381041
DiscoverProjectMessage::Finished { project, buildfile } => {
1039-
self.discover_handle = None;
1040-
self.report_progress(&title, Progress::End, None, None, None);
1041-
self.discover_workspace_queue.op_completed(());
1042+
self.discover_jobs_active = self.discover_jobs_active.saturating_sub(1);
1043+
if self.discover_jobs_active == 0 {
1044+
self.report_progress(&title, Progress::End, None, None, None);
1045+
}
10421046

10431047
let mut config = Config::clone(&*self.config);
10441048
config.add_discovered_project_from_command(project, buildfile);
10451049
self.update_configuration(config);
10461050
}
10471051
DiscoverProjectMessage::Progress { message } => {
1048-
self.report_progress(&title, Progress::Report, Some(message), None, None)
1052+
if self.discover_jobs_active > 0 {
1053+
self.report_progress(&title, Progress::Report, Some(message), None, None)
1054+
}
10491055
}
10501056
DiscoverProjectMessage::Error { error, source } => {
1051-
self.discover_handle = None;
10521057
let message = format!("Project discovery failed: {error}");
1053-
self.discover_workspace_queue.op_completed(());
10541058
self.show_and_log_error(message.clone(), source);
1055-
self.report_progress(&title, Progress::End, Some(message), None, None)
1059+
1060+
self.discover_jobs_active = self.discover_jobs_active.saturating_sub(1);
1061+
if self.discover_jobs_active == 0 {
1062+
self.report_progress(&title, Progress::End, Some(message), None, None)
1063+
}
1064+
}
1065+
}
1066+
}
1067+
1068+
/// Drop any discover command processes that have exited, due to
1069+
/// finishing or erroring.
1070+
fn cleanup_discover_handles(&mut self) {
1071+
let mut active_handles = vec![];
1072+
1073+
for mut discover_handle in self.discover_handles.drain(..) {
1074+
if !discover_handle.handle.has_exited() {
1075+
active_handles.push(discover_handle);
10561076
}
10571077
}
1078+
self.discover_handles = active_handles;
10581079
}
10591080

10601081
fn handle_cargo_test_msg(&mut self, message: CargoTestMessage) {

src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl GlobalState {
7474
&& !self.fetch_workspaces_queue.op_in_progress()
7575
&& !self.fetch_build_data_queue.op_in_progress()
7676
&& !self.fetch_proc_macros_queue.op_in_progress()
77-
&& !self.discover_workspace_queue.op_in_progress()
77+
&& self.discover_jobs_active == 0
7878
&& self.vfs_progress_config_version >= self.vfs_config_version
7979
}
8080

@@ -297,7 +297,7 @@ impl GlobalState {
297297
.collect();
298298
let cargo_config = self.config.cargo(None);
299299
let discover_command = self.config.discover_workspace_config().cloned();
300-
let is_quiescent = !(self.discover_workspace_queue.op_in_progress()
300+
let is_quiescent = !(self.discover_jobs_active > 0
301301
|| self.vfs_progress_config_version < self.vfs_config_version
302302
|| !self.vfs_done);
303303

0 commit comments

Comments
 (0)