Combine krate_ratoml and workspace_ratomls into one

This commit is contained in:
Ali Bektas 2024-07-29 02:50:53 +02:00
parent d7bedc85b3
commit e0b6d2f681
2 changed files with 163 additions and 162 deletions

View file

@ -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)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
discovered_projects: Vec<ProjectManifest>, discovered_projects: Vec<ProjectManifest>,
@ -779,11 +791,7 @@ pub struct Config {
/// Config node whose values apply to **every** Rust project. /// Config node whose values apply to **every** Rust project.
user_config: Option<(GlobalLocalConfigInput, ConfigErrors)>, user_config: Option<(GlobalLocalConfigInput, ConfigErrors)>,
/// TODO : This file can be used to make global changes while having only a workspace-wide scope. ratoml_file: FxHashMap<SourceRootId, (RatomlFile, ConfigErrors)>,
workspace_ratoml: FxHashMap<SourceRootId, (GlobalLocalConfigInput, ConfigErrors)>,
/// For every `SourceRoot` there can be at most one RATOML file.
krate_ratoml: FxHashMap<SourceRootId, (LocalConfigInput, ConfigErrors)>,
/// Clone of the value that is stored inside a `GlobalState`. /// Clone of the value that is stored inside a `GlobalState`.
source_root_parent_map: Arc<FxHashMap<SourceRootId, SourceRootId>>, source_root_parent_map: Arc<FxHashMap<SourceRootId, SourceRootId>>,
@ -914,83 +922,95 @@ impl Config {
should_update = true; should_update = true;
} }
if let Some(change) = change.workspace_ratoml_change { if let Some(change) = change.ratoml_file_change {
tracing::info!("updating root ra-toml config"); for (source_root_id, (kind, _, text)) in change {
for (source_root_id, (_, text)) in change { match kind {
if let Some(text) = text { RatomlFileKind::Crate => {
let mut toml_errors = vec![]; if let Some(text) = text {
match toml::from_str(&text) { let mut toml_errors = vec![];
Ok(table) => { tracing::info!("updating ra-toml config: {:#}", text);
validate_toml_table( match toml::from_str(&text) {
GlobalLocalConfigInput::FIELDS, Ok(table) => {
&table, validate_toml_table(
&mut String::new(), &[LocalConfigInput::FIELDS],
&mut toml_errors, &table,
); &mut String::new(),
config.workspace_ratoml.insert( &mut toml_errors,
source_root_id, );
( config.ratoml_file.insert(
GlobalLocalConfigInput::from_toml(table, &mut toml_errors), source_root_id,
ConfigErrors( (
toml_errors RatomlFile::Crate(LocalConfigInput::from_toml(
.into_iter() &table,
.map(|(a, b)| ConfigErrorInner::Toml { &mut toml_errors,
config_key: a, )),
error: b, ConfigErrors(
}) toml_errors
.map(Arc::new) .into_iter()
.collect(), .map(|(a, b)| ConfigErrorInner::Toml {
), config_key: a,
), error: b,
); })
should_update = true; .map(Arc::new)
} .collect(),
Err(e) => { ),
config.validation_errors.0.push( ),
ConfigErrorInner::ParseError { reason: e.message().to_owned() } );
.into(), }
); 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) {
if let Some(change) = change.ratoml_file_change { Ok(table) => {
for (source_root_id, (_, text)) in change { validate_toml_table(
if let Some(text) = text { GlobalLocalConfigInput::FIELDS,
let mut toml_errors = vec![]; &table,
tracing::info!("updating ra-toml config: {:#}", text); &mut String::new(),
match toml::from_str(&text) { &mut toml_errors,
Ok(table) => { );
validate_toml_table( config.ratoml_file.insert(
&[LocalConfigInput::FIELDS], source_root_id,
&table, (
&mut String::new(), RatomlFile::Workspace(
&mut toml_errors, GlobalLocalConfigInput::from_toml(
); table,
config.krate_ratoml.insert( &mut toml_errors,
source_root_id, ),
( ),
LocalConfigInput::from_toml(&table, &mut toml_errors), ConfigErrors(
ConfigErrors( toml_errors
toml_errors .into_iter()
.into_iter() .map(|(a, b)| ConfigErrorInner::Toml {
.map(|(a, b)| ConfigErrorInner::Toml { config_key: a,
config_key: a, error: b,
error: b, })
}) .map(Arc::new)
.map(Arc::new) .collect(),
.collect(), ),
), ),
), );
); should_update = true;
} }
Err(e) => { Err(e) => {
config.validation_errors.0.push( config.validation_errors.0.push(
ConfigErrorInner::ParseError { reason: e.message().to_owned() } ConfigErrorInner::ParseError {
.into(), reason: e.message().to_owned(),
); }
.into(),
);
}
}
} }
} }
} }
@ -1022,9 +1042,8 @@ impl Config {
.1 .1
.0 .0
.iter() .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.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()) .chain(config.validation_errors.0.iter())
.cloned() .cloned()
.collect(), .collect(),
@ -1052,8 +1071,8 @@ impl Config {
pub struct ConfigChange { pub struct ConfigChange {
user_config_change: Option<Arc<str>>, user_config_change: Option<Arc<str>>,
client_config_change: Option<serde_json::Value>, client_config_change: Option<serde_json::Value>,
workspace_ratoml_change: Option<FxHashMap<SourceRootId, (VfsPath, Option<Arc<str>>)>>, ratoml_file_change:
ratoml_file_change: Option<FxHashMap<SourceRootId, (VfsPath, Option<Arc<str>>)>>, Option<FxHashMap<SourceRootId, (RatomlFileKind, VfsPath, Option<Arc<str>>)>>,
source_map_change: Option<Arc<FxHashMap<SourceRootId, SourceRootId>>>, source_map_change: Option<Arc<FxHashMap<SourceRootId, SourceRootId>>>,
} }
@ -1063,11 +1082,10 @@ impl ConfigChange {
source_root: SourceRootId, source_root: SourceRootId,
vfs_path: VfsPath, vfs_path: VfsPath,
content: Option<Arc<str>>, content: Option<Arc<str>>,
) -> Option<(VfsPath, Option<Arc<str>>)> { ) -> Option<(RatomlFileKind, VfsPath, Option<Arc<str>>)> {
dbg!("change_ratoml", &vfs_path);
self.ratoml_file_change self.ratoml_file_change
.get_or_insert_with(Default::default) .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<Arc<str>>) { pub fn change_user_config(&mut self, content: Option<Arc<str>>) {
@ -1080,11 +1098,10 @@ impl ConfigChange {
source_root: SourceRootId, source_root: SourceRootId,
vfs_path: VfsPath, vfs_path: VfsPath,
content: Option<Arc<str>>, content: Option<Arc<str>>,
) -> Option<(VfsPath, Option<Arc<str>>)> { ) -> Option<(RatomlFileKind, VfsPath, Option<Arc<str>>)> {
dbg!("change_workspace", &vfs_path); self.ratoml_file_change
self.workspace_ratoml_change
.get_or_insert_with(Default::default) .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) { pub fn change_client_config(&mut self, change: serde_json::Value) {
@ -1346,14 +1363,13 @@ impl Config {
workspace_roots, workspace_roots,
visual_studio_code_version, visual_studio_code_version,
client_config: (FullConfigInput::default(), ConfigErrors(vec![])), client_config: (FullConfigInput::default(), ConfigErrors(vec![])),
krate_ratoml: FxHashMap::default(),
default_config: DEFAULT_CONFIG_DATA.get_or_init(|| Box::leak(Box::default())), default_config: DEFAULT_CONFIG_DATA.get_or_init(|| Box::leak(Box::default())),
source_root_parent_map: Arc::new(FxHashMap::default()), source_root_parent_map: Arc::new(FxHashMap::default()),
user_config: None, user_config: None,
user_config_path, user_config_path,
detached_files: Default::default(), detached_files: Default::default(),
validation_errors: 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<SourceRootId>) -> RustfmtConfig { pub fn rustfmt(&self, source_root_id: Option<SourceRootId>) -> RustfmtConfig {
match &self.rustfmt_overrideCommand(None) { match &self.rustfmt_overrideCommand(source_root_id) {
Some(args) if !args.is_empty() => { Some(args) if !args.is_empty() => {
let mut args = args.clone(); let mut args = args.clone();
let command = args.remove(0); let command = args.remove(0);
@ -2536,27 +2552,23 @@ macro_rules! _impl_for_config_data {
$($doc)* $($doc)*
#[allow(non_snake_case)] #[allow(non_snake_case)]
$vis fn $field(&self, source_root: Option<SourceRootId>) -> &$ty { $vis fn $field(&self, source_root: Option<SourceRootId>) -> &$ty {
let follow = if stringify!($field) == "assist_emitMustUse" { dbg!("YEY"); true } else {false}; let mut source_root = source_root;
let mut current: Option<SourceRootId> = None; while let Some(sr) = source_root {
let mut next: Option<SourceRootId> = source_root; if let Some((file, _)) = self.ratoml_file.get(&sr) {
if follow { dbg!(&self.krate_ratoml);} match file {
while let Some(source_root_id) = next { RatomlFile::Workspace(config) => {
current = next; if let Some(v) = config.local.$field.as_ref() {
next = self.source_root_parent_map.get(&source_root_id).copied(); return &v;
if let Some((config, _)) = self.krate_ratoml.get(&source_root_id) { }
if let Some(value) = config.$field.as_ref() { },
return value; RatomlFile::Crate(config) => {
} 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(&current).as_ref() {
if let Some(v) = root_path_ratoml.local.$field.as_ref() {
return &v;
} }
} }
source_root = self.source_root_parent_map.get(&sr).copied();
} }
if let Some(v) = self.client_config.0.local.$field.as_ref() { if let Some(v) = self.client_config.0.local.$field.as_ref() {
@ -2584,21 +2596,20 @@ macro_rules! _impl_for_config_data {
$($doc)* $($doc)*
#[allow(non_snake_case)] #[allow(non_snake_case)]
$vis fn $field(&self, source_root : Option<SourceRootId>) -> &$ty { $vis fn $field(&self, source_root : Option<SourceRootId>) -> &$ty {
let follow = if stringify!($field) == "rustfmt_extraArgs" { dbg!("YEY"); true } else {false}; let mut source_root = source_root;
let mut current: Option<SourceRootId> = None; while let Some(sr) = source_root {
let mut next: Option<SourceRootId> = source_root; if let Some((file, _)) = self.ratoml_file.get(&sr) {
while let Some(source_root_id) = next { match file {
current = next; RatomlFile::Workspace(config) => {
next = self.source_root_parent_map.get(&source_root_id).copied(); if let Some(v) = config.global.$field.as_ref() {
} return &v;
}
if let Some(current) = current { },
if follow { dbg!(&self.workspace_ratoml);} _ => ()
if let Some((root_path_ratoml, _)) = self.workspace_ratoml.get(&current).as_ref() {
if let Some(v) = root_path_ratoml.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() { if let Some(v) = self.client_config.0.global.$field.as_ref() {
@ -3667,21 +3678,7 @@ mod tests {
let (_, e, _) = config.apply_change(change); let (_, e, _) = config.apply_change(change);
expect_test::expect![[r#" expect_test::expect![[r#"
ConfigErrors( 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); .assert_debug_eq(&e);

View file

@ -26,13 +26,10 @@ use triomphe::Arc;
use vfs::{AbsPathBuf, AnchoredPathBuf, ChangeKind, Vfs, VfsPath}; use vfs::{AbsPathBuf, AnchoredPathBuf, ChangeKind, Vfs, VfsPath};
use crate::{ use crate::{
config::{Config, ConfigChange, ConfigErrors}, config::{Config, ConfigChange, ConfigErrors, RatomlFileKind},
diagnostics::{CheckFixes, DiagnosticCollection}, diagnostics::{CheckFixes, DiagnosticCollection},
line_index::{LineEndings, LineIndex}, line_index::{LineEndings, LineIndex},
lsp::{ lsp::{from_proto, to_proto::url_from_abs_path},
from_proto::{self},
to_proto::url_from_abs_path,
},
lsp_ext, lsp_ext,
main_loop::Task, main_loop::Task,
mem_docs::MemDocs, mem_docs::MemDocs,
@ -411,27 +408,34 @@ impl GlobalState {
let sr_id = db.file_source_root(file_id); let sr_id = db.file_source_root(file_id);
let sr = db.source_root(sr_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 !sr.is_library {
if let Some((old_path, old_text)) = change.change_ratoml( let entry = if workspace_ratoml_paths.contains(&vfs_path) {
sr_id, change.change_workspace_ratoml(
vfs_path.clone(), sr_id,
Some(db.file_text(file_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. // SourceRoot has more than 1 RATOML files. In this case lexicographically smaller wins.
if old_path < vfs_path { 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."); 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. // 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 { } else {