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()); 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}