diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index c8d34e15a8c..728dc996243 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -122,6 +122,9 @@ pub(crate) fn new(sender: Sender, config: Config) -> Global } 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 @@ pub(crate) fn process_changes(&mut self) -> bool { 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 @@ pub(crate) fn process_changes(&mut self) -> bool { }; 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 96e2399ceda..cea03fb6b6c 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -22,6 +22,7 @@ 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 @@ fn on_notification(&mut self, not: Notification) -> Result<()> { 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 0a201fceb12..a425320f681 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -6,7 +6,7 @@ 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 @@ pub(crate) fn update_configuration(&mut self, config: Config) { 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 @@ pub(crate) fn maybe_refresh(&mut self, saved_doc_url: &str) { } 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 024e5801875..569da8a1c9d 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -70,7 +70,7 @@ pub fn is_created_or_deleted(&self) -> bool { } } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Copy, Clone)] pub enum ChangeKind { Create, Modify,