Skip to main content

termden_core/
config.rs

1use std::fs;
2use std::path::PathBuf;
3
4use serde::{Deserialize, Serialize};
5
6/// Which built-in palette to use.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "kebab-case")]
9pub enum ThemeId {
10    CatppuccinMocha,
11    Everforest,
12}
13
14impl Default for ThemeId {
15    fn default() -> Self {
16        Self::CatppuccinMocha
17    }
18}
19
20impl ThemeId {
21    pub const ALL: [ThemeId; 2] = [ThemeId::CatppuccinMocha, ThemeId::Everforest];
22
23    pub fn label(self) -> &'static str {
24        match self {
25            ThemeId::CatppuccinMocha => "Catppuccin Mocha",
26            ThemeId::Everforest => "Everforest",
27        }
28    }
29
30    pub fn next(self) -> Self {
31        match self {
32            ThemeId::CatppuccinMocha => ThemeId::Everforest,
33            ThemeId::Everforest => ThemeId::CatppuccinMocha,
34        }
35    }
36}
37
38/// User configuration, read from `$XDG_CONFIG_HOME/termden/config.toml`.
39///
40/// Every field has a default so the file can stay tiny.
41#[derive(Debug, Clone, Serialize, Deserialize)]
42#[serde(default)]
43pub struct Config {
44    pub theme: ThemeId,
45    pub ui_font: String,
46    pub mono_font: String,
47    /// Terminal text size in px (ctrl+shift +/- adjusts and saves it).
48    pub font_size: f32,
49    pub panel_width: f32,
50    pub gap: f32,
51    pub corner_radius: f32,
52}
53
54impl Default for Config {
55    fn default() -> Self {
56        Self {
57            theme: ThemeId::CatppuccinMocha,
58            ui_font: "Noto Sans".to_string(),
59            mono_font: "JetBrainsMono Nerd Font".to_string(),
60            font_size: 16.0,
61            panel_width: 268.0,
62            gap: 12.0,
63            corner_radius: 12.0,
64        }
65    }
66}
67
68impl Config {
69    pub fn path() -> PathBuf {
70        config_dir().join("termden").join("config.toml")
71    }
72
73    pub fn load() -> Self {
74        let path = Self::path();
75        let Ok(text) = fs::read_to_string(&path) else {
76            return Self::default();
77        };
78
79        match toml::from_str(&text) {
80            Ok(config) => config,
81            Err(error) => {
82                eprintln!("termden: could not parse {}: {error}", path.display());
83                Self::default()
84            }
85        }
86    }
87
88    pub fn save(&self) -> std::io::Result<()> {
89        let path = Self::path();
90        if let Some(parent) = path.parent() {
91            fs::create_dir_all(parent)?;
92        }
93        let text = toml::to_string_pretty(self).map_err(std::io::Error::other)?;
94        fs::write(path, text)
95    }
96}
97
98fn config_dir() -> PathBuf {
99    crate::state::xdg_dir("XDG_CONFIG_HOME", ".config")
100}