use serde::{Deserialize, Serialize}; use anyhow::Result; use std::fs; use std::path::PathBuf; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Config { pub server_url: String, pub timeout_sec: u64, #[serde(default = "default_theme")] pub theme: Theme, #[serde(default)] pub update_api: Option, } #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Theme { #[serde(default = "default_selected_bg")] pub selected_bg: String, } fn default_selected_bg() -> String { "blue".to_string() } fn default_theme() -> Theme { Theme { selected_bg: default_selected_bg(), } } pub fn config_path() -> PathBuf { // Respect XDG_CONFIG_HOME; fall back to ~/.config on all platforms. let base = std::env::var("XDG_CONFIG_HOME") .map(PathBuf::from) .unwrap_or_else(|_| { dirs::home_dir() .unwrap_or_else(|| PathBuf::from(".")) .join(".config") }); base.join(env!("CARGO_PKG_NAME")).join("config.toml") } impl Config { /// Returns true when a config file already exists. pub fn exists() -> bool { config_path().exists() } /// Load config from disk. Panics-safe: returns error if file is missing or malformed. pub fn load() -> Result { let path = config_path(); let content = fs::read_to_string(&path)?; Ok(toml::from_str(&content)?) } /// Create and persist a new config with the given server URL. pub fn create_with_url(server_url: &str) -> Result { let path = config_path(); let config = Config { server_url: server_url.to_string(), timeout_sec: 10, theme: default_theme(), update_api: None, }; fs::create_dir_all(path.parent().unwrap())?; fs::write(&path, toml::to_string_pretty(&config)?)?; Ok(config) } }