about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs124
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs30
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs2
4 files changed, 83 insertions, 74 deletions
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 4a09ef21adc..6724b6a7add 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -779,11 +779,8 @@ pub struct Config {
     /// Config node whose values apply to **every** Rust project.
     user_config: Option<(GlobalLocalConfigInput, ConfigErrors)>,
 
-    /// A special file for this session whose path is set to `self.root_path.join("rust-analyzer.toml")`
-    root_ratoml_path: VfsPath,
-
-    /// This file can be used to make global changes while having only a workspace-wide scope.
-    root_ratoml: Option<(GlobalLocalConfigInput, ConfigErrors)>,
+    /// TODO : This file can be used to make global changes while having only a workspace-wide scope.
+    workspace_ratoml_change: FxHashMap<SourceRootId, (GlobalLocalConfigInput, ConfigErrors)>,
 
     /// For every `SourceRoot` there can be at most one RATOML file.
     ratoml_files: FxHashMap<SourceRootId, (LocalConfigInput, ConfigErrors)>,
@@ -917,38 +914,44 @@ impl Config {
             should_update = true;
         }
 
-        if let Some(change) = change.root_ratoml_change {
-            tracing::info!("updating root ra-toml config: {:#}", change);
-            #[allow(clippy::single_match)]
-            match toml::from_str(&change) {
-                Ok(table) => {
+        if let Some(change) = change.workspace_ratoml_change {
+            tracing::info!("updating root ra-toml config");
+            for (source_root_id, (_, text)) in change {
+                if let Some(text) = text {
                     let mut toml_errors = vec![];
-                    validate_toml_table(
-                        GlobalLocalConfigInput::FIELDS,
-                        &table,
-                        &mut String::new(),
-                        &mut toml_errors,
-                    );
-                    config.root_ratoml = Some((
-                        GlobalLocalConfigInput::from_toml(table, &mut toml_errors),
-                        ConfigErrors(
-                            toml_errors
-                                .into_iter()
-                                .map(|(a, b)| ConfigErrorInner::Toml { config_key: a, error: b })
-                                .map(Arc::new)
-                                .collect(),
-                        ),
-                    ));
-                    should_update = true;
-                }
-                Err(e) => {
-                    config.root_ratoml = Some((
-                        GlobalLocalConfigInput::from_toml(toml::map::Map::default(), &mut vec![]),
-                        ConfigErrors(vec![ConfigErrorInner::ParseError {
-                            reason: e.message().to_owned(),
+                    match toml::from_str(&text) {
+                        Ok(table) => {
+                            validate_toml_table(
+                                GlobalLocalConfigInput::FIELDS,
+                                &table,
+                                &mut String::new(),
+                                &mut toml_errors,
+                            );
+                            config.workspace_ratoml_change.insert(
+                                source_root_id,
+                                (
+                                    GlobalLocalConfigInput::from_toml(table, &mut toml_errors),
+                                    ConfigErrors(
+                                        toml_errors
+                                            .into_iter()
+                                            .map(|(a, b)| ConfigErrorInner::Toml {
+                                                config_key: a,
+                                                error: b,
+                                            })
+                                            .map(Arc::new)
+                                            .collect(),
+                                    ),
+                                ),
+                            );
+                            should_update = true;
+                        }
+                        Err(e) => {
+                            config.validation_errors.0.push(
+                                ConfigErrorInner::ParseError { reason: e.message().to_owned() }
+                                    .into(),
+                            );
                         }
-                        .into()]),
-                    ));
+                    }
                 }
             }
         }
@@ -958,7 +961,6 @@ impl Config {
                 if let Some(text) = text {
                     let mut toml_errors = vec![];
                     tracing::info!("updating ra-toml config: {:#}", text);
-                    #[allow(clippy::single_match)]
                     match toml::from_str(&text) {
                         Ok(table) => {
                             validate_toml_table(
@@ -985,16 +987,10 @@ impl Config {
                             );
                         }
                         Err(e) => {
-                            config.root_ratoml = Some((
-                                GlobalLocalConfigInput::from_toml(
-                                    toml::map::Map::default(),
-                                    &mut vec![],
-                                ),
-                                ConfigErrors(vec![ConfigErrorInner::ParseError {
-                                    reason: e.message().to_owned(),
-                                }
-                                .into()]),
-                            ));
+                            config.validation_errors.0.push(
+                                ConfigErrorInner::ParseError { reason: e.message().to_owned() }
+                                    .into(),
+                            );
                         }
                     }
                 }
@@ -1026,7 +1022,13 @@ impl Config {
                 .1
                  .0
                 .iter()
-                .chain(config.root_ratoml.as_ref().into_iter().flat_map(|it| it.1 .0.iter()))
+                .chain(
+                    config
+                        .workspace_ratoml_change
+                        .values()
+                        .into_iter()
+                        .flat_map(|it| it.1 .0.iter()),
+                )
                 .chain(config.user_config.as_ref().into_iter().flat_map(|it| it.1 .0.iter()))
                 .chain(config.ratoml_files.values().flat_map(|it| it.1 .0.iter()))
                 .chain(config.validation_errors.0.iter())
@@ -1055,8 +1057,8 @@ impl Config {
 #[derive(Default, Debug)]
 pub struct ConfigChange {
     user_config_change: Option<Arc<str>>,
-    root_ratoml_change: Option<Arc<str>>,
     client_config_change: Option<serde_json::Value>,
+    workspace_ratoml_change: Option<FxHashMap<SourceRootId, (VfsPath, Option<Arc<str>>)>>,
     ratoml_file_change: Option<FxHashMap<SourceRootId, (VfsPath, Option<Arc<str>>)>>,
     source_map_change: Option<Arc<FxHashMap<SourceRootId, SourceRootId>>>,
 }
@@ -1078,9 +1080,15 @@ impl ConfigChange {
         self.user_config_change = content;
     }
 
-    pub fn change_root_ratoml(&mut self, content: Option<Arc<str>>) {
-        assert!(self.root_ratoml_change.is_none()); // Otherwise it is a double write.
-        self.root_ratoml_change = content;
+    pub fn change_workspace_ratoml(
+        &mut self,
+        source_root: SourceRootId,
+        vfs_path: VfsPath,
+        content: Option<Arc<str>>,
+    ) -> Option<(VfsPath, Option<Arc<str>>)> {
+        self.workspace_ratoml_change
+            .get_or_insert_with(Default::default)
+            .insert(source_root, (vfs_path, content))
     }
 
     pub fn change_client_config(&mut self, change: serde_json::Value) {
@@ -1333,11 +1341,6 @@ impl Config {
         // FIXME @alibektas : Temporary solution. I don't think this is right as at some point we may allow users to specify
         // custom USER_CONFIG_PATHs which may also be relative.
         let user_config_path = VfsPath::from(AbsPathBuf::assert(user_config_path));
-        let root_ratoml_path = {
-            let mut p = root_path.clone();
-            p.push("rust-analyzer.toml");
-            VfsPath::new_real_path(p.to_string())
-        };
 
         Config {
             caps: ClientCapabilities::new(caps),
@@ -1352,10 +1355,9 @@ impl Config {
             source_root_parent_map: Arc::new(FxHashMap::default()),
             user_config: None,
             user_config_path,
-            root_ratoml: None,
-            root_ratoml_path,
             detached_files: Default::default(),
             validation_errors: Default::default(),
+            workspace_ratoml_change: Default::default(),
         }
     }
 
@@ -1398,10 +1400,6 @@ impl Config {
         &self.root_path
     }
 
-    pub fn root_ratoml_path(&self) -> &VfsPath {
-        &self.root_ratoml_path
-    }
-
     pub fn caps(&self) -> &ClientCapabilities {
         &self.caps
     }
@@ -3591,7 +3589,7 @@ mod tests {
 
         let mut change = ConfigChange::default();
 
-        change.change_root_ratoml(Some(
+        change.change_user_config(Some(
             toml::toml! {
                 [cargo.cfgs]
                 these = "these"
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 9fd9bee5377..d78e7603582 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -10,6 +10,7 @@ use flycheck::{project_json, FlycheckHandle};
 use hir::ChangeWithProcMacros;
 use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
 use ide_db::base_db::{CrateId, ProcMacroPaths, SourceDatabaseExt};
+use itertools::Itertools;
 use load_cargo::SourceRootConfig;
 use lsp_types::{SemanticTokens, Url};
 use nohash_hasher::IntMap;
@@ -22,7 +23,7 @@ use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, Worksp
 use rustc_hash::{FxHashMap, FxHashSet};
 use tracing::{span, trace, Level};
 use triomphe::Arc;
-use vfs::{AbsPathBuf, AnchoredPathBuf, ChangeKind, Vfs};
+use vfs::{AbsPathBuf, AnchoredPathBuf, ChangeKind, Vfs, VfsPath};
 
 use crate::{
     config::{Config, ConfigChange, ConfigErrors},
@@ -382,26 +383,37 @@ impl GlobalState {
         {
             let config_change = {
                 let user_config_path = self.config.user_config_path();
-                let root_ratoml_path = self.config.root_ratoml_path();
                 let mut change = ConfigChange::default();
                 let db = self.analysis_host.raw_database();
 
+                // FIXME @alibektas : This is silly. There is abs no reason to use VfsPaths when there is SourceRoots. But how
+                // do I resolve a "workspace_root" to its corresponding id without having to rely on a cargo.toml's ( or project json etc.) file id?
+                let workspace_roots = self
+                    .workspaces
+                    .iter()
+                    .map(|ws| VfsPath::from(ws.workspace_root().to_owned()))
+                    .collect_vec();
+
                 for (file_id, (_change_kind, vfs_path)) in modified_ratoml_files {
                     if vfs_path == *user_config_path {
                         change.change_user_config(Some(db.file_text(file_id)));
                         continue;
                     }
 
-                    if vfs_path == *root_ratoml_path {
-                        change.change_root_ratoml(Some(db.file_text(file_id)));
-                        continue;
-                    }
-
                     // If change has been made to a ratoml file that
                     // belongs to a non-local source root, we will ignore it.
-                    // As it doesn't make sense a users to use external config files.
                     let sr_id = db.file_source_root(file_id);
                     let sr = db.source_root(sr_id);
+
+                    if workspace_roots.contains(&vfs_path) {
+                        change.change_workspace_ratoml(
+                            sr_id,
+                            vfs_path,
+                            Some(db.file_text(file_id)),
+                        );
+                        continue;
+                    }
+
                     if !sr.is_library {
                         if let Some((old_path, old_text)) = change.change_ratoml(
                             sr_id,
@@ -430,7 +442,7 @@ impl GlobalState {
             if should_update {
                 self.update_configuration(config);
             } else {
-                // No global or client level config was changed. So we can just naively replace config.
+                // No global or client level config was changed. So we can naively replace config.
                 self.config = Arc::new(config);
             }
         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index fb16f28a14b..b2d360c62db 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -541,7 +541,6 @@ impl GlobalState {
 
             watchers.extend(
                 iter::once(self.config.user_config_path().as_path())
-                    .chain(iter::once(self.config.root_ratoml_path().as_path()))
                     .chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref)))
                     .flatten()
                     .map(|glob_pattern| lsp_types::FileSystemWatcher {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
index 3b05138e187..298e10fb9e0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
@@ -808,7 +808,7 @@ enum Value {
 /// Having a ratoml file at the root of a project enables
 /// configuring global level configurations as well.
 #[test]
-#[ignore = "Root ratomls are not being looked for on startup. Fix this."]
+// #[ignore = "Root ratomls are not being looked for on startup. Fix this."]
 fn ratoml_in_root_is_global() {
     let server = RatomlTest::new(
         vec![