use serde::{Deserialize, Serialize}; use std::path::PathBuf; use super::theme::Theme; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Config { #[serde(default = "default_auto_hide_toolbar")] pub auto_hide_toolbar: bool, #[serde(default = "default_hide_tab_bar")] pub hide_tab_bar: bool, #[serde(default = "default_show_line_numbers")] pub show_line_numbers: bool, #[serde(default = "default_word_wrap")] pub word_wrap: bool, #[serde(default = "Theme::default")] pub theme: Theme, #[serde(default = "default_line_side")] pub line_side: bool, #[serde(default = "default_font_family")] pub font_family: String, #[serde(default = "default_font_size")] pub font_size: f32, // pub vim_mode: bool, } fn default_auto_hide_toolbar() -> bool { false } fn default_hide_tab_bar() -> bool { true } fn default_show_line_numbers() -> bool { false } fn default_word_wrap() -> bool { true } fn default_line_side() -> bool { false } fn default_font_family() -> String { "Proportional".to_string() } fn default_font_size() -> f32 { 14.0 } impl Default for Config { fn default() -> Self { Self { auto_hide_toolbar: false, hide_tab_bar: true, show_line_numbers: false, word_wrap: true, theme: Theme::default(), line_side: false, font_family: "Proportional".to_string(), font_size: 14.0, // vim_mode: false, } } } impl Config { pub fn config_path() -> Option { let config_dir = if let Some(config_dir) = dirs::config_dir() { config_dir.join(format!("{}", env!("CARGO_PKG_NAME"))) } else if let Some(home_dir) = dirs::home_dir() { home_dir .join(".config") .join(format!("{}", env!("CARGO_PKG_NAME"))) } else { return None; }; Some(config_dir.join("config.toml")) } pub fn load() -> Self { let config_path = match Self::config_path() { Some(path) => path, None => return Self::default(), }; if !config_path.exists() { let default_config = Self::default(); if let Err(e) = default_config.save() { eprintln!("Failed to create default config file: {e}"); } return default_config; } match std::fs::read_to_string(&config_path) { Ok(content) => { let mut config = match toml::from_str::(&content) { Ok(config) => config, Err(e) => { eprintln!( "Failed to parse config file {}: {}", config_path.display(), e ); return Self::default(); } }; let default_config = Self::default(); config.merge_with_default(default_config); config } Err(e) => { eprintln!( "Failed to read config file {}: {}", config_path.display(), e ); Self::default() } } } fn merge_with_default(&mut self, default: Config) { if self.font_family.is_empty() { self.font_family = default.font_family; } if self.font_size <= 0.0 { self.font_size = default.font_size; } } pub fn save(&self) -> Result<(), Box> { let config_path = Self::config_path().ok_or("Cannot determine config directory")?; if let Some(parent) = config_path.parent() { std::fs::create_dir_all(parent)?; } let content = toml::to_string_pretty(self)?; std::fs::write(&config_path, content)?; Ok(()) } }