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("notice", COLOR_NOTICE);
43    map.insert("status", COLOR_STATUS);
44    map.insert("default", base);
45    map
46}
47
48pub fn apply_theme(name: &str) {
49    let theme = match name.to_lowercase().as_str() {
50        "monochrome" => Theme {
51            name: "monochrome".into(),
52            fg: GREY,
53            bg: BLACK,
54            log_styles: log_defaults(GREY),
55        },
56        "inverted" => Theme {
57            name: "inverted".into(),
58            fg: BLACK,
59            bg: WHITE,
60            log_styles: log_defaults(BLACK),
61        },
62        "blue" => Theme {
63            name: "blue".into(),
64            fg: WHITE,
65            bg: BLUE,
66            log_styles: log_defaults(WHITE),
67        },
68        "green" => Theme {
69            name: "green".into(),
70            fg: BLACK,
71            bg: GREEN,
72            log_styles: log_defaults(BLACK),
73        },
74        _ => Theme {
75            name: "default".into(),
76            fg: WHITE,
77            bg: BLACK,
78            log_styles: log_defaults(WHITE),
79        },
80    };
81
82    let _ = THEME.set(theme.clone()); // only sets once
83    theme.apply();
84}
85
86pub fn current_theme() -> Theme {
87    THEME
88        .get()
89        .cloned()
90        .unwrap_or_else(|| Theme {
91            name: "default".into(),
92            fg: WHITE,
93            bg: BLACK,
94            log_styles: log_defaults(WHITE),
95        })
96}