1use std::sync::RwLock;
7
8use ratatui::style::{Color, Modifier, Style};
9
10static THEME: RwLock<Option<Theme>> = RwLock::new(None);
12
13static THEME_NAME: RwLock<Option<String>> = RwLock::new(None);
15
16pub fn init_theme(name: &str, theme: Theme) {
18 if let Ok(mut guard) = THEME.write() {
19 *guard = Some(theme);
20 }
21 if let Ok(mut guard) = THEME_NAME.write() {
22 *guard = Some(name.to_string());
23 }
24}
25
26pub fn set_theme(name: &str, theme: Theme) {
28 if let Ok(mut guard) = THEME.write() {
29 *guard = Some(theme);
30 }
31 if let Ok(mut guard) = THEME_NAME.write() {
32 *guard = Some(name.to_string());
33 }
34}
35
36pub fn current_theme_name() -> String {
38 THEME_NAME
39 .read()
40 .ok()
41 .and_then(|guard| guard.clone())
42 .unwrap_or_else(|| "default".to_string())
43}
44
45pub fn theme() -> Theme {
47 THEME
48 .read()
49 .ok()
50 .and_then(|guard| guard.clone())
51 .unwrap_or_default()
52}
53
54#[derive(Clone)]
56pub struct Theme {
57 pub background: Style,
59 pub text: Style,
60
61 pub border: Style,
63 pub border_focused: Style,
64
65 pub title_separator: Style,
67 pub title_indicator_connected: Style,
68 pub title_indicator_disconnected: Style,
69 pub title_text: Style,
70
71 pub user_prefix: Style,
73 pub system_prefix: Style,
74 pub assistant_prefix: Style,
75 pub timestamp: Style,
76
77 pub cursor: Style,
79
80 pub bold: Modifier,
82 pub italic: Modifier,
83 pub strikethrough: Modifier,
84 pub inline_code: Style,
85 pub link_text: Style,
86 pub link_url: Style,
87
88 pub heading_1: Style,
90 pub heading_2: Style,
91 pub heading_3: Style,
92 pub heading_4: Style,
93
94 pub code_block: Style,
96
97 pub table_header: Style,
99 pub table_cell: Style,
100 pub table_border: Style,
101
102 pub tool_header: Style,
104 pub tool_executing: Style,
105 pub tool_completed: Style,
106 pub tool_failed: Style,
107
108 pub input_border: Style,
110 pub input_text: Style,
111 pub prompt: Style,
112
113 pub throbber_label: Style,
115 pub throbber_spinner: Style,
116
117 pub status_help: Style,
119 pub status_model: Style,
120
121 pub popup_border: Style,
123 pub popup_header: Style,
124 pub popup_item: Style,
125 pub popup_item_selected: Style,
126 pub popup_item_desc: Style,
127 pub popup_item_desc_selected: Style,
128 pub popup_selected_bg: Style,
129 pub popup_empty: Style,
130
131 pub help_text: Style,
133 pub muted_text: Style,
134 pub focused_text: Style,
135 pub focus_indicator: Style,
136 pub selected: Style,
137 pub unselected: Style,
138 pub button_confirm: Style,
139 pub button_confirm_focused: Style,
140 pub button_cancel: Style,
141 pub button_cancel_focused: Style,
142 pub warning: Style,
143 pub category: Style,
144 pub resource: Style,
145}
146
147impl Theme {
148 pub fn bold(&self) -> Modifier { self.bold }
152 pub fn italic(&self) -> Modifier { self.italic }
153 pub fn strikethrough(&self) -> Modifier { self.strikethrough }
154 pub fn inline_code(&self) -> Style { self.inline_code }
155 pub fn link_text(&self) -> Style { self.link_text }
156 pub fn link_url(&self) -> Style { self.link_url }
157 pub fn heading_1(&self) -> Style { self.heading_1 }
158 pub fn heading_2(&self) -> Style { self.heading_2 }
159 pub fn heading_3(&self) -> Style { self.heading_3 }
160 pub fn heading_4(&self) -> Style { self.heading_4 }
161 pub fn code_block(&self) -> Style { self.code_block }
162 pub fn assistant_prefix(&self) -> Style { self.assistant_prefix }
163
164 pub fn table_header(&self) -> Style { self.table_header }
166 pub fn table_cell(&self) -> Style { self.table_cell }
167 pub fn table_border(&self) -> Style { self.table_border }
168
169 pub fn border(&self) -> Style { self.border }
171 pub fn border_focused(&self) -> Style { self.border_focused }
172
173 pub fn popup_border(&self) -> Style { self.popup_border }
175 pub fn popup_header(&self) -> Style { self.popup_header }
176 pub fn popup_item(&self) -> Style { self.popup_item }
177 pub fn popup_item_selected(&self) -> Style { self.popup_item_selected }
178 pub fn popup_item_desc(&self) -> Style { self.popup_item_desc }
179 pub fn popup_item_desc_selected(&self) -> Style { self.popup_item_desc_selected }
180 pub fn popup_selected_bg(&self) -> Style { self.popup_selected_bg }
181 pub fn popup_empty(&self) -> Style { self.popup_empty }
182
183 pub fn status_help(&self) -> Style { self.status_help }
185 pub fn background(&self) -> Style { self.background }
186 pub fn text(&self) -> Style { self.text }
187 pub fn cursor(&self) -> Style { self.cursor }
188
189 pub fn help_text(&self) -> Style { self.help_text }
191 pub fn muted_text(&self) -> Style { self.muted_text }
192 pub fn focused_text(&self) -> Style { self.focused_text }
193 pub fn focus_indicator(&self) -> Style { self.focus_indicator }
194 pub fn selected(&self) -> Style { self.selected }
195 pub fn unselected(&self) -> Style { self.unselected }
196 pub fn button_confirm(&self) -> Style { self.button_confirm }
197 pub fn button_confirm_focused(&self) -> Style { self.button_confirm_focused }
198 pub fn button_cancel(&self) -> Style { self.button_cancel }
199 pub fn button_cancel_focused(&self) -> Style { self.button_cancel_focused }
200 pub fn warning(&self) -> Style { self.warning }
201 pub fn category(&self) -> Style { self.category }
202 pub fn resource(&self) -> Style { self.resource }
203}
204
205impl Default for Theme {
206 fn default() -> Self {
207 Self {
208 background: Style::default(),
210 text: Style::default(),
211
212 border: Style::default().fg(Color::DarkGray),
214 border_focused: Style::default().fg(Color::Cyan),
215
216 title_separator: Style::default().fg(Color::DarkGray),
218 title_indicator_connected: Style::default().fg(Color::Green),
219 title_indicator_disconnected: Style::default().fg(Color::Red),
220 title_text: Style::default(),
221
222 user_prefix: Style::default().fg(Color::Blue),
224 system_prefix: Style::default().fg(Color::Yellow),
225 assistant_prefix: Style::default().fg(Color::Magenta),
226 timestamp: Style::default().fg(Color::DarkGray),
227
228 cursor: Style::default().fg(Color::Green),
230
231 bold: Modifier::BOLD,
233 italic: Modifier::ITALIC,
234 strikethrough: Modifier::CROSSED_OUT,
235 inline_code: Style::default().fg(Color::Yellow),
236 link_text: Style::default().fg(Color::Cyan),
237 link_url: Style::default().fg(Color::DarkGray),
238
239 heading_1: Style::default()
241 .fg(Color::Cyan)
242 .add_modifier(Modifier::BOLD),
243 heading_2: Style::default()
244 .fg(Color::Green)
245 .add_modifier(Modifier::BOLD),
246 heading_3: Style::default()
247 .fg(Color::Yellow)
248 .add_modifier(Modifier::BOLD),
249 heading_4: Style::default()
250 .fg(Color::White)
251 .add_modifier(Modifier::BOLD),
252
253 code_block: Style::default().fg(Color::Rgb(180, 180, 180)),
255
256 table_header: Style::default()
258 .fg(Color::Cyan)
259 .add_modifier(Modifier::BOLD),
260 table_cell: Style::default().fg(Color::White),
261 table_border: Style::default().fg(Color::DarkGray),
262
263 tool_header: Style::default().fg(Color::Cyan),
265 tool_executing: Style::default()
266 .fg(Color::Gray)
267 .add_modifier(Modifier::ITALIC),
268 tool_completed: Style::default().fg(Color::Green),
269 tool_failed: Style::default().fg(Color::Red),
270
271 input_border: Style::default().fg(Color::DarkGray),
273 input_text: Style::default(),
274 prompt: Style::default(),
275
276 throbber_label: Style::default().fg(Color::DarkGray),
278 throbber_spinner: Style::default().fg(Color::Cyan),
279
280 status_help: Style::default().fg(Color::DarkGray),
282 status_model: Style::default().fg(Color::DarkGray),
283
284 popup_border: Style::default().fg(Color::DarkGray),
286 popup_header: Style::default().fg(Color::DarkGray),
287 popup_item: Style::default().fg(Color::White),
288 popup_item_selected: Style::default()
289 .fg(Color::Cyan)
290 .add_modifier(Modifier::BOLD),
291 popup_item_desc: Style::default().fg(Color::DarkGray),
292 popup_item_desc_selected: Style::default().fg(Color::Gray),
293 popup_selected_bg: Style::default().bg(Color::DarkGray),
294 popup_empty: Style::default()
295 .fg(Color::DarkGray)
296 .add_modifier(Modifier::ITALIC),
297
298 help_text: Style::default().fg(Color::DarkGray),
300 muted_text: Style::default().fg(Color::Gray),
301 focused_text: Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD),
302 focus_indicator: Style::default().fg(Color::Yellow),
303 selected: Style::default().fg(Color::Green),
304 unselected: Style::default().fg(Color::Gray),
305 button_confirm: Style::default().fg(Color::Rgb(60, 120, 60)),
306 button_confirm_focused: Style::default().fg(Color::LightGreen).add_modifier(Modifier::BOLD),
307 button_cancel: Style::default().fg(Color::Rgb(140, 70, 70)),
308 button_cancel_focused: Style::default().fg(Color::LightRed).add_modifier(Modifier::BOLD),
309 warning: Style::default().fg(Color::Yellow),
310 category: Style::default().fg(Color::Magenta),
311 resource: Style::default().fg(Color::Cyan),
312 }
313 }
314}
315