From 86bc4d20b30b8deb7783c200ad9f5d3acf019116 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 10 Jul 2020 18:48:39 +0200 Subject: Also reload when adding new examples, tests, etc --- crates/rust-analyzer/src/global_state.rs | 21 +++++++++++----- crates/rust-analyzer/src/main_loop.rs | 5 +++- crates/rust-analyzer/src/reload.rs | 41 +++++++++++++++++++++++++++++--- crates/vfs/src/lib.rs | 2 +- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index c8d34e15a..728dc9962 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -122,6 +122,9 @@ impl GlobalState { } pub(crate) fn process_changes(&mut self) -> bool { + let mut fs_changes = Vec::new(); + let mut has_fs_changes = false; + let change = { let mut change = AnalysisChange::new(); let (vfs, line_endings_map) = &mut *self.vfs.write(); @@ -130,13 +133,14 @@ impl GlobalState { return false; } - let fs_op = changed_files.iter().any(|it| it.is_created_or_deleted()); - if fs_op { - let roots = self.source_root_config.partition(&vfs); - change.set_roots(roots) - } - for file in changed_files { + if file.is_created_or_deleted() { + if let Some(path) = vfs.file_path(file.file_id).as_path() { + fs_changes.push((path.to_path_buf(), file.change_kind)); + has_fs_changes = true; + } + } + let text = if file.exists() { let bytes = vfs.file_contents(file.file_id).to_vec(); match String::from_utf8(bytes).ok() { @@ -152,10 +156,15 @@ impl GlobalState { }; change.change_file(file.file_id, text); } + if has_fs_changes { + let roots = self.source_root_config.partition(&vfs); + change.set_roots(roots); + } change }; self.analysis_host.apply_change(change); + self.maybe_refresh(&fs_changes); true } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 96e2399ce..cea03fb6b 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -22,6 +22,7 @@ use crate::{ Result, }; use ra_project_model::ProjectWorkspace; +use vfs::ChangeKind; pub fn main_loop(config: Config, connection: Connection) -> Result<()> { log::info!("initial config: {:#?}", config); @@ -428,7 +429,9 @@ impl GlobalState { if let Some(flycheck) = &this.flycheck { flycheck.handle.update(); } - this.maybe_refresh(params.text_document.uri.as_str()); + if let Ok(abs_path) = from_proto::abs_path(¶ms.text_document.uri) { + this.maybe_refresh(&[(abs_path, ChangeKind::Modify)]); + } Ok(()) })? .on::(|this, _params| { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 0a201fceb..a425320f6 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -6,7 +6,7 @@ use flycheck::FlycheckHandle; use ra_db::{CrateGraph, SourceRoot, VfsPath}; use ra_ide::AnalysisChange; use ra_project_model::{PackageRoot, ProcMacroClient, ProjectWorkspace}; -use vfs::{file_set::FileSetConfig, AbsPath}; +use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; use crate::{ config::{Config, FilesWatcher, LinkedProject}, @@ -27,8 +27,8 @@ impl GlobalState { self.reload_flycheck(); } } - pub(crate) fn maybe_refresh(&mut self, saved_doc_url: &str) { - if !(saved_doc_url.ends_with("Cargo.toml") || saved_doc_url.ends_with("Cargo.lock")) { + pub(crate) fn maybe_refresh(&mut self, changes: &[(AbsPathBuf, ChangeKind)]) { + if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) { return; } match self.status { @@ -40,6 +40,41 @@ impl GlobalState { } else { self.transition(Status::NeedsReload); } + + fn is_interesting(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"]; + + if path.ends_with("Cargo.toml") || path.ends_with("Cargo.lock") { + return true; + } + if change_kind == ChangeKind::Modify { + return false; + } + if path.extension().map(|it| it.to_str()) != Some("rs".into()) { + return false; + } + if IMPLICIT_TARGET_FILES.iter().any(|it| path.ends_with(it)) { + return true; + } + let parent = match path.parent() { + Some(it) => it, + None => return false, + }; + if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.ends_with(it)) { + return true; + } + if path.ends_with("main.rs") { + let grand_parent = match parent.parent() { + Some(it) => it, + None => return false, + }; + if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.ends_with(it)) { + return true; + } + } + false + } } pub(crate) fn transition(&mut self, new_status: Status) { self.status = new_status; diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 024e58018..569da8a1c 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -70,7 +70,7 @@ impl ChangedFile { } } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Copy, Clone)] pub enum ChangeKind { Create, Modify, -- cgit v1.2.3 From be679a02aba985ee458dd8441606bff0595a2ce2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 10 Jul 2020 18:53:01 +0200 Subject: Add profiling calls --- crates/rust-analyzer/src/global_state.rs | 2 ++ crates/rust-analyzer/src/reload.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 728dc9962..9a9a6547a 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -26,6 +26,7 @@ use crate::{ to_proto::url_from_abs_path, Result, }; +use ra_prof::profile; #[derive(Eq, PartialEq, Copy, Clone)] pub(crate) enum Status { @@ -122,6 +123,7 @@ impl GlobalState { } pub(crate) fn process_changes(&mut self) -> bool { + let _p = profile("GlobalState::process_changes"); let mut fs_changes = Vec::new(); let mut has_fs_changes = false; diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index a425320f6..ffe234a5b 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -14,9 +14,11 @@ use crate::{ lsp_ext, main_loop::Task, }; +use ra_prof::profile; impl GlobalState { pub(crate) fn update_configuration(&mut self, config: Config) { + let _p = profile("GlobalState::update_configuration"); let old_config = mem::replace(&mut self.config, config); if self.config.lru_capacity != old_config.lru_capacity { self.analysis_host.update_lru_capacity(old_config.lru_capacity); @@ -114,6 +116,7 @@ impl GlobalState { }); } pub(crate) fn switch_workspaces(&mut self, workspaces: Vec>) { + let _p = profile("GlobalState::switch_workspaces"); log::info!("reloading projects: {:?}", self.config.linked_projects); let mut has_errors = false; @@ -302,6 +305,7 @@ pub(crate) struct SourceRootConfig { impl SourceRootConfig { pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec { + let _p = profile("SourceRootConfig::partition"); self.fsc .partition(vfs) .into_iter() -- cgit v1.2.3 From 676d2e040dfe619d666d5b3068db47346655f23b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 10 Jul 2020 22:28:41 +0200 Subject: Sort cargo metadata See https://github.com/rust-lang/cargo/issues/8477 We need this to prevent spurious workspace reloads --- crates/ra_project_model/src/cargo_workspace.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 6d1154056..4182ca156 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -155,7 +155,7 @@ impl CargoWorkspace { if let Some(target) = cargo_features.target.as_ref() { meta.other_options(vec![String::from("--filter-platform"), target.clone()]); } - let meta = meta.exec().with_context(|| { + let mut meta = meta.exec().with_context(|| { format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display()) })?; @@ -175,6 +175,7 @@ impl CargoWorkspace { let ws_members = &meta.workspace_members; + meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); for meta_pkg in meta.packages { let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } = meta_pkg; @@ -210,7 +211,7 @@ impl CargoWorkspace { } } let resolve = meta.resolve.expect("metadata executed with deps"); - for node in resolve.nodes { + for mut node in resolve.nodes { let source = match pkg_by_id.get(&node.id) { Some(&src) => src, // FIXME: replace this and a similar branch below with `.unwrap`, once @@ -221,6 +222,7 @@ impl CargoWorkspace { continue; } }; + node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg)); for dep_node in node.deps { let pkg = match pkg_by_id.get(&dep_node.pkg) { Some(&pkg) => pkg, -- cgit v1.2.3 From a1ef6cc553bbd141d94144ccb8e1599fa3f76526 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 10 Jul 2020 22:29:40 +0200 Subject: Optimize VFS processing --- crates/rust-analyzer/src/main_loop.rs | 68 ++++++++++++++++++++--------------- crates/vfs/src/lib.rs | 2 +- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index cea03fb6b..702f25a19 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -198,39 +198,49 @@ impl GlobalState { } self.analysis_host.maybe_collect_garbage(); } - Event::Vfs(task) => match task { - vfs::loader::Message::Loaded { files } => { - let vfs = &mut self.vfs.write().0; - for (path, contents) in files { - let path = VfsPath::from(path); - if !self.mem_docs.contains(&path) { - vfs.set_file_contents(path, contents) + Event::Vfs(mut task) => { + let _p = profile("GlobalState::handle_event/vfs"); + loop { + match task { + vfs::loader::Message::Loaded { files } => { + let vfs = &mut self.vfs.write().0; + for (path, contents) in files { + let path = VfsPath::from(path); + if !self.mem_docs.contains(&path) { + vfs.set_file_contents(path, contents) + } + } + } + vfs::loader::Message::Progress { n_total, n_done } => { + if n_total == 0 { + self.transition(Status::Invalid); + } else { + let state = if n_done == 0 { + self.transition(Status::Loading); + Progress::Begin + } else if n_done < n_total { + Progress::Report + } else { + assert_eq!(n_done, n_total); + self.transition(Status::Ready); + Progress::End + }; + self.report_progress( + "roots scanned", + state, + Some(format!("{}/{}", n_done, n_total)), + Some(Progress::percentage(n_done, n_total)), + ) + } } } - } - vfs::loader::Message::Progress { n_total, n_done } => { - if n_total == 0 { - self.transition(Status::Invalid); - } else { - let state = if n_done == 0 { - self.transition(Status::Loading); - Progress::Begin - } else if n_done < n_total { - Progress::Report - } else { - assert_eq!(n_done, n_total); - self.transition(Status::Ready); - Progress::End - }; - self.report_progress( - "roots scanned", - state, - Some(format!("{}/{}", n_done, n_total)), - Some(Progress::percentage(n_done, n_total)), - ) + // Coalesce many VFS event into a single loop turn + task = match self.loader.receiver.try_recv() { + Ok(task) => task, + Err(_) => break, } } - }, + } Event::Flycheck(task) => match task { flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 569da8a1c..3bfecd08f 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -70,7 +70,7 @@ impl ChangedFile { } } -#[derive(Eq, PartialEq, Copy, Clone)] +#[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum ChangeKind { Create, Modify, -- cgit v1.2.3