1use std::cell::Cell;
4
5use ratatui::style::Color;
6
7thread_local! {
8 static ACTIVE_RENDER_SETTINGS: Cell<TextRenderSettings> =
9 const { Cell::new(TextRenderSettings::DEFAULT) };
10}
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub struct TextPalette {
15 pub accent: Color,
17 pub info: Color,
19 pub success: Color,
21 pub surface: Color,
23 pub surface_clarification: Color,
25 pub surface_elevated: Color,
27 pub surface_overlay: Color,
29 pub text: Color,
31 pub text_muted: Color,
33 pub text_subtle: Color,
35 pub warning: Color,
37 pub warning_soft: Color,
39}
40
41impl TextPalette {
42 pub const DEFAULT: Self = Self {
44 accent: Color::Cyan,
45 info: Color::LightBlue,
46 success: Color::Green,
47 surface: Color::Rgb(35, 42, 55),
48 surface_clarification: Color::Rgb(28, 38, 48),
49 surface_elevated: Color::Black,
50 surface_overlay: Color::Black,
51 text: Color::White,
52 text_muted: Color::Gray,
53 text_subtle: Color::DarkGray,
54 warning: Color::Yellow,
55 warning_soft: Color::LightYellow,
56 };
57}
58
59impl Default for TextPalette {
60 fn default() -> Self {
61 Self::DEFAULT
62 }
63}
64
65#[derive(Clone, Copy, Debug, Eq, PartialEq)]
68pub struct TextRenderSettings {
69 pub cache_version: u64,
72 pub palette: TextPalette,
74}
75
76impl TextRenderSettings {
77 pub const DEFAULT: Self = Self {
79 cache_version: 0,
80 palette: TextPalette::DEFAULT,
81 };
82}
83
84impl Default for TextRenderSettings {
85 fn default() -> Self {
86 Self::DEFAULT
87 }
88}
89
90struct RenderSettingsScope<'settings> {
91 cell: &'settings Cell<TextRenderSettings>,
92 previous_settings: TextRenderSettings,
93}
94
95impl Drop for RenderSettingsScope<'_> {
96 fn drop(&mut self) {
97 self.cell.set(self.previous_settings);
98 }
99}
100
101pub(crate) mod palette {
102 use ratatui::style::Color;
103
104 use super::active_palette;
105
106 pub(crate) fn accent() -> Color {
107 active_palette().accent
108 }
109
110 pub(crate) fn info() -> Color {
111 active_palette().info
112 }
113
114 pub(crate) fn surface() -> Color {
115 active_palette().surface
116 }
117
118 pub(crate) fn surface_clarification() -> Color {
119 active_palette().surface_clarification
120 }
121
122 pub(crate) fn surface_elevated() -> Color {
123 active_palette().surface_elevated
124 }
125
126 pub(crate) fn surface_overlay() -> Color {
127 active_palette().surface_overlay
128 }
129
130 pub(crate) fn success() -> Color {
131 active_palette().success
132 }
133
134 pub(crate) fn text() -> Color {
135 active_palette().text
136 }
137
138 pub(crate) fn text_muted() -> Color {
139 active_palette().text_muted
140 }
141
142 pub(crate) fn text_subtle() -> Color {
143 active_palette().text_subtle
144 }
145
146 pub(crate) fn warning() -> Color {
147 active_palette().warning
148 }
149
150 pub(crate) fn warning_soft() -> Color {
151 active_palette().warning_soft
152 }
153}
154
155pub(crate) fn with_render_settings<Output>(
156 settings: TextRenderSettings,
157 render: impl FnOnce() -> Output,
158) -> Output {
159 ACTIVE_RENDER_SETTINGS.with(|cell| {
160 let previous_settings = cell.replace(settings);
161 let _scope = RenderSettingsScope {
162 cell,
163 previous_settings,
164 };
165
166 render()
167 })
168}
169
170pub(crate) fn active_theme_cache_version() -> u64 {
171 active_settings().cache_version
172}
173
174fn active_palette() -> TextPalette {
175 active_settings().palette
176}
177
178fn active_settings() -> TextRenderSettings {
179 ACTIVE_RENDER_SETTINGS.with(Cell::get)
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn test_default_palette_uses_current_theme_table_surface() {
188 let palette = TextPalette::DEFAULT;
190
191 let surface_elevated = palette.surface_elevated;
193
194 assert_eq!(surface_elevated, Color::Black);
196 }
197}