lx_cli/
config.rs

1use colored::Color;
2use serde::Deserialize;
3use std::fs;
4use std::path::PathBuf;
5
6#[derive(Debug, Deserialize, Clone, Default)]
7pub struct Config {
8    #[serde(default)]
9    pub colors: ColorConfig,
10    #[serde(default)]
11    pub icons: IconConfig,
12    #[serde(default)]
13    pub display: DisplayConfig,
14}
15
16#[derive(Debug, Deserialize, Clone)]
17pub struct ColorConfig {
18    #[serde(default = "default_directory_color")]
19    pub directory: String,
20    #[serde(default = "default_executable_color")]
21    pub executable: String,
22    #[serde(default = "default_regular_color")]
23    pub regular: String,
24}
25
26#[derive(Debug, Deserialize, Clone)]
27pub struct IconConfig {
28    #[serde(default = "default_directory_icon")]
29    pub directory: String,
30    #[serde(default = "default_executable_icon")]
31    pub executable: String,
32    #[serde(default = "default_regular_icon")]
33    pub regular: String,
34    #[serde(default)]
35    pub colors: IconColorConfig,
36}
37
38#[derive(Debug, Deserialize, Clone)]
39pub struct IconColorConfig {
40    #[serde(default = "default_directory_icon_color")]
41    pub directory: String,
42    #[serde(default = "default_executable_icon_color")]
43    pub executable: String,
44    #[serde(default = "default_regular_icon_color")]
45    pub regular: String,
46}
47
48#[derive(Debug, Deserialize, Clone)]
49pub struct DisplayConfig {
50    #[serde(default = "default_column_spacing")]
51    pub column_spacing: usize,
52    #[serde(default = "default_max_rows")]
53    pub max_rows: usize,
54    #[serde(default)]
55    pub tree: TreeConfig,
56    #[serde(default = "default_long_format_fields")]
57    pub long_format_fields: Vec<String>,
58}
59
60#[derive(Debug, Deserialize, Clone)]
61pub struct TreeConfig {
62    #[serde(default = "default_tree_style")]
63    pub style: String,
64    #[serde(default = "default_recursive_long_format")]
65    pub recursive_long_format: String,
66}
67
68impl Default for TreeConfig {
69    fn default() -> Self {
70        TreeConfig {
71            style: default_tree_style(),
72            recursive_long_format: default_recursive_long_format(),
73        }
74    }
75}
76
77impl Default for IconConfig {
78    fn default() -> Self {
79        IconConfig {
80            directory: default_directory_icon(),
81            executable: default_executable_icon(),
82            regular: default_regular_icon(),
83            colors: IconColorConfig::default(),
84        }
85    }
86}
87
88impl Default for IconColorConfig {
89    fn default() -> Self {
90        IconColorConfig {
91            directory: default_directory_icon_color(),
92            executable: default_executable_icon_color(),
93            regular: default_regular_icon_color(),
94        }
95    }
96}
97
98impl Default for ColorConfig {
99    fn default() -> Self {
100        ColorConfig {
101            directory: default_directory_color(),
102            executable: default_executable_color(),
103            regular: default_regular_color(),
104        }
105    }
106}
107
108impl Default for DisplayConfig {
109    fn default() -> Self {
110        DisplayConfig {
111            column_spacing: default_column_spacing(),
112            max_rows: default_max_rows(),
113            tree: TreeConfig::default(),
114            long_format_fields: default_long_format_fields(),
115        }
116    }
117}
118
119fn default_directory_color() -> String {
120    "blue".to_string()
121}
122
123fn default_executable_color() -> String {
124    "green".to_string()
125}
126
127fn default_regular_color() -> String {
128    "white".to_string()
129}
130
131fn default_column_spacing() -> usize {
132    2
133}
134
135fn default_max_rows() -> usize {
136    0 // 0 means no limit
137}
138
139fn default_tree_style() -> String {
140    "ascii".to_string()
141}
142
143fn default_recursive_long_format() -> String {
144    "nested".to_string()
145}
146
147fn default_long_format_fields() -> Vec<String> {
148    vec![
149        "filename".to_string(),
150        "icon".to_string(),
151        "size".to_string(),
152        "modified".to_string(),
153        "owner".to_string(),
154        "group".to_string(),
155        "nlink".to_string(),
156        "permissions".to_string(),
157    ]
158}
159
160fn default_directory_icon() -> String {
161    "".to_string()
162}
163
164fn default_executable_icon() -> String {
165    "".to_string()
166}
167
168fn default_regular_icon() -> String {
169    "".to_string()
170}
171
172fn default_directory_icon_color() -> String {
173    "blue".to_string()
174}
175
176fn default_executable_icon_color() -> String {
177    "green".to_string()
178}
179
180fn default_regular_icon_color() -> String {
181    "white".to_string()
182}
183
184impl ColorConfig {
185    pub fn get_directory_color(&self) -> Color {
186        parse_color(&self.directory)
187    }
188
189    pub fn get_executable_color(&self) -> Color {
190        parse_color(&self.executable)
191    }
192
193    pub fn get_regular_color(&self) -> Color {
194        parse_color(&self.regular)
195    }
196}
197
198impl IconColorConfig {
199    pub fn get_directory_color(&self) -> Color {
200        parse_color(&self.directory)
201    }
202
203    pub fn get_executable_color(&self) -> Color {
204        parse_color(&self.executable)
205    }
206
207    pub fn get_regular_color(&self) -> Color {
208        parse_color(&self.regular)
209    }
210}
211
212impl IconConfig {
213    pub fn get_directory_icon(&self) -> String {
214        self.directory.clone()
215    }
216
217    pub fn get_executable_icon(&self) -> String {
218        self.executable.clone()
219    }
220
221    pub fn get_regular_icon(&self) -> String {
222        self.regular.clone()
223    }
224}
225
226fn parse_color(color_str: &str) -> Color {
227    match color_str.to_lowercase().as_str() {
228        "black" => Color::Black,
229        "red" => Color::Red,
230        "green" => Color::Green,
231        "yellow" => Color::Yellow,
232        "blue" => Color::Blue,
233        "magenta" => Color::Magenta,
234        "cyan" => Color::Cyan,
235        "white" => Color::White,
236        "bright_black" => Color::BrightBlack,
237        "bright_red" => Color::BrightRed,
238        "bright_green" => Color::BrightGreen,
239        "bright_yellow" => Color::BrightYellow,
240        "bright_blue" => Color::BrightBlue,
241        "bright_magenta" => Color::BrightMagenta,
242        "bright_cyan" => Color::BrightCyan,
243        "bright_white" => Color::BrightWhite,
244        _ => Color::White, // Default fallback
245    }
246}
247
248pub fn load_config() -> Config {
249    let config_path = get_config_path();
250
251    if !config_path.exists() {
252        return Config::default();
253    }
254
255    match fs::read_to_string(&config_path) {
256        Ok(contents) => match toml::from_str(&contents) {
257            Ok(config) => config,
258            Err(e) => {
259                eprintln!("Warning: Failed to parse config file: {}", e);
260                Config::default()
261            }
262        },
263        Err(_) => Config::default(),
264    }
265}
266
267fn get_config_path() -> PathBuf {
268    let mut path = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
269    path.push(".config");
270    path.push("lx");
271    path.push("config");
272    path
273}