@@ -779,7 +779,6 @@ pub struct Config {
779
779
/// | Windows | `{FOLDERID_RoamingAppData}` | C:\Users\Alice\AppData\Roaming |
780
780
user_config_path : VfsPath ,
781
781
782
- /// FIXME @alibektas : Change this to sth better.
783
782
/// Config node whose values apply to **every** Rust project.
784
783
user_config : Option < ( GlobalLocalConfigInput , ConfigErrors ) > ,
785
784
@@ -795,6 +794,12 @@ pub struct Config {
795
794
/// Clone of the value that is stored inside a `GlobalState`.
796
795
source_root_parent_map : Arc < FxHashMap < SourceRootId , SourceRootId > > ,
797
796
797
+ /// Use case : It is an error to have an empty value for `check_command`.
798
+ /// Since it is a `global` command at the moment, its final value can only be determined by
799
+ /// traversing through `global` configs and the `client` config. However the non-null value constraint
800
+ /// is config level agnostic, so this requires an independent error storage
801
+ validation_errors : ConfigErrors ,
802
+
798
803
detached_files : Vec < AbsPathBuf > ,
799
804
}
800
805
@@ -824,6 +829,7 @@ impl Config {
824
829
/// The return tuple's bool component signals whether the `GlobalState` should call its `update_configuration()` method.
825
830
fn apply_change_with_sink ( & self , change : ConfigChange ) -> ( Config , bool ) {
826
831
let mut config = self . clone ( ) ;
832
+ config. validation_errors = ConfigErrors :: default ( ) ;
827
833
828
834
let mut should_update = false ;
829
835
@@ -852,6 +858,7 @@ impl Config {
852
858
853
859
if let Some ( mut json) = change. client_config_change {
854
860
tracing:: info!( "updating config from JSON: {:#}" , json) ;
861
+
855
862
if !( json. is_null ( ) || json. as_object ( ) . map_or ( false , |it| it. is_empty ( ) ) ) {
856
863
let mut json_errors = vec ! [ ] ;
857
864
let detached_files = get_field_json :: < Vec < Utf8PathBuf > > (
@@ -867,6 +874,37 @@ impl Config {
867
874
868
875
patch_old_style:: patch_json_for_outdated_configs ( & mut json) ;
869
876
877
+ // IMPORTANT : This holds as long as ` completion_snippets_custom` is declared `client`.
878
+ config. snippets . clear ( ) ;
879
+
880
+ let snips = self . completion_snippets_custom ( ) . to_owned ( ) ;
881
+
882
+ for ( name, def) in snips. iter ( ) {
883
+ if def. prefix . is_empty ( ) && def. postfix . is_empty ( ) {
884
+ continue ;
885
+ }
886
+ let scope = match def. scope {
887
+ SnippetScopeDef :: Expr => SnippetScope :: Expr ,
888
+ SnippetScopeDef :: Type => SnippetScope :: Type ,
889
+ SnippetScopeDef :: Item => SnippetScope :: Item ,
890
+ } ;
891
+ match Snippet :: new (
892
+ & def. prefix ,
893
+ & def. postfix ,
894
+ & def. body ,
895
+ def. description . as_ref ( ) . unwrap_or ( name) ,
896
+ & def. requires ,
897
+ scope,
898
+ ) {
899
+ Some ( snippet) => config. snippets . push ( snippet) ,
900
+ None => json_errors. push ( (
901
+ name. to_owned ( ) ,
902
+ <serde_json:: Error as serde:: de:: Error >:: custom ( format ! (
903
+ "snippet {name} is invalid or triggers are missing" ,
904
+ ) ) ,
905
+ ) ) ,
906
+ }
907
+ }
870
908
config. client_config = (
871
909
FullConfigInput :: from_json ( json, & mut json_errors) ,
872
910
ConfigErrors (
@@ -906,8 +944,15 @@ impl Config {
906
944
) ) ;
907
945
should_update = true ;
908
946
}
909
- // FIXME
910
- Err ( _) => ( ) ,
947
+ Err ( e) => {
948
+ config. root_ratoml = Some ( (
949
+ GlobalLocalConfigInput :: from_toml ( toml:: map:: Map :: default ( ) , & mut vec ! [ ] ) ,
950
+ ConfigErrors ( vec ! [ ConfigErrorInner :: ParseError {
951
+ reason: e. message( ) . to_owned( ) ,
952
+ }
953
+ . into( ) ] ) ,
954
+ ) ) ;
955
+ }
911
956
}
912
957
}
913
958
@@ -942,8 +987,18 @@ impl Config {
942
987
) ,
943
988
) ;
944
989
}
945
- // FIXME
946
- Err ( _) => ( ) ,
990
+ Err ( e) => {
991
+ config. root_ratoml = Some ( (
992
+ GlobalLocalConfigInput :: from_toml (
993
+ toml:: map:: Map :: default ( ) ,
994
+ & mut vec ! [ ] ,
995
+ ) ,
996
+ ConfigErrors ( vec ! [ ConfigErrorInner :: ParseError {
997
+ reason: e. message( ) . to_owned( ) ,
998
+ }
999
+ . into( ) ] ) ,
1000
+ ) ) ;
1001
+ }
947
1002
}
948
1003
}
949
1004
}
@@ -953,48 +1008,13 @@ impl Config {
953
1008
config. source_root_parent_map = source_root_map;
954
1009
}
955
1010
956
- // IMPORTANT : This holds as long as ` completion_snippets_custom` is declared `client`.
957
- config. snippets . clear ( ) ;
958
-
959
- let snips = self . completion_snippets_custom ( ) . to_owned ( ) ;
960
-
961
- for ( name, def) in snips. iter ( ) {
962
- if def. prefix . is_empty ( ) && def. postfix . is_empty ( ) {
963
- continue ;
964
- }
965
- let scope = match def. scope {
966
- SnippetScopeDef :: Expr => SnippetScope :: Expr ,
967
- SnippetScopeDef :: Type => SnippetScope :: Type ,
968
- SnippetScopeDef :: Item => SnippetScope :: Item ,
969
- } ;
970
- #[ allow( clippy:: single_match) ]
971
- match Snippet :: new (
972
- & def. prefix ,
973
- & def. postfix ,
974
- & def. body ,
975
- def. description . as_ref ( ) . unwrap_or ( name) ,
976
- & def. requires ,
977
- scope,
978
- ) {
979
- Some ( snippet) => config. snippets . push ( snippet) ,
980
- // FIXME
981
- // None => error_sink.0.push(ConfigErrorInner::Json {
982
- // config_key: "".to_owned(),
983
- // error: <serde_json::Error as serde::de::Error>::custom(format!(
984
- // "snippet {name} is invalid or triggers are missing",
985
- // )),
986
- // }),
987
- None => ( ) ,
988
- }
1011
+ if config. check_command ( ) . is_empty ( ) {
1012
+ config. validation_errors . 0 . push ( Arc :: new ( ConfigErrorInner :: Json {
1013
+ config_key : "/check/command" . to_owned ( ) ,
1014
+ error : serde_json:: Error :: custom ( "expected a non-empty string" ) ,
1015
+ } ) ) ;
989
1016
}
990
1017
991
- // FIXME: bring this back
992
- // if config.check_command().is_empty() {
993
- // error_sink.0.push(ConfigErrorInner::Json {
994
- // config_key: "/check/command".to_owned(),
995
- // error: serde_json::Error::custom("expected a non-empty string"),
996
- // });
997
- // }
998
1018
( config, should_update)
999
1019
}
1000
1020
@@ -1012,6 +1032,7 @@ impl Config {
1012
1032
. chain ( config. root_ratoml . as_ref ( ) . into_iter ( ) . flat_map ( |it| it. 1 . 0 . iter ( ) ) )
1013
1033
. chain ( config. user_config . as_ref ( ) . into_iter ( ) . flat_map ( |it| it. 1 . 0 . iter ( ) ) )
1014
1034
. chain ( config. ratoml_files . values ( ) . flat_map ( |it| it. 1 . 0 . iter ( ) ) )
1035
+ . chain ( config. validation_errors . 0 . iter ( ) )
1015
1036
. cloned ( )
1016
1037
. collect ( ) ,
1017
1038
) ;
@@ -1259,9 +1280,10 @@ pub struct ClientCommandsConfig {
1259
1280
pub enum ConfigErrorInner {
1260
1281
Json { config_key : String , error : serde_json:: Error } ,
1261
1282
Toml { config_key : String , error : toml:: de:: Error } ,
1283
+ ParseError { reason : String } ,
1262
1284
}
1263
1285
1264
- #[ derive( Clone , Debug ) ]
1286
+ #[ derive( Clone , Debug , Default ) ]
1265
1287
pub struct ConfigErrors ( Vec < Arc < ConfigErrorInner > > ) ;
1266
1288
1267
1289
impl ConfigErrors {
@@ -1283,6 +1305,7 @@ impl fmt::Display for ConfigErrors {
1283
1305
f ( & ": " ) ?;
1284
1306
f ( e)
1285
1307
}
1308
+ ConfigErrorInner :: ParseError { reason } => f ( reason) ,
1286
1309
} ) ;
1287
1310
write ! ( f, "invalid config value{}:\n {}" , if self . 0 . len( ) == 1 { "" } else { "s" } , errors)
1288
1311
}
@@ -1336,6 +1359,7 @@ impl Config {
1336
1359
root_ratoml : None ,
1337
1360
root_ratoml_path,
1338
1361
detached_files : Default :: default ( ) ,
1362
+ validation_errors : Default :: default ( ) ,
1339
1363
}
1340
1364
}
1341
1365
@@ -2575,6 +2599,7 @@ macro_rules! _impl_for_config_data {
2575
2599
}
2576
2600
}
2577
2601
2602
+
2578
2603
& self . default_config. global. $field
2579
2604
}
2580
2605
) *
@@ -3304,7 +3329,7 @@ fn validate_toml_table(
3304
3329
ptr. push_str ( k) ;
3305
3330
3306
3331
match v {
3307
- // This is a table config, any entry in it is therefor valid
3332
+ // This is a table config, any entry in it is therefore valid
3308
3333
toml:: Value :: Table ( _) if verify ( ptr) => ( ) ,
3309
3334
toml:: Value :: Table ( table) => validate_toml_table ( known_ptrs, table, ptr, error_sink) ,
3310
3335
_ if !verify ( ptr) => error_sink
0 commit comments