@@ -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 {
11401163pub 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 ) ]
11461170pub struct ConfigErrors ( Vec < Arc < ConfigErrorInner > > ) ;
11471171
11481172impl 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
0 commit comments