1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5#[serde(default)]
6pub struct Config {
7 pub ultra_compact: bool,
8 pub tee_on_error: bool,
9 pub checkpoint_interval: u32,
10 pub excluded_commands: Vec<String>,
11 pub custom_aliases: Vec<AliasEntry>,
12 pub slow_command_threshold_ms: u64,
15 #[serde(default = "default_theme")]
16 pub theme: String,
17 #[serde(default)]
18 pub cloud: CloudConfig,
19}
20
21fn default_theme() -> String {
22 "default".to_string()
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, Default)]
26#[serde(default)]
27pub struct CloudConfig {
28 pub contribute_enabled: bool,
29 pub last_contribute: Option<String>,
30 pub last_sync: Option<String>,
31 pub last_model_pull: Option<String>,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct AliasEntry {
36 pub command: String,
37 pub alias: String,
38}
39
40impl Default for Config {
41 fn default() -> Self {
42 Self {
43 ultra_compact: false,
44 tee_on_error: false,
45 checkpoint_interval: 15,
46 excluded_commands: Vec::new(),
47 custom_aliases: Vec::new(),
48 slow_command_threshold_ms: 5000,
49 theme: default_theme(),
50 cloud: CloudConfig::default(),
51 }
52 }
53}
54
55impl Config {
56 pub fn path() -> Option<PathBuf> {
57 dirs::home_dir().map(|h| h.join(".lean-ctx").join("config.toml"))
58 }
59
60 pub fn load() -> Self {
61 let path = match Self::path() {
62 Some(p) => p,
63 None => return Self::default(),
64 };
65 match std::fs::read_to_string(&path) {
66 Ok(content) => toml::from_str(&content).unwrap_or_default(),
67 Err(_) => Self::default(),
68 }
69 }
70
71 pub fn save(&self) -> Result<(), String> {
72 let path = Self::path().ok_or("cannot determine home directory")?;
73 if let Some(parent) = path.parent() {
74 std::fs::create_dir_all(parent).map_err(|e| e.to_string())?;
75 }
76 let content = toml::to_string_pretty(self).map_err(|e| e.to_string())?;
77 std::fs::write(&path, content).map_err(|e| e.to_string())
78 }
79
80 pub fn show(&self) -> String {
81 let path = Self::path()
82 .map(|p| p.to_string_lossy().to_string())
83 .unwrap_or_else(|| "~/.lean-ctx/config.toml".to_string());
84 let content = toml::to_string_pretty(self).unwrap_or_default();
85 format!("Config: {path}\n\n{content}")
86 }
87}