1use serde::{Deserialize, Serialize};
6use std::path::{Path, PathBuf};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct CliConfig {
11 pub log_level: String,
13 pub default_port: u16,
15 pub cache: CacheConfig,
17 pub server: ServerConfig,
19 pub compiler: CompilerConfig,
21}
22
23impl Default for CliConfig {
24 fn default() -> Self {
25 Self {
26 log_level: "info".to_string(),
27 default_port: 3000,
28 cache: CacheConfig::default(),
29 server: ServerConfig::default(),
30 compiler: CompilerConfig::default(),
31 }
32 }
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct CacheConfig {
38 pub enabled: bool,
40 pub directory: PathBuf,
42 pub max_size_mb: usize,
44 pub ttl_hours: u64,
46}
47
48impl Default for CacheConfig {
49 fn default() -> Self {
50 Self {
51 enabled: true,
52 directory: get_cache_dir(),
53 max_size_mb: 100,
54 ttl_hours: 24,
55 }
56 }
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct ServerConfig {
62 pub host: String,
64 pub port: u16,
66 pub timeout_seconds: u64,
68 pub max_connections: usize,
70 pub cors_enabled: bool,
72}
73
74impl Default for ServerConfig {
75 fn default() -> Self {
76 Self {
77 host: "127.0.0.1".to_string(),
78 port: 3000,
79 timeout_seconds: 30,
80 max_connections: 100,
81 cors_enabled: true,
82 }
83 }
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct CompilerConfig {
89 pub optimization_level: u8,
91 pub include_debug_info: bool,
93 pub generate_source_maps: bool,
95 pub target_arch: String,
97}
98
99impl Default for CompilerConfig {
100 fn default() -> Self {
101 Self {
102 optimization_level: 0,
103 include_debug_info: true,
104 generate_source_maps: true,
105 target_arch: std::env::consts::ARCH.to_string(),
106 }
107 }
108}
109
110pub struct ConfigManager {
112 config: CliConfig,
113 config_path: PathBuf,
114}
115
116impl ConfigManager {
117 pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
119 let config_dir = get_config_dir();
120 std::fs::create_dir_all(&config_dir)?;
121
122 let config_path = config_dir.join("cli.toml");
123 let config = if config_path.exists() {
124 Self::load_config(&config_path)?
125 } else {
126 CliConfig::default()
127 };
128
129 Ok(Self {
130 config,
131 config_path,
132 })
133 }
134
135 fn load_config(path: &Path) -> Result<CliConfig, Box<dyn std::error::Error>> {
137 let content = std::fs::read_to_string(path)?;
138 let config: CliConfig = toml::from_str(&content)?;
139 Ok(config)
140 }
141
142 pub fn save_config(&self) -> Result<(), Box<dyn std::error::Error>> {
144 let content = toml::to_string_pretty(&self.config)?;
145 std::fs::write(&self.config_path, content)?;
146 Ok(())
147 }
148
149 pub fn get_config(&self) -> &CliConfig {
151 &self.config
152 }
153
154 pub fn update_config<F>(&mut self, updater: F)
156 where
157 F: FnOnce(&mut CliConfig),
158 {
159 updater(&mut self.config);
160 }
161
162 pub fn reset_config(&mut self) -> Result<(), Box<dyn std::error::Error>> {
164 self.config = CliConfig::default();
165 self.save_config()
166 }
167}
168
169fn get_config_dir() -> PathBuf {
171 dirs::config_dir()
172 .unwrap_or_else(|| PathBuf::from("."))
173 .join("kotoba")
174}
175
176fn get_cache_dir() -> PathBuf {
178 dirs::cache_dir()
179 .unwrap_or_else(|| PathBuf::from("."))
180 .join("kotoba")
181}