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
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,
}

#[allow(clippy::struct_field_names)]
#[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 skin = config
            .skin
            .as_deref()
            .and_then(|skin_file| match skin::Skin::from_file(skin_file) {
                Ok(skin) => Some(skin),
                Err(err) => {
                    Logger::debug(format!(
                        "Failed to read skin from file {skin_file}, err: {err}"
                    ));
                    None
                }
            })
            .unwrap_or_default();

        let mut theme = Theme::default();
        theme.update_from_skin(&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()
        })
    }
}