@@ -7,6 +7,7 @@ use std::collections::HashMap;
7
7
use std:: fmt:: Display ;
8
8
use std:: fs;
9
9
use std:: io:: Error as IOError ;
10
+ use std:: path:: PathBuf ;
10
11
use toml:: de:: Error as TomlError ;
11
12
12
13
#[ derive( Debug , Clone , PartialEq ) ]
@@ -24,6 +25,19 @@ pub struct ConfigRaw {
24
25
pub editor : Option < toml:: Value > ,
25
26
}
26
27
28
+ impl ConfigRaw {
29
+ pub fn load ( path : PathBuf ) -> Result < Option < ConfigRaw > , ConfigLoadError > {
30
+ match fs:: read_to_string ( path) {
31
+ // Don't treat a missing config file as an error.
32
+ Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: NotFound => Ok ( None ) ,
33
+ Err ( e) => Err ( ConfigLoadError :: Error ( e) ) ,
34
+ Ok ( s) => toml:: from_str ( & s)
35
+ . map ( Some )
36
+ . map_err ( ConfigLoadError :: BadConfig ) ,
37
+ }
38
+ }
39
+ }
40
+
27
41
impl Default for Config {
28
42
fn default ( ) -> Config {
29
43
Config {
@@ -56,80 +70,40 @@ impl Display for ConfigLoadError {
56
70
}
57
71
58
72
impl Config {
59
- pub fn load (
60
- global : Result < String , ConfigLoadError > ,
61
- local : Result < String , ConfigLoadError > ,
62
- ) -> Result < Config , ConfigLoadError > {
63
- let global_config: Result < ConfigRaw , ConfigLoadError > =
64
- global. and_then ( |file| toml:: from_str ( & file) . map_err ( ConfigLoadError :: BadConfig ) ) ;
65
- let local_config: Result < ConfigRaw , ConfigLoadError > =
66
- local. and_then ( |file| toml:: from_str ( & file) . map_err ( ConfigLoadError :: BadConfig ) ) ;
67
- let res = match ( global_config, local_config) {
68
- ( Ok ( global) , Ok ( local) ) => {
69
- let mut keys = keymap:: default ( ) ;
70
- if let Some ( global_keys) = global. keys {
71
- merge_keys ( & mut keys, global_keys)
72
- }
73
- if let Some ( local_keys) = local. keys {
74
- merge_keys ( & mut keys, local_keys)
75
- }
76
-
77
- let editor = match ( global. editor , local. editor ) {
78
- ( None , None ) => helix_view:: editor:: Config :: default ( ) ,
79
- ( None , Some ( val) ) | ( Some ( val) , None ) => {
80
- val. try_into ( ) . map_err ( ConfigLoadError :: BadConfig ) ?
81
- }
82
- ( Some ( global) , Some ( local) ) => merge_toml_values_with_strategy (
83
- global,
84
- local,
85
- & MergeStrategy {
86
- array : MergeMode :: Never ,
87
- table : MergeMode :: Always ,
88
- } ,
89
- )
90
- . try_into ( )
91
- . map_err ( ConfigLoadError :: BadConfig ) ?,
92
- } ;
93
-
94
- Config {
95
- theme : local. theme . or ( global. theme ) ,
96
- keys,
97
- editor,
98
- }
73
+ /// Merge a ConfigRaw value into a Config.
74
+ pub fn apply ( & mut self , opt_config_raw : Option < ConfigRaw > ) -> Result < ( ) , ConfigLoadError > {
75
+ if let Some ( config_raw) = opt_config_raw {
76
+ if let Some ( theme) = config_raw. theme {
77
+ self . theme = Some ( theme)
99
78
}
100
- // if any configs are invalid return that first
101
- ( _, Err ( ConfigLoadError :: BadConfig ( err) ) )
102
- | ( Err ( ConfigLoadError :: BadConfig ( err) ) , _) => {
103
- return Err ( ConfigLoadError :: BadConfig ( err) )
79
+ if let Some ( keymap) = config_raw. keys {
80
+ merge_keys ( & mut self . keys , keymap)
104
81
}
105
- ( Ok ( config ) , Err ( _ ) ) | ( Err ( _ ) , Ok ( config ) ) => {
106
- let mut keys = keymap :: default ( ) ;
107
- if let Some ( keymap ) = config . keys {
108
- merge_keys ( & mut keys , keymap ) ;
109
- }
110
- Config {
111
- theme : config . theme ,
112
- keys ,
113
- editor : config . editor . map_or_else (
114
- || Ok ( helix_view :: editor :: Config :: default ( ) ) ,
115
- |val| val . try_into ( ) . map_err ( ConfigLoadError :: BadConfig ) ,
116
- ) ? ,
117
- }
82
+ if let Some ( editor ) = config_raw . editor {
83
+ // We only know how to merge toml values, so convert back to toml first.
84
+ let val = toml :: Value :: try_from ( & self . editor ) . unwrap ( ) ;
85
+ self . editor = merge_toml_values_with_strategy (
86
+ val ,
87
+ editor ,
88
+ & MergeStrategy {
89
+ array : MergeMode :: Never ,
90
+ table : MergeMode :: Always ,
91
+ } ,
92
+ )
93
+ . try_into ( )
94
+ . map_err ( ConfigLoadError :: BadConfig ) ?
118
95
}
119
-
120
- // these are just two io errors return the one for the global config
121
- ( Err ( err) , Err ( _) ) => return Err ( err) ,
122
- } ;
123
-
124
- Ok ( res)
96
+ }
97
+ Ok ( ( ) )
125
98
}
126
99
127
100
pub fn load_default ( ) -> Result < Config , ConfigLoadError > {
128
- let global_config =
129
- fs:: read_to_string ( helix_loader:: config_file ( ) ) . map_err ( ConfigLoadError :: Error ) ;
130
- let local_config = fs:: read_to_string ( helix_loader:: workspace_config_file ( ) )
131
- . map_err ( ConfigLoadError :: Error ) ;
132
- Config :: load ( global_config, local_config)
101
+ let mut config = Config :: default ( ) ;
102
+ let global = ConfigRaw :: load ( helix_loader:: config_file ( ) ) ?;
103
+ let local = ConfigRaw :: load ( helix_loader:: workspace_config_file ( ) ) ?;
104
+ config. apply ( global) ?;
105
+ config. apply ( local) ?;
106
+ Ok ( config)
133
107
}
134
108
}
135
109
@@ -139,7 +113,12 @@ mod tests {
139
113
140
114
impl Config {
141
115
fn load_test ( global : & str , local : & str ) -> Config {
142
- Config :: load ( Ok ( global. to_owned ( ) ) , Ok ( local. to_owned ( ) ) ) . unwrap ( )
116
+ let mut config = Config :: default ( ) ;
117
+ let global = toml:: from_str ( & global) . unwrap ( ) ;
118
+ let local = toml:: from_str ( & local) . unwrap ( ) ;
119
+ config. apply ( Some ( global) ) . unwrap ( ) ;
120
+ config. apply ( Some ( local) ) . unwrap ( ) ;
121
+ config
143
122
}
144
123
}
145
124
@@ -174,6 +153,13 @@ mod tests {
174
153
assert_eq ! ( config. editor. shell, [ "fish" , "-c" ] ) ;
175
154
}
176
155
156
+ #[ test]
157
+ fn load_non_existing_config ( ) {
158
+ let path = PathBuf :: from ( r"does-not-exist" ) ;
159
+ let result = ConfigRaw :: load ( path) ;
160
+ assert ! ( result. is_ok_and( |x| x. is_none( ) ) ) ;
161
+ }
162
+
177
163
#[ test]
178
164
fn parsing_keymaps_config_file ( ) {
179
165
use crate :: keymap;
0 commit comments