Skip to content

Commit 630dc63

Browse files
committed
Minor fixes for ratoml module
- Parse errors are reflected as such by defining a new variant called `ConfigError::ParseError` - Amend `config::ConfigChange::apply_change`. - User config can be detected once again. - New error collection has been added to store config level agnostic errors.
1 parent 1bb376c commit 630dc63

File tree

3 files changed

+128
-115
lines changed

3 files changed

+128
-115
lines changed

crates/rust-analyzer/src/config.rs

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,6 @@ pub struct Config {
679679
/// | Windows | `{FOLDERID_RoamingAppData}` | C:\Users\Alice\AppData\Roaming |
680680
user_config_path: VfsPath,
681681

682-
/// FIXME @alibektas : Change this to sth better.
683682
/// Config node whose values apply to **every** Rust project.
684683
user_config: Option<(GlobalLocalConfigInput, ConfigErrors)>,
685684

@@ -695,6 +694,13 @@ pub struct Config {
695694
/// Clone of the value that is stored inside a `GlobalState`.
696695
source_root_parent_map: Arc<FxHashMap<SourceRootId, SourceRootId>>,
697696

697+
/// Use case : It is an error to have an empty value for `check_command`.
698+
/// Since it is a `global` command at the moment, its final value can only be determined by
699+
/// traversing through `global` configs and the `client` config. However the non-null value constraint
700+
/// is config level agnostic, so this requires an independent error storage
701+
/// FIXME : bad name I know...
702+
other_errors: ConfigErrors,
703+
698704
detached_files: Vec<AbsPathBuf>,
699705
}
700706

@@ -715,6 +721,7 @@ impl Config {
715721
/// The return tuple's bool component signals whether the `GlobalState` should call its `update_configuration()` method.
716722
fn apply_change_with_sink(&self, change: ConfigChange) -> (Config, bool) {
717723
let mut config = self.clone();
724+
config.other_errors = ConfigErrors::default();
718725

719726
let mut should_update = false;
720727

@@ -743,6 +750,7 @@ impl Config {
743750

744751
if let Some(mut json) = change.client_config_change {
745752
tracing::info!("updating config from JSON: {:#}", json);
753+
746754
if !(json.is_null() || json.as_object().map_or(false, |it| it.is_empty())) {
747755
let mut json_errors = vec![];
748756
let detached_files = get_field::<Vec<Utf8PathBuf>>(
@@ -758,6 +766,35 @@ impl Config {
758766

759767
patch_old_style::patch_json_for_outdated_configs(&mut json);
760768

769+
let snips = self.completion_snippets_custom().to_owned();
770+
771+
for (name, def) in snips.iter() {
772+
if def.prefix.is_empty() && def.postfix.is_empty() {
773+
continue;
774+
}
775+
let scope = match def.scope {
776+
SnippetScopeDef::Expr => SnippetScope::Expr,
777+
SnippetScopeDef::Type => SnippetScope::Type,
778+
SnippetScopeDef::Item => SnippetScope::Item,
779+
};
780+
#[allow(clippy::single_match)]
781+
match Snippet::new(
782+
&def.prefix,
783+
&def.postfix,
784+
&def.body,
785+
def.description.as_ref().unwrap_or(name),
786+
&def.requires,
787+
scope,
788+
) {
789+
Some(snippet) => config.snippets.push(snippet),
790+
None => json_errors.push((
791+
name.to_owned(),
792+
<serde_json::Error as serde::de::Error>::custom(format!(
793+
"snippet {name} is invalid or triggers are missing",
794+
)),
795+
)),
796+
}
797+
}
761798
config.client_config = (
762799
FullConfigInput::from_json(json, &mut json_errors),
763800
ConfigErrors(
@@ -797,8 +834,15 @@ impl Config {
797834
));
798835
should_update = true;
799836
}
800-
// FIXME
801-
Err(_) => (),
837+
Err(e) => {
838+
config.root_ratoml = Some((
839+
GlobalLocalConfigInput::from_toml(toml::map::Map::default(), &mut vec![]),
840+
ConfigErrors(vec![ConfigErrorInner::ParseError {
841+
reason: e.message().to_owned(),
842+
}
843+
.into()]),
844+
));
845+
}
802846
}
803847
}
804848

@@ -833,8 +877,18 @@ impl Config {
833877
),
834878
);
835879
}
836-
// FIXME
837-
Err(_) => (),
880+
Err(e) => {
881+
config.root_ratoml = Some((
882+
GlobalLocalConfigInput::from_toml(
883+
toml::map::Map::default(),
884+
&mut vec![],
885+
),
886+
ConfigErrors(vec![ConfigErrorInner::ParseError {
887+
reason: e.message().to_owned(),
888+
}
889+
.into()]),
890+
));
891+
}
838892
}
839893
}
840894
}
@@ -844,45 +898,13 @@ impl Config {
844898
config.source_root_parent_map = source_root_map;
845899
}
846900

847-
let snips = self.completion_snippets_custom().to_owned();
848-
849-
for (name, def) in snips.iter() {
850-
if def.prefix.is_empty() && def.postfix.is_empty() {
851-
continue;
852-
}
853-
let scope = match def.scope {
854-
SnippetScopeDef::Expr => SnippetScope::Expr,
855-
SnippetScopeDef::Type => SnippetScope::Type,
856-
SnippetScopeDef::Item => SnippetScope::Item,
857-
};
858-
#[allow(clippy::single_match)]
859-
match Snippet::new(
860-
&def.prefix,
861-
&def.postfix,
862-
&def.body,
863-
def.description.as_ref().unwrap_or(name),
864-
&def.requires,
865-
scope,
866-
) {
867-
Some(snippet) => config.snippets.push(snippet),
868-
// FIXME
869-
// None => error_sink.0.push(ConfigErrorInner::Json {
870-
// config_key: "".to_owned(),
871-
// error: <serde_json::Error as serde::de::Error>::custom(format!(
872-
// "snippet {name} is invalid or triggers are missing",
873-
// )),
874-
// }),
875-
None => (),
876-
}
901+
if config.check_command().is_empty() {
902+
config.other_errors.0.push(Arc::new(ConfigErrorInner::Json {
903+
config_key: "/check/command".to_owned(),
904+
error: serde_json::Error::custom("expected a non-empty string"),
905+
}));
877906
}
878907

879-
// FIXME: bring this back
880-
// if config.check_command().is_empty() {
881-
// error_sink.0.push(ConfigErrorInner::Json {
882-
// config_key: "/check/command".to_owned(),
883-
// error: serde_json::Error::custom("expected a non-empty string"),
884-
// });
885-
// }
886908
(config, should_update)
887909
}
888910

@@ -900,6 +922,7 @@ impl Config {
900922
.chain(config.root_ratoml.as_ref().into_iter().flat_map(|it| it.1 .0.iter()))
901923
.chain(config.user_config.as_ref().into_iter().flat_map(|it| it.1 .0.iter()))
902924
.chain(config.ratoml_files.values().flat_map(|it| it.1 .0.iter()))
925+
.chain(config.other_errors.0.iter())
903926
.cloned()
904927
.collect(),
905928
);
@@ -1140,9 +1163,10 @@ pub struct ClientCommandsConfig {
11401163
pub enum ConfigErrorInner {
11411164
Json { config_key: String, error: serde_json::Error },
11421165
Toml { config_key: String, error: toml::de::Error },
1166+
ParseError { reason: String },
11431167
}
11441168

1145-
#[derive(Clone, Debug)]
1169+
#[derive(Clone, Debug, Default)]
11461170
pub struct ConfigErrors(Vec<Arc<ConfigErrorInner>>);
11471171

11481172
impl ConfigErrors {
@@ -1164,6 +1188,7 @@ impl fmt::Display for ConfigErrors {
11641188
f(&": ")?;
11651189
f(e)
11661190
}
1191+
ConfigErrorInner::ParseError { reason } => f(reason),
11671192
});
11681193
write!(f, "invalid config value{}:\n{}", if self.0.len() == 1 { "" } else { "s" }, errors)
11691194
}
@@ -1217,6 +1242,7 @@ impl Config {
12171242
root_ratoml: None,
12181243
root_ratoml_path,
12191244
detached_files: Default::default(),
1245+
other_errors: Default::default(),
12201246
}
12211247
}
12221248

@@ -2597,6 +2623,7 @@ macro_rules! _impl_for_config_data {
25972623
}
25982624
}
25992625

2626+
26002627
&self.default_config.global.$field
26012628
}
26022629
)*
@@ -3299,7 +3326,7 @@ fn validate_toml_table(
32993326
ptr.push_str(k);
33003327

33013328
match v {
3302-
// This is a table config, any entry in it is therefor valid
3329+
// This is a table config, any entry in it is therefore valid
33033330
toml::Value::Table(_) if verify(ptr) => (),
33043331
toml::Value::Table(table) => validate_toml_table(known_ptrs, table, ptr, error_sink),
33053332
_ if !verify(ptr) => error_sink

crates/rust-analyzer/src/main_loop.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
use std::{
55
fmt,
6-
ops::Div as _,
6+
ops::{Div as _, Not},
77
time::{Duration, Instant},
88
};
99

@@ -13,11 +13,12 @@ use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath};
1313
use lsp_server::{Connection, Notification, Request};
1414
use lsp_types::{notification::Notification as _, TextDocumentIdentifier};
1515
use stdx::thread::ThreadIntent;
16-
use tracing::{span, Level};
16+
use tracing::{error, span, Level};
17+
use triomphe::Arc;
1718
use vfs::FileId;
1819

1920
use crate::{
20-
config::Config,
21+
config::{Config, ConfigChange},
2122
diagnostics::{fetch_native_diagnostics, DiagnosticsGeneration},
2223
dispatch::{NotificationDispatcher, RequestDispatcher},
2324
global_state::{file_id_to_url, url_to_file_id, GlobalState},
@@ -146,6 +147,8 @@ impl GlobalState {
146147
self.register_did_save_capability();
147148
}
148149

150+
self.fetch_aux_files();
151+
149152
self.fetch_workspaces_queue.request_op("startup".to_owned(), false);
150153
if let Some((cause, force_crate_graph_reload)) =
151154
self.fetch_workspaces_queue.should_start_op()
@@ -1038,4 +1041,43 @@ impl GlobalState {
10381041
.finish();
10391042
Ok(())
10401043
}
1044+
1045+
fn fetch_aux_files(&mut self) {
1046+
let user_config_path = self.config.user_config_path();
1047+
let root_ratoml_path = self.config.root_ratoml_path();
1048+
1049+
{
1050+
let vfs = &mut self.vfs.write().0;
1051+
let loader = &mut self.loader;
1052+
1053+
if vfs.file_id(user_config_path).is_none() {
1054+
if let Some(user_cfg_abs) = user_config_path.as_path() {
1055+
let contents = loader.handle.load_sync(user_cfg_abs);
1056+
vfs.set_file_contents(user_config_path.clone(), contents);
1057+
} else {
1058+
error!("Non-abs virtual path for user config.");
1059+
}
1060+
}
1061+
1062+
if vfs.file_id(root_ratoml_path).is_none() {
1063+
// FIXME @alibektas : Sometimes root_path_ratoml collide with a regular ratoml.
1064+
// Although this shouldn't be a problem because everything is mapped to a `FileId`.
1065+
// We may want to further think about this.
1066+
if let Some(root_ratoml_abs) = root_ratoml_path.as_path() {
1067+
let contents = loader.handle.load_sync(root_ratoml_abs);
1068+
vfs.set_file_contents(root_ratoml_path.clone(), contents);
1069+
} else {
1070+
error!("Non-abs virtual path for user config.");
1071+
}
1072+
}
1073+
}
1074+
1075+
let mut config_change = ConfigChange::default();
1076+
config_change.change_source_root_parent_map(self.local_roots_parent_map.clone());
1077+
1078+
let (config, e, _) = self.config.apply_change(config_change);
1079+
self.config_errors = e.is_empty().not().then_some(e);
1080+
1081+
self.config = Arc::new(config);
1082+
}
10411083
}

0 commit comments

Comments
 (0)