11use anyhow:: { Context , Result } ;
22use serde:: Deserialize ;
3- use std:: { fs, path:: PathBuf } ;
3+ use std:: { env , fs, path:: PathBuf } ;
44
55/// Represents global application settings loaded from cmdy.toml.
66#[ derive( Debug , Deserialize ) ]
@@ -22,6 +22,17 @@ impl Default for AppConfig {
2222 }
2323}
2424
25+ fn expand_tilde ( path : & PathBuf ) -> PathBuf {
26+ if let Some ( path_str) = path. to_str ( ) {
27+ if path_str. starts_with ( "~/" ) {
28+ if let Ok ( home) = env:: var ( "HOME" ) {
29+ return PathBuf :: from ( home) . join ( & path_str[ 2 ..] ) ;
30+ }
31+ }
32+ }
33+ path. clone ( )
34+ }
35+
2536/// Loads the application configuration from a TOML file.
2637/// Checks ~/.config/cmdy/cmdy.toml (macOS) or $XDG_CONFIG_HOME/cmdy/cmdy.toml, falling back to defaults.
2738pub fn load_app_config ( ) -> Result < AppConfig > {
@@ -42,7 +53,10 @@ pub fn load_app_config() -> Result<AppConfig> {
4253 let content = fs:: read_to_string ( & config_path)
4354 . with_context ( || format ! ( "Failed to read config file: {}" , config_path. display( ) ) ) ?;
4455 match toml:: from_str :: < AppConfig > ( & content) {
45- Ok ( cfg) => return Ok ( cfg) ,
56+ Ok ( mut cfg) => {
57+ cfg. directories = cfg. directories . iter ( ) . map ( expand_tilde) . collect ( ) ;
58+ return Ok ( cfg) ;
59+ }
4660 Err ( e) => eprintln ! (
4761 "Warning: Failed to parse config file {}: {}. Using defaults." ,
4862 config_path. display( ) ,
@@ -235,4 +249,38 @@ directories = ["one", "two"]
235249 assert ! ( result. is_err( ) , "Expected I/O error, got {:?}" , result) ;
236250 Ok ( ( ) )
237251 }
252+
253+ #[ test]
254+ /// load_app_config expands ~ in directory paths
255+ fn test_load_app_config_tilde_expansion ( ) -> Result < ( ) > {
256+ let _guard = ENV_LOCK . lock ( ) . unwrap ( ) ;
257+ let tmp = tempdir ( ) ?;
258+ unsafe {
259+ env:: set_var ( "HOME" , tmp. path ( ) ) ;
260+ }
261+ let ( _config_dir, config_file) = if cfg ! ( target_os = "macos" ) {
262+ let base = tmp. path ( ) . join ( ".config" ) . join ( "cmdy" ) ;
263+ fs:: create_dir_all ( & base) ?;
264+ let file = base. join ( "cmdy.toml" ) ;
265+ ( base, file)
266+ } else {
267+ unsafe {
268+ env:: set_var ( "XDG_CONFIG_HOME" , tmp. path ( ) ) ;
269+ }
270+ let base = tmp. path ( ) . join ( "cmdy" ) ;
271+ fs:: create_dir_all ( & base) ?;
272+ let file = base. join ( "cmdy.toml" ) ;
273+ ( base, file)
274+ } ;
275+ let content = r#"
276+ filter_command = "fzf"
277+ directories = ["~/test/path", "/absolute/path"]
278+ "# ;
279+ fs:: write ( & config_file, content) ?;
280+ let cfg = load_app_config ( ) ?;
281+ assert_eq ! ( cfg. directories. len( ) , 2 ) ;
282+ assert_eq ! ( cfg. directories[ 0 ] , tmp. path( ) . join( "test/path" ) ) ;
283+ assert_eq ! ( cfg. directories[ 1 ] , PathBuf :: from( "/absolute/path" ) ) ;
284+ Ok ( ( ) )
285+ }
238286}
0 commit comments