wireman_theme/
theme.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use crate::{skin, Config};
use logger::Logger;
use once_cell::sync::OnceCell;
use ratatui::{style::Style, widgets::BorderType};

pub static THEME: OnceCell<Theme> = OnceCell::new();

#[derive(Debug, Default, Clone)]
pub struct Theme {
    pub base: Base,
    pub list: List,
    pub border: Border,
    pub navbar: Navbar,
    pub editor: Editor,
    pub history: History,
    pub headers: Headers,
    pub footer: Footer,
    pub help_dialog: HelpDialog,
}

impl Theme {
    pub(crate) fn update_from_skin(&mut self, skin: &skin::Skin) {
        skin.apply_to(self);
    }
}

#[derive(Debug, Clone, Default)]
pub struct Base {
    pub style: Style,
}

#[derive(Debug, Clone)]
pub struct Border {
    pub border: (Style, Style),
    pub text: (Style, Style),
    pub border_type: (BorderType, BorderType),
}

impl Default for Border {
    fn default() -> Self {
        Self {
            border: (Style::default(), Style::default()),
            text: (Style::default(), Style::default()),
            border_type: (BorderType::Plain, BorderType::Double),
        }
    }
}

#[derive(Debug, Clone, Default)]
pub struct Navbar {
    pub title: Style,
    pub tabs: (Style, Style),
}

#[derive(Debug, Clone, Default)]
pub struct List {
    pub text: Style,
    pub focused: Style,
}

#[derive(Debug, Clone, Default)]
pub struct Editor {
    pub text: Style,
    pub cursor: Style,
    pub selection: Style,
    pub status_text: Style,
    pub status_line: Style,
    pub hide_status_line: bool,
}

#[derive(Debug, Clone, Default)]
pub struct History {
    pub active: (Style, Style),
    pub inactive: (Style, Style),
}

#[derive(Debug, Clone, Default)]
pub struct Headers {
    pub titles: Style,
    pub tabs: (Style, Style),
}

#[derive(Debug, Clone, Default)]
pub struct Footer {
    pub tabs: Style,
    pub text: Style,
    pub hide: bool,
}

#[derive(Debug, Clone, Default)]
pub struct HelpDialog {
    pub style: Style,
}

impl Theme {
    /// Initializes the `Theme` from a config.
    pub fn init(config: &Config) {
        let mut theme = Theme::default();

        if let Some(skin_file_path) = &config.skin {
            match skin::Skin::from_file(skin_file_path) {
                Ok(skin) => {
                    theme.update_from_skin(&skin);
                }
                Err(err) => {
                    Logger::debug(format!(
                        "Failed read skin from file {skin_file_path}, err: {err}"
                    ));
                    let default_skin = skin::Skin::default();
                    theme.update_from_skin(&default_skin);
                }
            }
        } else {
            let default_skin = skin::Skin::default();
            theme.update_from_skin(&default_skin);
        }

        let _ = THEME.set(theme.clone());
    }

    /// Gets the globally shared theme data
    #[must_use]
    pub fn global() -> &'static Theme {
        THEME.get_or_init(|| {
            Logger::debug("Theme was not initialized. Fallback to default.");
            Theme::default()
        })
    }
}