diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index f1dde104fc..e435af6c80 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -33,7 +33,7 @@ use crate::{ lsp_ext, main_loop::Task, mem_docs::MemDocs, - op_queue::OpQueue, + op_queue::{Cause, OpQueue}, reload, target_spec::{CargoTargetSpec, ProjectJsonTargetSpec, TargetSpec}, task_pool::{TaskPool, TaskQueue}, @@ -108,8 +108,8 @@ pub(crate) struct GlobalState { pub(crate) vfs: Arc)>>, pub(crate) vfs_config_version: u32, pub(crate) vfs_progress_config_version: u32, - pub(crate) vfs_progress_n_total: usize, - pub(crate) vfs_progress_n_done: usize, + pub(crate) vfs_done: bool, + pub(crate) wants_to_switch: Option, /// `workspaces` field stores the data we actually use, while the `OpQueue` /// stores the result of the last fetch. @@ -252,8 +252,8 @@ impl GlobalState { vfs: Arc::new(RwLock::new((vfs::Vfs::default(), IntMap::default()))), vfs_config_version: 0, vfs_progress_config_version: 0, - vfs_progress_n_total: 0, - vfs_progress_n_done: 0, + vfs_done: true, + wants_to_switch: None, workspaces: Arc::from(Vec::new()), crate_graph_file_dependencies: FxHashSet::default(), diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 9db81f2295..23ae282396 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -375,9 +375,14 @@ impl GlobalState { } } let event_handling_duration = loop_start.elapsed(); - - let state_changed = self.process_changes(); - let memdocs_added_or_removed = self.mem_docs.take_changes(); + let (state_changed, memdocs_added_or_removed) = if self.vfs_done { + if let Some(cause) = self.wants_to_switch.take() { + self.switch_workspaces(cause); + } + (self.process_changes(), self.mem_docs.take_changes()) + } else { + (false, false) + }; if self.is_quiescent() { let became_quiescent = !was_quiescent; @@ -672,7 +677,7 @@ impl GlobalState { if let Err(e) = self.fetch_workspace_error() { error!("FetchWorkspaceError:\n{e}"); } - self.switch_workspaces("fetched workspace".to_owned()); + self.wants_to_switch = Some("fetched workspace".to_owned()); (Progress::End, None) } }; @@ -718,8 +723,9 @@ impl GlobalState { error!("FetchBuildDataError:\n{e}"); } - self.switch_workspaces("fetched build data".to_owned()); - + if self.wants_to_switch.is_none() { + self.wants_to_switch = Some("fetched build data".to_owned()); + } (Some(Progress::End), None) } }; @@ -779,8 +785,7 @@ impl GlobalState { }; self.vfs_progress_config_version = config_version; - self.vfs_progress_n_total = n_total; - self.vfs_progress_n_done = n_done; + self.vfs_done = state == Progress::End; let mut message = format!("{n_done}/{n_total}"); if let Some(dir) = dir { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 5c95ccd4b8..39301f4288 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -62,13 +62,13 @@ pub(crate) enum ProcMacroProgress { impl GlobalState { pub(crate) fn is_quiescent(&self) -> bool { - !(self.last_reported_status.is_none() - || self.fetch_workspaces_queue.op_in_progress() - || self.fetch_build_data_queue.op_in_progress() - || self.fetch_proc_macros_queue.op_in_progress() - || self.discover_workspace_queue.op_in_progress() - || self.vfs_progress_config_version < self.vfs_config_version - || self.vfs_progress_n_done < self.vfs_progress_n_total) + self.vfs_done + && self.last_reported_status.is_some() + && !self.fetch_workspaces_queue.op_in_progress() + && !self.fetch_build_data_queue.op_in_progress() + && !self.fetch_proc_macros_queue.op_in_progress() + && !self.discover_workspace_queue.op_in_progress() + && self.vfs_progress_config_version >= self.vfs_config_version } pub(crate) fn update_configuration(&mut self, config: Config) { @@ -102,15 +102,13 @@ impl GlobalState { } pub(crate) fn current_status(&self) -> lsp_ext::ServerStatusParams { - let mut status = lsp_ext::ServerStatusParams { - health: lsp_ext::Health::Ok, - quiescent: self.is_quiescent(), - message: None, - }; + let quiescent = self.is_quiescent(); + let mut status = + lsp_ext::ServerStatusParams { health: lsp_ext::Health::Ok, quiescent, message: None }; let mut message = String::new(); if !self.config.cargo_autoreload(None) - && self.is_quiescent() + && quiescent && self.fetch_workspaces_queue.op_requested() && self.config.discover_workspace_config().is_none() { @@ -242,7 +240,7 @@ impl GlobalState { let discover_command = self.config.discover_workspace_config().cloned(); let is_quiescent = !(self.discover_workspace_queue.op_in_progress() || self.vfs_progress_config_version < self.vfs_config_version - || self.vfs_progress_n_done < self.vfs_progress_n_total); + || !self.vfs_done); move |sender| { let progress = { diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs index 0972e4234e..7328cd9ed6 100644 --- a/crates/vfs-notify/src/lib.rs +++ b/crates/vfs-notify/src/lib.rs @@ -61,6 +61,7 @@ type NotifyEvent = notify::Result; struct NotifyActor { sender: loader::Sender, + // FIXME: Consider hashset watched_entries: Vec, // Drop order is significant. watcher: Option<(RecommendedWatcher, Receiver)>, diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 77f890fd7e..bc40e03c5a 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -201,8 +201,8 @@ impl Vfs { pub fn set_file_contents(&mut self, path: VfsPath, contents: Option>) -> bool { let _p = span!(Level::INFO, "Vfs::set_file_contents").entered(); let file_id = self.alloc_file_id(path); - let state = self.get(file_id); - let change_kind = match (state, contents) { + let state: FileState = self.get(file_id); + let change = match (state, contents) { (FileState::Deleted, None) => return false, (FileState::Deleted, Some(v)) => { let hash = hash_once::(&*v); @@ -225,7 +225,7 @@ impl Vfs { }; }; - let changed_file = ChangedFile { file_id, change: change_kind }; + let changed_file = ChangedFile { file_id, change }; match self.changes.entry(file_id) { // two changes to the same file in one cycle, merge them appropriately Entry::Occupied(mut o) => {