Skip to main content

tca_types/
config.rs

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