Skip to main content

tca_types/
config.rs

1//! Read and write user TCA preferences.
2
3use anyhow::Result;
4use core::fmt;
5use etcetera::{choose_app_strategy, AppStrategy, AppStrategyArgs};
6use std::fs;
7use std::path::PathBuf;
8
9use serde::{Deserialize, Serialize};
10
11/// Configuration for TCA user preferences.
12#[derive(Default, Debug, Serialize, Deserialize)]
13pub struct TcaSection {
14    /// The general default theme. Used if mode can't be detected or other options
15    /// aren't defined.
16    pub default_theme: Option<String>,
17    /// Default dark mode theme.
18    pub default_dark_theme: Option<String>,
19    /// Default light mode theme.
20    pub default_light_theme: Option<String>,
21}
22
23/// TCA configuration file.
24///
25/// A TOML file containing TCA user preferences
26/// Stored at `$XDG_CONFIG_HOME/tca/tca.toml`.
27#[derive(Default, Debug, Serialize, Deserialize)]
28pub struct TcaConfig {
29    #[serde(default)]
30    /// TCA theme preferences.
31    pub tca: TcaSection,
32}
33
34impl TcaConfig {
35    /// Returns the path to the TCA config file (`tca.toml` in the app config dir).
36    pub fn path() -> Result<PathBuf> {
37        let strategy = choose_app_strategy(AppStrategyArgs {
38            top_level_domain: "org".into(),
39            author: "TCA".into(),
40            app_name: "tca".into(),
41        })?;
42        Ok(strategy.config_dir().join("tca.toml"))
43    }
44
45    /// Load the user's configuration preferences.
46    ///
47    /// Returns [`Default`] if the config file doesn't exist or cannot be parsed.
48    pub fn load() -> Self {
49        let Ok(path) = TcaConfig::path() else {
50            return Self::default();
51        };
52        let Ok(content) = fs::read_to_string(path) else {
53            return Self::default();
54        };
55        toml::from_str::<TcaConfig>(&content).unwrap_or_default()
56    }
57
58    /// Save the user's configuration preferences.
59    pub fn store(&self) -> Result<()> {
60        let path = TcaConfig::path()?;
61        if let Some(parent) = path.parent() {
62            fs::create_dir_all(parent)?;
63        }
64        let content = toml::to_string(self)?;
65        fs::write(&path, content)?;
66        Ok(())
67    }
68}
69
70impl fmt::Display for TcaConfig {
71    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72        write!(
73            f,
74            "default: {:?}\ndefault_dark: {:?}\ndefault_light: {:?}",
75            self.tca.default_theme.as_deref().unwrap_or("None"),
76            self.tca.default_dark_theme.as_deref().unwrap_or("None"),
77            self.tca.default_light_theme.as_deref().unwrap_or("None"),
78        )
79    }
80}