1
- //! There are two files that store properties for Alloy, the *cache* and the *config*.
2
- //!
3
- //! The most important distinction between these is that Alloy never writes to the *config*
4
- //! but it does write to the *cache* to save portions of the state of the program (e.g. window size
5
- //! and position).
6
- //!
7
- //! Furthermore it's generally true that the user will only edit the *config* to specify their
8
- //! preferences.
9
- //!
10
1
use directories:: ProjectDirs ;
11
2
use serde:: { Deserialize , Serialize } ;
12
- use std:: { borrow :: Cow , collections:: BTreeMap , fs, path :: Path , path:: PathBuf } ;
3
+ use std:: { collections:: BTreeMap , fs, path:: PathBuf } ;
13
4
14
5
/// Application name for project directories
15
6
const APPLICATION : & str = "Alloy" ;
16
7
17
- #[ derive( Debug , Serialize , Deserialize , Copy , Clone , PartialEq , Eq ) ]
18
- #[ serde( rename_all = "snake_case" ) ]
8
+ #[ derive( Clone , Copy , Debug , Default , Eq , PartialEq , Serialize , Deserialize ) ]
9
+ pub enum WindowMode {
10
+ #[ default]
11
+ Normal ,
12
+ Maximized ,
13
+ Fullscreen ,
14
+ }
15
+
16
+ #[ derive( Clone , Copy , Debug , Default , Eq , PartialEq , Serialize , Deserialize ) ]
19
17
pub enum Theme {
18
+ #[ default]
20
19
Light ,
21
20
Dark ,
22
21
}
23
22
24
23
impl Theme {
25
- pub fn switch_theme ( self ) -> Self {
24
+ pub fn toggle ( self ) -> Self {
26
25
match self {
27
26
Theme :: Dark => Theme :: Light ,
28
27
Theme :: Light => Theme :: Dark ,
29
28
}
30
29
}
31
30
}
32
31
33
- #[ derive(
34
- Copy , Clone , Eq , PartialEq , Debug , Default , Serialize , Deserialize ,
35
- ) ]
36
- #[ serde( rename_all = "snake_case" ) ]
32
+ #[ derive( Clone , Copy , Debug , Default , Eq , PartialEq , Serialize , Deserialize ) ]
33
+ pub enum ScalingMode {
34
+ #[ default]
35
+ Fixed ,
36
+ FitStretch ,
37
+ FitMin ,
38
+ }
39
+
40
+ #[ derive( Clone , Copy , Debug , Default , Eq , PartialEq , Serialize , Deserialize ) ]
37
41
pub enum Antialias {
38
42
#[ default]
39
43
Auto ,
40
44
Always ,
41
45
Never ,
42
46
}
43
47
44
- #[ derive( Debug , Default , PartialEq , Eq , Clone , Serialize , Deserialize ) ]
45
- pub struct CacheImageSection {
46
- pub fit_stretches : bool ,
47
- pub antialiasing : Antialias ,
48
- }
49
-
50
- #[ derive( Debug , Default , PartialEq , Eq , Clone , Deserialize ) ]
51
- pub struct ConfigImageSection {
52
- pub antialiasing : Option < String > ,
53
- }
54
-
55
- #[ derive( Debug , PartialEq , Eq , Clone , Serialize , Deserialize ) ]
56
- pub struct CacheWindowSection {
57
- pub dark : bool ,
58
- pub win_w : u32 ,
59
- pub win_h : u32 ,
60
- pub win_x : i32 ,
61
- pub win_y : i32 ,
62
- }
63
-
64
- impl Default for CacheWindowSection {
65
- fn default ( ) -> Self {
66
- Self {
67
- dark : false ,
68
- win_w : 580 ,
69
- win_h : 558 ,
70
- win_x : 64 ,
71
- win_y : 64 ,
72
- }
73
- }
74
- }
75
-
76
- #[ derive( Debug , Clone , Deserialize ) ]
77
- pub struct ConfigWindowSection {
78
- pub start_fullscreen : Option < bool > ,
79
- pub start_maximized : Option < bool > ,
80
- pub show_bottom_bar : Option < bool > ,
48
+ #[ derive( Clone , Debug , Default , Eq , PartialEq , Serialize , Deserialize ) ]
49
+ pub struct ConfigWindow {
50
+ pub title_folders : Option < u32 > ,
51
+ pub mode : Option < WindowMode > ,
81
52
pub theme : Option < Theme > ,
82
- pub use_last_window_area : Option < bool > ,
83
- pub win_w : Option < u32 > ,
84
- pub win_h : Option < u32 > ,
85
- pub win_x : Option < i32 > ,
86
- pub win_y : Option < i32 > ,
87
- }
88
-
89
- #[ derive( Deserialize ) ]
90
- struct IncompleteCache {
91
- pub window : Option < CacheWindowSection > ,
92
- pub image : Option < CacheImageSection > ,
93
53
}
94
54
95
- #[ derive( Debug , Default , PartialEq , Eq , Clone , Serialize ) ]
96
- pub struct Cache {
97
- pub window : CacheWindowSection ,
98
- pub image : CacheImageSection ,
55
+ #[ derive( Clone , Debug , Default , Eq , PartialEq , Serialize , Deserialize ) ]
56
+ pub struct ConfigImage {
57
+ pub scaling : Option < ScalingMode > ,
58
+ pub antialiasing : Option < Antialias > ,
99
59
}
100
60
101
- impl From < IncompleteCache > for Cache {
102
- fn from ( cache : IncompleteCache ) -> Self {
103
- Self {
104
- window : cache. window . unwrap_or_default ( ) ,
105
- image : cache. image . unwrap_or_default ( ) ,
106
- }
107
- }
108
- }
109
-
110
- impl Cache {
111
- pub fn theme ( & self ) -> Theme {
112
- if self . window . dark {
113
- Theme :: Dark
114
- } else {
115
- Theme :: Light
116
- }
117
- }
118
-
119
- pub fn set_theme ( & mut self , theme : Theme ) {
120
- self . window . dark = theme == Theme :: Dark ;
121
- }
122
-
123
- pub fn load ( ) -> Result < Cache , String > {
124
- let file_path = cache_file ( ) ;
125
- let cfg_str = fs:: read_to_string ( & file_path) . map_err ( |_| {
126
- format ! ( "Could not read cache from {file_path:?}" )
127
- } ) ?;
128
- let result: IncompleteCache =
129
- toml:: from_str ( & cfg_str) . map_err ( |e| format ! ( "{e}" ) ) ?;
130
- //println!("Read cache from file:\n{:#?}", result);
131
- Ok ( result. into ( ) )
132
- }
133
-
134
- pub fn save ( & self ) -> Result < ( ) , String > {
135
- let file_path = cache_file ( ) ;
136
- let string = toml:: to_string ( self ) . map_err ( |e| format ! ( "{e}" ) ) ?;
137
- fs:: write ( & file_path, string) . map_err ( |_| {
138
- format ! ( "Could not write to cache file {:?}" , file_path)
139
- } ) ?;
140
- Ok ( ( ) )
141
- }
142
- }
143
-
144
- #[ derive( Debug , Default , PartialEq , Eq , Clone , Deserialize ) ]
61
+ #[ derive( Clone , Debug , Default , Eq , PartialEq , Serialize , Deserialize ) ]
145
62
pub struct EnvVar {
146
63
pub name : String ,
147
64
pub value : String ,
148
65
}
149
66
150
- #[ derive( Debug , Default , PartialEq , Eq , Clone , Deserialize ) ]
67
+ #[ derive( Clone , Debug , Default , Eq , PartialEq , Serialize , Deserialize ) ]
151
68
pub struct Command {
152
69
pub input : Vec < String > ,
153
70
pub program : String ,
154
71
pub args : Option < Vec < String > > ,
155
72
pub envs : Option < Vec < EnvVar > > ,
156
73
}
157
74
158
- #[ derive( Debug , Default , PartialEq , Eq , Clone , Deserialize ) ]
159
- pub struct TitleSection {
160
- pub displayed_folders : Option < u32 > ,
161
- pub show_program_name : Option < bool > ,
162
- }
163
-
164
- impl TitleSection {
165
- pub fn format_file_path < ' a > ( & self , file_path : & ' a Path ) -> Cow < ' a , str > {
166
- match self . displayed_folders {
167
- Some ( 0 ) | None => file_path. file_name ( ) . unwrap ( ) . to_string_lossy ( ) ,
168
- Some ( n) => {
169
- let mut component_count = 0 ;
170
- // On Windows the root can be the second component, when a
171
- // `Prefix` is the first.
172
- let mut root_index = 0 ;
173
- for ( idx, c) in file_path. components ( ) . enumerate ( ) {
174
- component_count += 1 ;
175
- if c == std:: path:: Component :: RootDir {
176
- root_index = idx as u32 ;
177
- }
178
- }
179
- let path = if ( component_count - root_index) <= ( 1 + n) {
180
- file_path
181
- . to_string_lossy ( )
182
- . trim_start_matches ( "\\ \\ ?\\ " )
183
- . to_owned ( )
184
- . into ( )
185
- } else {
186
- let ancestor = file_path
187
- . ancestors ( )
188
- . take ( 2 + n as usize )
189
- . last ( )
190
- . unwrap ( ) ;
191
- file_path. strip_prefix ( ancestor) . unwrap ( ) . to_string_lossy ( )
192
- } ;
193
- path
194
- }
195
- }
196
- }
197
- }
198
-
199
- #[ derive( Debug , Default , Clone , Deserialize ) ]
75
+ #[ derive( Debug , Default , Clone , Deserialize , Serialize ) ]
200
76
pub struct Configuration {
77
+ pub window : Option < ConfigWindow > ,
78
+ pub image : Option < ConfigImage > ,
201
79
pub bindings : Option < BTreeMap < String , Vec < String > > > ,
202
80
pub commands : Option < Vec < Command > > ,
203
- pub title : Option < TitleSection > ,
204
- pub image : Option < ConfigImageSection > ,
205
- pub window : Option < ConfigWindowSection > ,
206
81
}
207
82
208
83
impl Configuration {
209
- pub fn load ( ) -> Result < Configuration , String > {
84
+ pub fn load ( ) -> Result < Self , String > {
210
85
let file_path = config_file ( ) ;
211
86
let cfg_str = fs:: read_to_string ( & file_path)
212
87
. map_err ( |_| format ! ( "Could not read config from {file_path:?}" ) ) ?;
@@ -215,6 +90,64 @@ impl Configuration {
215
90
//println!("Read config from file:\n{:#?}", result);
216
91
Ok ( result)
217
92
}
93
+
94
+ pub fn save ( & self ) -> Result < ( ) , String > {
95
+ let file_path = config_file ( ) ;
96
+ let cfg_str = toml:: to_string ( self ) . map_err ( |e| format ! ( "{e}" ) ) ?;
97
+ fs:: write ( & file_path, cfg_str) . map_err ( |_| {
98
+ format ! ( "Could not write to config file {file_path:?}" )
99
+ } ) ?;
100
+ Ok ( ( ) )
101
+ }
102
+
103
+ pub fn scaling ( & self ) -> ScalingMode {
104
+ self . image . as_ref ( ) . and_then ( |i| i. scaling ) . unwrap_or_default ( )
105
+ }
106
+
107
+ pub fn set_scaling ( & mut self , scaling : ScalingMode ) {
108
+ if self . image . is_none ( ) {
109
+ self . image = Some ( ConfigImage :: default ( ) ) ;
110
+ }
111
+ if let Some ( image) = & mut self . image {
112
+ image. scaling = Some ( scaling) ;
113
+ }
114
+ }
115
+
116
+ pub fn antialiasing ( & self ) -> Antialias {
117
+ self . image . as_ref ( ) . and_then ( |i| i. antialiasing ) . unwrap_or_default ( )
118
+ }
119
+
120
+ pub fn set_antialiasing ( & mut self , antialias : Antialias ) {
121
+ if self . image . is_none ( ) {
122
+ self . image = Some ( ConfigImage :: default ( ) ) ;
123
+ }
124
+ if let Some ( image) = & mut self . image {
125
+ image. antialiasing = Some ( antialias) ;
126
+ }
127
+ }
128
+
129
+ pub fn title_folders ( & self ) -> u32 {
130
+ self . window . as_ref ( ) . and_then ( |w| w. title_folders ) . unwrap_or_default ( )
131
+ }
132
+
133
+ pub fn window_mode ( & self ) -> WindowMode {
134
+ self . window . as_ref ( ) . and_then ( |w| w. mode ) . unwrap_or_default ( )
135
+ }
136
+
137
+ pub fn theme ( & self ) -> Theme {
138
+ self . window . as_ref ( ) . and_then ( |w| w. theme ) . unwrap_or_default ( )
139
+ }
140
+
141
+ pub fn set_theme ( & mut self , theme : Theme ) {
142
+ self . window_config ( ) . theme = Some ( theme) ;
143
+ }
144
+
145
+ fn window_config ( & mut self ) -> & mut ConfigWindow {
146
+ if self . window . is_none ( ) {
147
+ self . window = Some ( ConfigWindow :: default ( ) ) ;
148
+ }
149
+ self . window . as_mut ( ) . unwrap ( )
150
+ }
218
151
}
219
152
220
153
fn project_dir_fallback ( ) -> PathBuf {
@@ -231,18 +164,7 @@ fn config_file() -> PathBuf {
231
164
if !config_dir. exists ( ) {
232
165
std:: fs:: create_dir_all ( & config_dir) . unwrap ( ) ;
233
166
}
234
- config_dir. join ( "cfg.toml" )
235
- }
236
-
237
- fn cache_file ( ) -> PathBuf {
238
- let cache_dir = match ProjectDirs :: from ( "" , "" , APPLICATION ) {
239
- Some ( proj) => proj. cache_dir ( ) . to_owned ( ) ,
240
- None => project_dir_fallback ( ) ,
241
- } ;
242
- if !cache_dir. exists ( ) {
243
- std:: fs:: create_dir_all ( & cache_dir) . unwrap ( ) ;
244
- }
245
- cache_dir. join ( "cache.toml" )
167
+ config_dir. join ( "config.toml" )
246
168
}
247
169
248
170
pub fn data_dir ( ) -> PathBuf {
0 commit comments