1use anyhow::Result;
4use serde::{Deserialize, Serialize};
5use std::fs;
6use std::path::PathBuf;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Config {
11 pub display: DisplayConfig,
12 pub general: GeneralConfig,
13 pub search: SearchConfig,
14 pub ui: UiConfig,
15}
16
17#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
19#[serde(rename_all = "lowercase")]
20pub enum AliasExpansion {
21 #[default]
22 Name,
23 Script,
24}
25
26#[derive(Debug, Clone, Default, Serialize, Deserialize)]
28#[serde(default)]
29pub struct GeneralConfig {
30 pub shell_files: Vec<String>,
32 pub alias_expansion: AliasExpansion,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct SearchConfig {
38 pub case_matching: CaseMatching,
40 pub normalize: bool,
42 pub enable_regex: bool,
44 pub substring_matching: bool,
46}
47
48#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
50#[serde(rename_all = "lowercase")]
51pub enum CaseMatching {
52 Ignore,
54 Smart,
56 Respect,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct UiConfig {
63 pub theme: String,
65 pub keybind_mode: String,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct DisplayConfig {
72 pub show_type_badges: bool,
74 pub syntax_highlighting: bool,
76 pub parse_comments: bool,
78}
79
80impl Default for Config {
81 fn default() -> Self {
82 Self {
83 display: DisplayConfig {
84 parse_comments: true,
85 show_type_badges: true,
86 syntax_highlighting: true,
87 },
88 general: GeneralConfig::default(),
89 search: SearchConfig {
90 case_matching: CaseMatching::Smart,
91 enable_regex: true,
92 normalize: true,
93 substring_matching: true,
94 },
95 ui: UiConfig {
96 keybind_mode: "vim".to_string(),
97 theme: "default".to_string(),
98 },
99 }
100 }
101}
102
103pub fn get_config_path() -> Result<PathBuf> {
108 let home = std::env::var("HOME")
109 .or_else(|_| std::env::var("USERPROFILE"))
110 .map_err(|_| anyhow::anyhow!("HOME or USERPROFILE environment variable not set"))?;
111
112 let config_dir = PathBuf::from(home).join(".config").join("alf");
113 Ok(config_dir.join("config.toml"))
114}
115
116pub fn load_config() -> Result<Config> {
118 let path = get_config_path()?;
119 let content = fs::read_to_string(&path)?;
120 let config: Config = toml::from_str(&content)?;
121 Ok(config)
122}
123
124pub fn save_config(config: &Config) -> Result<()> {
126 let path = get_config_path()?;
127
128 if let Some(parent) = path.parent() {
130 fs::create_dir_all(parent)?;
131 }
132
133 let content = toml::to_string_pretty(config)?;
134 fs::write(&path, content)?;
135 Ok(())
136}
137
138pub fn is_first_run() -> Result<bool> {
140 let path = get_config_path()?;
141 Ok(!path.exists())
142}
143
144#[cfg(test)]
145mod config_tests;