1use crate::tui::Theme;
2use crate::utils::expand_path;
3use serde::Deserialize;
4use serde::Serialize;
5use std::fs;
6use std::io::Write;
7use std::path::{Path, PathBuf};
8
9#[derive(Deserialize, Serialize)]
10pub struct Config {
11 pub tries_path: Option<String>,
12 pub theme: Option<String>,
13 pub editor: Option<String>,
14 pub apply_date_prefix: Option<bool>,
15 pub transparent_background: Option<bool>,
16}
17
18pub fn get_file_config_toml_name() -> String {
19 std::env::var("TRY_CONFIG").unwrap_or("config.toml".to_string())
20}
21
22pub fn get_config_dir() -> PathBuf {
23 std::env::var_os("TRY_CONFIG_DIR")
24 .map(PathBuf::from)
25 .unwrap_or_else(|| get_base_config_dir().join("try-rs"))
26}
27
28pub fn get_base_config_dir() -> PathBuf {
29 dirs::config_dir().unwrap_or_else(|| {
30 dirs::home_dir()
31 .expect("Could not find home directory")
32 .join(".config")
33 })
34}
35
36fn config_candidates() -> Vec<PathBuf> {
38 let config_name = get_file_config_toml_name();
39 let mut candidates = Vec::new();
40
41 if let Some(env_dir) = std::env::var_os("TRY_CONFIG_DIR") {
42 candidates.push(PathBuf::from(env_dir).join(&config_name));
43 }
44 if let Some(dir) = dirs::config_dir() {
45 candidates.push(dir.join("try-rs").join(&config_name));
46 }
47 if let Some(home) = dirs::home_dir() {
48 candidates.push(home.join(".config").join("try-rs").join(&config_name));
49 }
50
51 candidates
52}
53
54fn find_config_path() -> Option<PathBuf> {
56 config_candidates().into_iter().find(|p| p.exists())
57}
58
59pub fn load_file_config_toml_if_exists() -> Option<Config> {
60 let path = find_config_path()?;
61 let contents = fs::read_to_string(&path).ok()?;
62 toml::from_str::<Config>(&contents).ok()
63}
64
65pub struct AppConfig {
66 pub tries_dir: PathBuf,
67 pub theme: Theme,
68 pub editor_cmd: Option<String>,
69 pub config_path: Option<PathBuf>,
70 pub apply_date_prefix: Option<bool>,
71 pub transparent_background: Option<bool>,
72}
73
74pub fn load_configuration() -> AppConfig {
75 let default_path = dirs::home_dir()
76 .expect("Folder not found")
77 .join("work")
78 .join("tries");
79
80 let mut theme = Theme::default();
81 let try_path = std::env::var_os("TRY_PATH");
82 let try_path_specified = try_path.is_some();
83 let mut final_path = try_path.map(PathBuf::from).unwrap_or(default_path);
84 let mut editor_cmd = std::env::var("VISUAL")
85 .ok()
86 .or_else(|| std::env::var("EDITOR").ok());
87 let mut apply_date_prefix = None;
88 let mut transparent_background = None;
89
90 let loaded_config_path = find_config_path();
91
92 if let Some(config) = load_file_config_toml_if_exists() {
93 if let Some(path_str) = config.tries_path
94 && !try_path_specified
95 {
96 final_path = expand_path(&path_str);
97 }
98 if let Some(editor) = config.editor {
99 editor_cmd = Some(editor);
100 }
101 if let Some(theme_name) = config.theme {
102 if let Some(found_theme) = Theme::all().into_iter().find(|t| t.name == theme_name) {
103 theme = found_theme;
104 }
105 }
106 apply_date_prefix = config.apply_date_prefix;
107 transparent_background = config.transparent_background;
108 }
109
110 AppConfig {
111 tries_dir: final_path,
112 theme,
113 editor_cmd,
114 config_path: loaded_config_path,
115 apply_date_prefix,
116 transparent_background,
117 }
118}
119
120pub fn save_config(
121 path: &Path,
122 theme: &Theme,
123 tries_path: &Path,
124 editor: &Option<String>,
125 apply_date_prefix: Option<bool>,
126 transparent_background: Option<bool>,
127) -> std::io::Result<()> {
128 let config = Config {
129 tries_path: Some(tries_path.to_string_lossy().to_string()),
130 theme: Some(theme.name.clone()),
131 editor: editor.clone(),
132 apply_date_prefix,
133 transparent_background,
134 };
135
136 let toml_string =
137 toml::to_string(&config).map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
138
139 if let Some(parent) = path.parent() {
140 if !parent.exists() {
141 fs::create_dir_all(parent)?;
142 }
143 }
144
145 let mut file = fs::File::create(path)?;
146 file.write_all(toml_string.as_bytes())?;
147 Ok(())
148}