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