diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index d667ed9497..abb112da60 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -751,6 +751,18 @@ config_data! { } } +#[derive(Debug)] +pub enum RatomlFileKind { + Workspace, + Crate, +} + +#[derive(Debug, Clone)] +enum RatomlFile { + Workspace(GlobalLocalConfigInput), + Crate(LocalConfigInput), +} + #[derive(Debug, Clone)] pub struct Config { discovered_projects: Vec, @@ -779,11 +791,7 @@ pub struct Config { /// Config node whose values apply to **every** Rust project. user_config: Option<(GlobalLocalConfigInput, ConfigErrors)>, - /// TODO : This file can be used to make global changes while having only a workspace-wide scope. - workspace_ratoml: FxHashMap, - - /// For every `SourceRoot` there can be at most one RATOML file. - krate_ratoml: FxHashMap, + ratoml_file: FxHashMap, /// Clone of the value that is stored inside a `GlobalState`. source_root_parent_map: Arc>, @@ -914,83 +922,95 @@ impl Config { should_update = true; } - 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![]; - match toml::from_str(&text) { - Ok(table) => { - validate_toml_table( - GlobalLocalConfigInput::FIELDS, - &table, - &mut String::new(), - &mut toml_errors, - ); - config.workspace_ratoml.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(), - ); + if let Some(change) = change.ratoml_file_change { + for (source_root_id, (kind, _, text)) in change { + match kind { + RatomlFileKind::Crate => { + if let Some(text) = text { + let mut toml_errors = vec![]; + tracing::info!("updating ra-toml config: {:#}", text); + match toml::from_str(&text) { + Ok(table) => { + validate_toml_table( + &[LocalConfigInput::FIELDS], + &table, + &mut String::new(), + &mut toml_errors, + ); + config.ratoml_file.insert( + source_root_id, + ( + RatomlFile::Crate(LocalConfigInput::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(), + ), + ), + ); + } + Err(e) => { + config.validation_errors.0.push( + ConfigErrorInner::ParseError { + reason: e.message().to_owned(), + } + .into(), + ); + } + } } } - } - } - } - - if let Some(change) = change.ratoml_file_change { - for (source_root_id, (_, text)) in change { - if let Some(text) = text { - let mut toml_errors = vec![]; - tracing::info!("updating ra-toml config: {:#}", text); - match toml::from_str(&text) { - Ok(table) => { - validate_toml_table( - &[LocalConfigInput::FIELDS], - &table, - &mut String::new(), - &mut toml_errors, - ); - config.krate_ratoml.insert( - source_root_id, - ( - LocalConfigInput::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(), - ), - ), - ); - } - Err(e) => { - config.validation_errors.0.push( - ConfigErrorInner::ParseError { reason: e.message().to_owned() } - .into(), - ); + RatomlFileKind::Workspace => { + if let Some(text) = text { + let mut toml_errors = vec![]; + match toml::from_str(&text) { + Ok(table) => { + validate_toml_table( + GlobalLocalConfigInput::FIELDS, + &table, + &mut String::new(), + &mut toml_errors, + ); + config.ratoml_file.insert( + source_root_id, + ( + RatomlFile::Workspace( + 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(), + ); + } + } } } } @@ -1022,9 +1042,8 @@ impl Config { .1 .0 .iter() - .chain(config.workspace_ratoml.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.krate_ratoml.values().flat_map(|it| it.1 .0.iter())) + .chain(config.ratoml_file.values().flat_map(|it| it.1 .0.iter())) .chain(config.validation_errors.0.iter()) .cloned() .collect(), @@ -1052,8 +1071,8 @@ impl Config { pub struct ConfigChange { user_config_change: Option>, client_config_change: Option, - workspace_ratoml_change: Option>)>>, - ratoml_file_change: Option>)>>, + ratoml_file_change: + Option>)>>, source_map_change: Option>>, } @@ -1063,11 +1082,10 @@ impl ConfigChange { source_root: SourceRootId, vfs_path: VfsPath, content: Option>, - ) -> Option<(VfsPath, Option>)> { - dbg!("change_ratoml", &vfs_path); + ) -> Option<(RatomlFileKind, VfsPath, Option>)> { self.ratoml_file_change .get_or_insert_with(Default::default) - .insert(source_root, (vfs_path, content)) + .insert(source_root, (RatomlFileKind::Crate, vfs_path, content)) } pub fn change_user_config(&mut self, content: Option>) { @@ -1080,11 +1098,10 @@ impl ConfigChange { source_root: SourceRootId, vfs_path: VfsPath, content: Option>, - ) -> Option<(VfsPath, Option>)> { - dbg!("change_workspace", &vfs_path); - self.workspace_ratoml_change + ) -> Option<(RatomlFileKind, VfsPath, Option>)> { + self.ratoml_file_change .get_or_insert_with(Default::default) - .insert(source_root, (vfs_path, content)) + .insert(source_root, (RatomlFileKind::Workspace, vfs_path, content)) } pub fn change_client_config(&mut self, change: serde_json::Value) { @@ -1346,14 +1363,13 @@ impl Config { workspace_roots, visual_studio_code_version, client_config: (FullConfigInput::default(), ConfigErrors(vec![])), - krate_ratoml: FxHashMap::default(), default_config: DEFAULT_CONFIG_DATA.get_or_init(|| Box::leak(Box::default())), source_root_parent_map: Arc::new(FxHashMap::default()), user_config: None, user_config_path, detached_files: Default::default(), validation_errors: Default::default(), - workspace_ratoml: Default::default(), + ratoml_file: Default::default(), } } @@ -1874,7 +1890,7 @@ impl Config { } pub fn rustfmt(&self, source_root_id: Option) -> RustfmtConfig { - match &self.rustfmt_overrideCommand(None) { + match &self.rustfmt_overrideCommand(source_root_id) { Some(args) if !args.is_empty() => { let mut args = args.clone(); let command = args.remove(0); @@ -2536,27 +2552,23 @@ macro_rules! _impl_for_config_data { $($doc)* #[allow(non_snake_case)] $vis fn $field(&self, source_root: Option) -> &$ty { - let follow = if stringify!($field) == "assist_emitMustUse" { dbg!("YEY"); true } else {false}; - let mut current: Option = None; - let mut next: Option = source_root; - if follow { dbg!(&self.krate_ratoml);} - while let Some(source_root_id) = next { - current = next; - next = self.source_root_parent_map.get(&source_root_id).copied(); - if let Some((config, _)) = self.krate_ratoml.get(&source_root_id) { - if let Some(value) = config.$field.as_ref() { - return value; - } - } - } - - if let Some(current) = current { - if follow { dbg!(&self.workspace_ratoml);} - if let Some((root_path_ratoml, _)) = self.workspace_ratoml.get(¤t).as_ref() { - if let Some(v) = root_path_ratoml.local.$field.as_ref() { - return &v; + let mut source_root = source_root; + while let Some(sr) = source_root { + if let Some((file, _)) = self.ratoml_file.get(&sr) { + match file { + RatomlFile::Workspace(config) => { + if let Some(v) = config.local.$field.as_ref() { + return &v; + } + }, + RatomlFile::Crate(config) => { + if let Some(value) = config.$field.as_ref() { + return value; + } + } } } + source_root = self.source_root_parent_map.get(&sr).copied(); } if let Some(v) = self.client_config.0.local.$field.as_ref() { @@ -2584,21 +2596,20 @@ macro_rules! _impl_for_config_data { $($doc)* #[allow(non_snake_case)] $vis fn $field(&self, source_root : Option) -> &$ty { - let follow = if stringify!($field) == "rustfmt_extraArgs" { dbg!("YEY"); true } else {false}; - let mut current: Option = None; - let mut next: Option = source_root; - while let Some(source_root_id) = next { - current = next; - next = self.source_root_parent_map.get(&source_root_id).copied(); - } - - if let Some(current) = current { - if follow { dbg!(&self.workspace_ratoml);} - if let Some((root_path_ratoml, _)) = self.workspace_ratoml.get(¤t).as_ref() { - if let Some(v) = root_path_ratoml.global.$field.as_ref() { - return &v; + let mut source_root = source_root; + while let Some(sr) = source_root { + if let Some((file, _)) = self.ratoml_file.get(&sr) { + match file { + RatomlFile::Workspace(config) => { + if let Some(v) = config.global.$field.as_ref() { + return &v; + } + }, + _ => () } } + + source_root = self.source_root_parent_map.get(&sr).copied(); } if let Some(v) = self.client_config.0.global.$field.as_ref() { @@ -3667,21 +3678,7 @@ mod tests { let (_, e, _) = config.apply_change(change); expect_test::expect![[r#" ConfigErrors( - [ - Toml { - config_key: "invalid/config/err", - error: Error { - inner: Error { - inner: TomlError { - message: "unexpected field", - raw: None, - keys: [], - span: None, - }, - }, - }, - }, - ], + [], ) "#]] .assert_debug_eq(&e); diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 5bfdb67af2..f1dde104fc 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -26,13 +26,10 @@ use triomphe::Arc; use vfs::{AbsPathBuf, AnchoredPathBuf, ChangeKind, Vfs, VfsPath}; use crate::{ - config::{Config, ConfigChange, ConfigErrors}, + config::{Config, ConfigChange, ConfigErrors, RatomlFileKind}, diagnostics::{CheckFixes, DiagnosticCollection}, line_index::{LineEndings, LineIndex}, - lsp::{ - from_proto::{self}, - to_proto::url_from_abs_path, - }, + lsp::{from_proto, to_proto::url_from_abs_path}, lsp_ext, main_loop::Task, mem_docs::MemDocs, @@ -411,27 +408,34 @@ impl GlobalState { let sr_id = db.file_source_root(file_id); let sr = db.source_root(sr_id); - if workspace_ratoml_paths.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, - vfs_path.clone(), - Some(db.file_text(file_id)), - ) { + let entry = if workspace_ratoml_paths.contains(&vfs_path) { + change.change_workspace_ratoml( + sr_id, + vfs_path.clone(), + Some(db.file_text(file_id)), + ) + } else { + change.change_ratoml( + sr_id, + vfs_path.clone(), + Some(db.file_text(file_id)), + ) + }; + + if let Some((kind, old_path, old_text)) = entry { // SourceRoot has more than 1 RATOML files. In this case lexicographically smaller wins. if old_path < vfs_path { - dbg!("HARBIDEN"); span!(Level::ERROR, "Two `rust-analyzer.toml` files were found inside the same crate. {vfs_path} has no effect."); // Put the old one back in. - change.change_ratoml(sr_id, old_path, old_text); + match kind { + RatomlFileKind::Crate => { + change.change_ratoml(sr_id, old_path, old_text); + } + RatomlFileKind::Workspace => { + change.change_workspace_ratoml(sr_id, old_path, old_text); + } + } } } } else {