Skip to content

Commit

Permalink
Auto merge of rust-lang#12947 - Veykril:switch-workspace, r=Veykril
Browse files Browse the repository at this point in the history
Don't switch workspace on vfs file changes from libraries

When r-a starts up, it starts switching the workspace before all vfs
events have been processed which causes us to switch workspace multiple
times until all vfs changes have been processed. This scales with the
size of the project and its dependencies. If workspace files from
dependencies as well as the sysroot get loaded, we shouldn't switch
the workspace as those have no impact on the project workspace.
  • Loading branch information
bors committed Aug 5, 2022
2 parents 97038e5 + 6a17372 commit 3792720
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 36 deletions.
34 changes: 21 additions & 13 deletions crates/rust-analyzer/src/global_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{sync::Arc, time::Instant};
use crossbeam_channel::{unbounded, Receiver, Sender};
use flycheck::FlycheckHandle;
use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId};
use ide_db::base_db::{CrateId, FileLoader, SourceDatabase};
use ide_db::base_db::{CrateId, FileLoader, SourceDatabase, SourceDatabaseExt};
use lsp_types::{SemanticTokens, Url};
use parking_lot::{Mutex, RwLock};
use proc_macro_api::ProcMacroServer;
Expand Down Expand Up @@ -176,7 +176,7 @@ impl GlobalState {

pub(crate) fn process_changes(&mut self) -> bool {
let _p = profile::span("GlobalState::process_changes");
let mut fs_changes = Vec::new();
let mut fs_refresh_changes = Vec::new();
// A file was added or deleted
let mut has_structure_changes = false;

Expand All @@ -192,11 +192,8 @@ impl GlobalState {
if let Some(path) = vfs.file_path(file.file_id).as_path() {
let path = path.to_path_buf();
if reload::should_refresh_for_change(&path, file.change_kind) {
tracing::warn!("fetch-fiel_change");
self.fetch_workspaces_queue
.request_op(format!("vfs file change: {}", path.display()));
fs_refresh_changes.push((path, file.file_id));
}
fs_changes.push((path, file.change_kind));
if file.is_created_or_deleted() {
has_structure_changes = true;
}
Expand Down Expand Up @@ -228,14 +225,25 @@ impl GlobalState {

self.analysis_host.apply_change(change);

let raw_database = &self.analysis_host.raw_database();
self.proc_macro_changed =
changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
let crates = raw_database.relevant_crates(file.file_id);
let crate_graph = raw_database.crate_graph();
{
let raw_database = self.analysis_host.raw_database();
let workspace_structure_change =
fs_refresh_changes.into_iter().find(|&(_, file_id)| {
!raw_database.source_root(raw_database.file_source_root(file_id)).is_library
});
if let Some((path, _)) = workspace_structure_change {
self.fetch_workspaces_queue
.request_op(format!("workspace vfs file change: {}", path.display()));
}
self.proc_macro_changed =
changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
let crates = raw_database.relevant_crates(file.file_id);
let crate_graph = raw_database.crate_graph();

crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
});
}

crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
});
true
}

Expand Down
42 changes: 20 additions & 22 deletions crates/rust-analyzer/src/reload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,7 @@ impl GlobalState {
}

if let Err(error) = self.fetch_build_data_error() {
self.show_and_log_error(
"rust-analyzer failed to run build scripts".to_string(),
Some(error),
);
self.show_and_log_error("failed to run build scripts".to_string(), Some(error));
}

let workspaces = self
Expand Down Expand Up @@ -308,6 +305,7 @@ impl GlobalState {

if self.proc_macro_clients.is_empty() {
if let Some((path, args)) = self.config.proc_macro_srv() {
tracing::info!("Spawning proc-macro servers");
self.proc_macro_clients = self
.workspaces
.iter()
Expand All @@ -316,35 +314,31 @@ impl GlobalState {
let mut path = path.clone();

if let ProjectWorkspace::Cargo { sysroot, .. } = ws {
tracing::info!("Found a cargo workspace...");
tracing::debug!("Found a cargo workspace...");
if let Some(sysroot) = sysroot.as_ref() {
tracing::info!("Found a cargo workspace with a sysroot...");
tracing::debug!("Found a cargo workspace with a sysroot...");
let server_path =
sysroot.root().join("libexec").join(&standalone_server_name);
if std::fs::metadata(&server_path).is_ok() {
tracing::info!(
tracing::debug!(
"And the server exists at {}",
server_path.display()
);
path = server_path;
args = vec![];
} else {
tracing::info!(
tracing::debug!(
"And the server does not exist at {}",
server_path.display()
);
}
}
}

tracing::info!(
"Using proc-macro server at {} with args {:?}",
path.display(),
args
);
tracing::info!(?args, "Using proc-macro server at {}", path.display(),);
ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| {
let error = format!(
"Failed to run proc_macro_srv from path {}, error: {:?}",
"Failed to run proc-macro server from path {}, error: {:?}",
path.display(),
err
);
Expand Down Expand Up @@ -684,22 +678,26 @@ pub(crate) fn load_proc_macro(
pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {
const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
let file_name = path.file_name().unwrap_or_default();

if file_name == "Cargo.toml" || file_name == "Cargo.lock" {
let file_name = match path.file_name().unwrap_or_default().to_str() {
Some(it) => it,
None => return false,
};

if let "Cargo.toml" | "Cargo.lock" = file_name {
return true;
}
if change_kind == ChangeKind::Modify {
return false;
}

// .cargo/config{.toml}
if path.extension().unwrap_or_default() != "rs" {
if (file_name == "config.toml" || file_name == "config")
&& path.parent().map(|parent| parent.as_ref().ends_with(".cargo")) == Some(true)
{
return true;
}
return false;
let is_cargo_config = matches!(file_name, "config.toml" | "config")
&& path.parent().map(|parent| parent.as_ref().ends_with(".cargo")).unwrap_or(false);
return is_cargo_config;
}

if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) {
return true;
}
Expand Down
7 changes: 6 additions & 1 deletion crates/vfs-notify/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ impl loader::Handle for NotifyHandle {
.expect("failed to spawn thread");
NotifyHandle { sender, _thread: thread }
}

fn set_config(&mut self, config: loader::Config) {
self.sender.send(Message::Config(config)).unwrap();
}

fn invalidate(&mut self, path: AbsPathBuf) {
self.sender.send(Message::Invalidate(path)).unwrap();
}

fn load_sync(&mut self, path: &AbsPath) -> Option<Vec<u8>> {
read(path)
}
Expand All @@ -70,16 +73,18 @@ impl NotifyActor {
fn new(sender: loader::Sender) -> NotifyActor {
NotifyActor { sender, watched_entries: Vec::new(), watcher: None }
}

fn next_event(&self, receiver: &Receiver<Message>) -> Option<Event> {
let watcher_receiver = self.watcher.as_ref().map(|(_, receiver)| receiver);
select! {
recv(receiver) -> it => it.ok().map(Event::Message),
recv(watcher_receiver.unwrap_or(&never())) -> it => Some(Event::NotifyEvent(it.unwrap())),
}
}

fn run(mut self, inbox: Receiver<Message>) {
while let Some(event) = self.next_event(&inbox) {
tracing::debug!("vfs-notify event: {:?}", event);
tracing::debug!(?event, "vfs-notify event");
match event {
Event::Message(msg) => match msg {
Message::Config(config) => {
Expand Down

0 comments on commit 3792720

Please sign in to comment.