From d0a8f6a3eb5094af36a72ca01b290a494dfd7b16 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 10 Jul 2020 15:27:34 +0200 Subject: Automatically reload project info on Cargo.toml changes --- crates/ra_project_model/src/cargo_workspace.rs | 8 +++--- crates/ra_project_model/src/lib.rs | 2 +- crates/ra_project_model/src/sysroot.rs | 6 ++-- crates/rust-analyzer/src/config.rs | 4 +++ crates/rust-analyzer/src/main_loop.rs | 20 +------------ crates/rust-analyzer/src/reload.rs | 40 +++++++++++++++++++++++++- editors/code/package.json | 5 ++++ 7 files changed, 57 insertions(+), 28 deletions(-) diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 04f7eb741..6d1154056 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -24,7 +24,7 @@ use rustc_hash::FxHashMap; /// /// We use absolute paths here, `cargo metadata` guarantees to always produce /// abs paths. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct CargoWorkspace { packages: Arena, targets: Arena, @@ -68,7 +68,7 @@ pub type Package = Idx; pub type Target = Idx; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct PackageData { pub version: String, pub name: String, @@ -83,13 +83,13 @@ pub struct PackageData { pub proc_macro_dylib_path: Option, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct PackageDependency { pub pkg: Package, pub name: String, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct TargetData { pub package: Package, pub name: String, diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 5d1f871c4..b9c5424bf 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -24,7 +24,7 @@ pub use crate::{ }; pub use ra_proc_macro::ProcMacroClient; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub enum ProjectWorkspace { /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs index fc1673ede..68d134da4 100644 --- a/crates/ra_project_model/src/sysroot.rs +++ b/crates/ra_project_model/src/sysroot.rs @@ -3,19 +3,19 @@ use std::{convert::TryFrom, env, ops, path::Path, process::Command}; use anyhow::{bail, format_err, Result}; +use paths::{AbsPath, AbsPathBuf}; use ra_arena::{Arena, Idx}; use crate::output; -use paths::{AbsPath, AbsPathBuf}; -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, Eq, PartialEq)] pub struct Sysroot { crates: Arena, } pub type SysrootCrate = Idx; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct SysrootCrateData { pub name: String, pub root: AbsPathBuf, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 9dd81b4fc..ed5e52871 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -29,6 +29,7 @@ pub struct Config { pub files: FilesConfig, pub notifications: NotificationsConfig, + pub cargo_autoreload: bool, pub cargo: CargoConfig, pub rustfmt: RustfmtConfig, pub flycheck: Option, @@ -141,6 +142,7 @@ impl Config { files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, notifications: NotificationsConfig { cargo_toml_not_found: true }, + cargo_autoreload: true, cargo: CargoConfig::default(), rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() }, flycheck: Some(FlycheckConfig::CargoCommand { @@ -189,6 +191,7 @@ impl Config { }; self.notifications = NotificationsConfig { cargo_toml_not_found: data.notifications_cargoTomlNotFound }; + self.cargo_autoreload = data.cargo_autoreload; self.cargo = CargoConfig { no_default_features: data.cargo_noDefaultFeatures, all_features: data.cargo_allFeatures, @@ -364,6 +367,7 @@ config_data! { struct ConfigData { callInfo_full: bool = true, + cargo_autoreload: bool = true, cargo_allFeatures: bool = false, cargo_features: Vec = Vec::new(), cargo_loadOutDirsFromCheck: bool = false, diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index b48239058..96e2399ce 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -314,19 +314,6 @@ impl GlobalState { Ok(()) } - fn transition(&mut self, new_status: Status) { - self.status = Status::Ready; - if self.config.client_caps.status_notification { - let lsp_status = match new_status { - Status::Loading => lsp_ext::Status::Loading, - Status::Ready => lsp_ext::Status::Ready, - Status::Invalid => lsp_ext::Status::Invalid, - Status::NeedsReload => lsp_ext::Status::NeedsReload, - }; - self.send_notification::(lsp_status); - } - } - fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> { self.register_request(&req, request_received); @@ -441,12 +428,7 @@ impl GlobalState { if let Some(flycheck) = &this.flycheck { flycheck.handle.update(); } - let uri = params.text_document.uri.as_str(); - if uri.ends_with("Cargo.toml") || uri.ends_with("Cargo.lock") { - if matches!(this.status, Status::Ready | Status::Invalid) { - this.transition(Status::NeedsReload); - } - } + this.maybe_refresh(params.text_document.uri.as_str()); Ok(()) })? .on::(|this, _params| { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 74c3344df..0a201fceb 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -10,7 +10,8 @@ use vfs::{file_set::FileSetConfig, AbsPath}; use crate::{ config::{Config, FilesWatcher, LinkedProject}, - global_state::{GlobalState, Handle}, + global_state::{GlobalState, Handle, Status}, + lsp_ext, main_loop::Task, }; @@ -26,6 +27,32 @@ 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")) { + return; + } + match self.status { + Status::Loading | Status::NeedsReload => return, + Status::Ready | Status::Invalid => (), + } + if self.config.cargo_autoreload { + self.fetch_workspaces(); + } else { + self.transition(Status::NeedsReload); + } + } + pub(crate) fn transition(&mut self, new_status: Status) { + self.status = new_status; + if self.config.client_caps.status_notification { + let lsp_status = match new_status { + Status::Loading => lsp_ext::Status::Loading, + Status::Ready => lsp_ext::Status::Ready, + Status::Invalid => lsp_ext::Status::Invalid, + Status::NeedsReload => lsp_ext::Status::NeedsReload, + }; + self.send_notification::(lsp_status); + } + } pub(crate) fn fetch_workspaces(&mut self) { self.task_pool.handle.spawn({ let linked_projects = self.config.linked_projects.clone(); @@ -53,10 +80,13 @@ impl GlobalState { } pub(crate) fn switch_workspaces(&mut self, workspaces: Vec>) { log::info!("reloading projects: {:?}", self.config.linked_projects); + + let mut has_errors = false; let workspaces = workspaces .into_iter() .filter_map(|res| { res.map_err(|err| { + has_errors = true; log::error!("failed to load workspace: {:#}", err); self.show_message( lsp_types::MessageType::Error, @@ -67,6 +97,14 @@ impl GlobalState { }) .collect::>(); + if &*self.workspaces == &workspaces { + return; + } + + if !self.workspaces.is_empty() && has_errors { + return; + } + if let FilesWatcher::Client = self.config.files.watcher { let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { watchers: workspaces diff --git a/editors/code/package.json b/editors/code/package.json index 743a2290c..aac4ba94f 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -237,6 +237,11 @@ "default": true, "markdownDescription": "Whether to show `can't find Cargo.toml` error message" }, + "rust-analyzer.cargo.autoreload": { + "type": "boolean", + "default": true, + "markdownDescription": "Automatically refresh project info via `cargo metadata` on Cargo.toml changes" + }, "rust-analyzer.cargo.noDefaultFeatures": { "type": "boolean", "default": false, -- cgit v1.2.3