mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 05:53:45 +00:00
Turn root_ratoml into workspace_ratomls
This commit is contained in:
parent
0ba6f4eda0
commit
c4c6b64976
4 changed files with 84 additions and 75 deletions
|
@ -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;
|
||||
}
|
||||
.into()]),
|
||||
));
|
||||
Err(e) => {
|
||||
config.validation_errors.0.push(
|
||||
ConfigErrorInner::ParseError { reason: e.message().to_owned() }
|
||||
.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"
|
||||
|
|
|
@ -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)));
|
||||
// If change has been made to a ratoml file that
|
||||
// belongs to a non-local source root, we will ignore it.
|
||||
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 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 !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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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![
|
||||
|
|
Loading…
Reference in a new issue