modcli/output/
themes.rs

1use crossterm::style::{Color, SetForegroundColor, SetBackgroundColor, ResetColor};
2use std::collections::HashMap;
3use std::io::{stdout, Write};
4use std::sync::OnceLock;
5use crate::output::colors::*;
6
7#[derive(Clone)]
8pub struct Theme {
9    pub name: String,
10    pub fg: Color,
11    pub bg: Color,
12    pub log_styles: HashMap<&'static str, Color>,
13}
14
15impl Theme {
16    pub fn apply(&self) {
17        let _ = write!(stdout(), "{}{}", SetForegroundColor(self.fg), SetBackgroundColor(self.bg));
18        let _ = stdout().flush();
19    }
20
21    pub fn reset() {
22        let _ = write!(stdout(), "{}", ResetColor);
23        let _ = stdout().flush();
24    }
25
26    pub fn get_log_color(&self, key: &str) -> Color {
27        self.log_styles.get(key).copied().unwrap_or(self.fg)
28    }
29}
30
31
32static THEME: OnceLock<Theme> = OnceLock::new();
33
34fn log_defaults(base: Color) -> HashMap<&'static str, Color> {
35    let mut map = HashMap::new();
36    map.insert("error", COLOR_ERROR);
37    map.insert("warn", COLOR_WARNING);
38    map.insert("success", COLOR_SUCCESS);
39    map.insert("debug", COLOR_DEBUG);
40    map.insert("info", COLOR_INFO);
41    map.insert("trace", COLOR_TRACE);
42    map.insert("default", base);
43    map
44}
45
46pub fn apply_theme(name: &str) {
47    let theme = match name.to_lowercase().as_str() {
48        "monochrome" => Theme {
49            name: "monochrome".into(),
50            fg: GREY,
51            bg: BLACK,
52            log_styles: log_defaults(GREY),
53        },
54        "inverted" => Theme {
55            name: "inverted".into(),
56            fg: BLACK,
57            bg: WHITE,
58            log_styles: log_defaults(BLACK),
59        },
60        "blue" => Theme {
61            name: "blue".into(),
62            fg: WHITE,
63            bg: BLUE,
64            log_styles: log_defaults(WHITE),
65        },
66        "green" => Theme {
67            name: "green".into(),
68            fg: BLACK,
69            bg: GREEN,
70            log_styles: log_defaults(BLACK),
71        },
72        _ => Theme {
73            name: "default".into(),
74            fg: WHITE,
75            bg: BLACK,
76            log_styles: log_defaults(WHITE),
77        },
78    };
79
80    let _ = THEME.set(theme.clone()); // only sets once
81    theme.apply();
82}
83
84pub fn current_theme() -> Theme {
85    THEME
86        .get()
87        .cloned()
88        .unwrap_or_else(|| Theme {
89            name: "default".into(),
90            fg: WHITE,
91            bg: BLACK,
92            log_styles: log_defaults(WHITE),
93        })
94}