1use ratatui::style::Color;
2
3#[cfg(feature = "mermaid")]
4use crate::mermaid::theme::MermaidTheme;
5
6#[derive(Debug, Clone, Copy)]
7pub struct CodeColors {
8 pub comment: Color,
9 pub keyword: Color,
10 pub string: Color,
11 pub string_escape: Color,
12 pub number: Color,
13 pub constant: Color,
14 pub function: Color,
15 pub r#type: Color,
16 pub variable: Color,
17 pub property: Color,
18 pub operator: Color,
19 pub punctuation: Color,
20 pub attribute: Color,
21 pub tag: Color,
22 pub label: Color,
23 pub error: Color,
24}
25
26impl Default for CodeColors {
27 fn default() -> Self {
28 Self::DEFAULT
29 }
30}
31
32impl CodeColors {
33 pub const DEFAULT: Self = Self {
34 comment: Color::DarkGray,
35 keyword: Color::Magenta,
36 string: Color::Green,
37 string_escape: Color::LightGreen,
38 number: Color::Yellow,
39 constant: Color::Yellow,
40 function: Color::Cyan,
41 r#type: Color::LightCyan,
42 variable: Color::White,
43 property: Color::LightBlue,
44 operator: Color::LightMagenta,
45 punctuation: Color::DarkGray,
46 attribute: Color::LightYellow,
47 tag: Color::Cyan,
48 label: Color::LightRed,
49 error: Color::Red,
50 };
51
52 pub fn builder() -> CodeColorsBuilder {
53 CodeColorsBuilder(Self::default())
54 }
55}
56
57pub struct CodeColorsBuilder(CodeColors);
58
59impl CodeColorsBuilder {
60 pub fn comment(mut self, c: Color) -> Self {
61 self.0.comment = c;
62 self
63 }
64 pub fn keyword(mut self, c: Color) -> Self {
65 self.0.keyword = c;
66 self
67 }
68 pub fn string(mut self, c: Color) -> Self {
69 self.0.string = c;
70 self
71 }
72 pub fn string_escape(mut self, c: Color) -> Self {
73 self.0.string_escape = c;
74 self
75 }
76 pub fn number(mut self, c: Color) -> Self {
77 self.0.number = c;
78 self
79 }
80 pub fn constant(mut self, c: Color) -> Self {
81 self.0.constant = c;
82 self
83 }
84 pub fn function(mut self, c: Color) -> Self {
85 self.0.function = c;
86 self
87 }
88 pub fn r#type(mut self, c: Color) -> Self {
89 self.0.r#type = c;
90 self
91 }
92 pub fn variable(mut self, c: Color) -> Self {
93 self.0.variable = c;
94 self
95 }
96 pub fn property(mut self, c: Color) -> Self {
97 self.0.property = c;
98 self
99 }
100 pub fn operator(mut self, c: Color) -> Self {
101 self.0.operator = c;
102 self
103 }
104 pub fn punctuation(mut self, c: Color) -> Self {
105 self.0.punctuation = c;
106 self
107 }
108 pub fn attribute(mut self, c: Color) -> Self {
109 self.0.attribute = c;
110 self
111 }
112 pub fn tag(mut self, c: Color) -> Self {
113 self.0.tag = c;
114 self
115 }
116 pub fn label(mut self, c: Color) -> Self {
117 self.0.label = c;
118 self
119 }
120 pub fn error(mut self, c: Color) -> Self {
121 self.0.error = c;
122 self
123 }
124 pub fn build(self) -> CodeColors {
125 self.0
126 }
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
130pub struct Generation(pub u64);
131
132impl Generation {
133 pub fn next(&self) -> Self {
134 Self(self.0 + 1)
135 }
136}
137
138pub trait RichTextTheme {
139 fn generation(&self) -> Generation;
140 fn get_text_color(&self) -> Color;
141 fn get_muted_text_color(&self) -> Color;
142 fn get_primary_color(&self) -> Color;
143 fn get_popup_selected_background(&self) -> Color;
144 fn get_border_color(&self) -> Color;
145 fn get_focused_border_color(&self) -> Color;
146 fn get_secondary_color(&self) -> Color;
147 fn get_info_color(&self) -> Color;
148 fn get_json_key_color(&self) -> Color;
149 fn get_json_string_color(&self) -> Color;
150 fn get_json_number_color(&self) -> Color;
151 fn get_json_bool_color(&self) -> Color;
152 fn get_json_null_color(&self) -> Color;
153 fn get_accent_yellow(&self) -> Color;
154
155 fn get_code_colors(&self) -> CodeColors {
156 CodeColors::default()
157 }
158
159 fn get_popup_selected_text_color(&self) -> Color {
160 Color::White
161 }
162 fn get_background_color(&self) -> Color {
163 Color::Black
164 }
165
166 #[cfg(feature = "mermaid")]
167 fn get_mermaid_theme(&self) -> MermaidTheme {
168 MermaidTheme::for_background(self.get_background_color())
169 }
170}
171
172#[derive(Debug, Clone, Copy)]
173pub struct ThemeConfig {
174 pub gen: Generation,
175 pub text_color: Color,
176 pub muted_text_color: Color,
177 pub primary_color: Color,
178 pub popup_selected_background: Color,
179 pub border_color: Color,
180 pub focused_border_color: Color,
181 pub secondary_color: Color,
182 pub info_color: Color,
183 pub json_key_color: Color,
184 pub json_string_color: Color,
185 pub json_number_color: Color,
186 pub json_bool_color: Color,
187 pub json_null_color: Color,
188 pub accent_yellow: Color,
189 pub code_colors: CodeColors,
190}
191
192impl Default for ThemeConfig {
193 fn default() -> Self {
194 Self {
195 gen: Generation(1),
196 text_color: Color::White,
197 muted_text_color: Color::DarkGray,
198 primary_color: Color::Cyan,
199 popup_selected_background: Color::DarkGray,
200 border_color: Color::DarkGray,
201 focused_border_color: Color::White,
202 secondary_color: Color::Blue,
203 info_color: Color::LightBlue,
204 json_key_color: Color::LightCyan,
205 json_string_color: Color::Green,
206 json_number_color: Color::Yellow,
207 json_bool_color: Color::Magenta,
208 json_null_color: Color::DarkGray,
209 accent_yellow: Color::Yellow,
210 code_colors: CodeColors::DEFAULT,
211 }
212 }
213}
214
215impl ThemeConfig {
216 pub fn new() -> Self {
217 Self::default()
218 }
219
220 pub fn builder() -> ThemeBuilder {
221 ThemeBuilder {
222 config: Self::default(),
223 }
224 }
225
226 pub fn with_generation(mut self, gen: Generation) -> Self {
227 self.gen = gen;
228 self
229 }
230
231 pub fn with_text_color(mut self, c: Color) -> Self {
232 self.text_color = c;
233 self
234 }
235
236 pub fn with_muted_text_color(mut self, c: Color) -> Self {
237 self.muted_text_color = c;
238 self
239 }
240
241 pub fn with_primary_color(mut self, c: Color) -> Self {
242 self.primary_color = c;
243 self
244 }
245
246 pub fn with_popup_selected_background(mut self, c: Color) -> Self {
247 self.popup_selected_background = c;
248 self
249 }
250
251 pub fn with_border_color(mut self, c: Color) -> Self {
252 self.border_color = c;
253 self
254 }
255
256 pub fn with_focused_border_color(mut self, c: Color) -> Self {
257 self.focused_border_color = c;
258 self
259 }
260
261 pub fn with_secondary_color(mut self, c: Color) -> Self {
262 self.secondary_color = c;
263 self
264 }
265
266 pub fn with_info_color(mut self, c: Color) -> Self {
267 self.info_color = c;
268 self
269 }
270
271 pub fn with_json_key_color(mut self, c: Color) -> Self {
272 self.json_key_color = c;
273 self
274 }
275
276 pub fn with_json_string_color(mut self, c: Color) -> Self {
277 self.json_string_color = c;
278 self
279 }
280
281 pub fn with_json_number_color(mut self, c: Color) -> Self {
282 self.json_number_color = c;
283 self
284 }
285
286 pub fn with_json_bool_color(mut self, c: Color) -> Self {
287 self.json_bool_color = c;
288 self
289 }
290
291 pub fn with_json_null_color(mut self, c: Color) -> Self {
292 self.json_null_color = c;
293 self
294 }
295
296 pub fn with_accent_yellow(mut self, c: Color) -> Self {
297 self.accent_yellow = c;
298 self
299 }
300
301 pub fn with_code_colors(mut self, colors: CodeColors) -> Self {
302 self.code_colors = colors;
303 self
304 }
305}
306
307impl RichTextTheme for ThemeConfig {
308 fn generation(&self) -> Generation {
309 self.gen
310 }
311 fn get_text_color(&self) -> Color {
312 self.text_color
313 }
314 fn get_muted_text_color(&self) -> Color {
315 self.muted_text_color
316 }
317 fn get_primary_color(&self) -> Color {
318 self.primary_color
319 }
320 fn get_popup_selected_background(&self) -> Color {
321 self.popup_selected_background
322 }
323 fn get_border_color(&self) -> Color {
324 self.border_color
325 }
326 fn get_focused_border_color(&self) -> Color {
327 self.focused_border_color
328 }
329 fn get_secondary_color(&self) -> Color {
330 self.secondary_color
331 }
332 fn get_info_color(&self) -> Color {
333 self.info_color
334 }
335 fn get_json_key_color(&self) -> Color {
336 self.json_key_color
337 }
338 fn get_json_string_color(&self) -> Color {
339 self.json_string_color
340 }
341 fn get_json_number_color(&self) -> Color {
342 self.json_number_color
343 }
344 fn get_json_bool_color(&self) -> Color {
345 self.json_bool_color
346 }
347 fn get_json_null_color(&self) -> Color {
348 self.json_null_color
349 }
350 fn get_accent_yellow(&self) -> Color {
351 self.accent_yellow
352 }
353 fn get_code_colors(&self) -> CodeColors {
354 self.code_colors
355 }
356}
357
358pub struct ThemeBuilder {
359 config: ThemeConfig,
360}
361
362impl ThemeBuilder {
363 pub fn with_generation(mut self, gen: Generation) -> Self {
364 self.config.gen = gen;
365 self
366 }
367
368 pub fn with_text_color(mut self, c: Color) -> Self {
369 self.config.text_color = c;
370 self
371 }
372
373 pub fn with_muted_text_color(mut self, c: Color) -> Self {
374 self.config.muted_text_color = c;
375 self
376 }
377
378 pub fn with_primary_color(mut self, c: Color) -> Self {
379 self.config.primary_color = c;
380 self
381 }
382
383 pub fn with_popup_selected_background(mut self, c: Color) -> Self {
384 self.config.popup_selected_background = c;
385 self
386 }
387
388 pub fn with_border_color(mut self, c: Color) -> Self {
389 self.config.border_color = c;
390 self
391 }
392
393 pub fn with_focused_border_color(mut self, c: Color) -> Self {
394 self.config.focused_border_color = c;
395 self
396 }
397
398 pub fn with_secondary_color(mut self, c: Color) -> Self {
399 self.config.secondary_color = c;
400 self
401 }
402
403 pub fn with_info_color(mut self, c: Color) -> Self {
404 self.config.info_color = c;
405 self
406 }
407
408 pub fn with_json_key_color(mut self, c: Color) -> Self {
409 self.config.json_key_color = c;
410 self
411 }
412
413 pub fn with_json_string_color(mut self, c: Color) -> Self {
414 self.config.json_string_color = c;
415 self
416 }
417
418 pub fn with_json_number_color(mut self, c: Color) -> Self {
419 self.config.json_number_color = c;
420 self
421 }
422
423 pub fn with_json_bool_color(mut self, c: Color) -> Self {
424 self.config.json_bool_color = c;
425 self
426 }
427
428 pub fn with_json_null_color(mut self, c: Color) -> Self {
429 self.config.json_null_color = c;
430 self
431 }
432
433 pub fn with_accent_yellow(mut self, c: Color) -> Self {
434 self.config.accent_yellow = c;
435 self
436 }
437
438 pub fn with_code_colors(mut self, colors: CodeColors) -> Self {
439 self.config.code_colors = colors;
440 self
441 }
442
443 pub fn build(self) -> ThemeConfig {
444 self.config
445 }
446}
447
448#[deprecated(since = "0.3.0", note = "Use `ThemeConfig::default()` instead")]
449pub struct DefaultTheme;
450
451#[allow(deprecated)]
452impl RichTextTheme for DefaultTheme {
453 fn generation(&self) -> Generation {
454 Generation(1)
455 }
456 fn get_text_color(&self) -> Color {
457 Color::White
458 }
459 fn get_muted_text_color(&self) -> Color {
460 Color::DarkGray
461 }
462 fn get_primary_color(&self) -> Color {
463 Color::Cyan
464 }
465 fn get_secondary_color(&self) -> Color {
466 Color::Blue
467 }
468 fn get_info_color(&self) -> Color {
469 Color::LightBlue
470 }
471 fn get_border_color(&self) -> Color {
472 Color::DarkGray
473 }
474 fn get_focused_border_color(&self) -> Color {
475 Color::White
476 }
477 fn get_popup_selected_background(&self) -> Color {
478 Color::DarkGray
479 }
480 fn get_json_key_color(&self) -> Color {
481 Color::LightCyan
482 }
483 fn get_json_string_color(&self) -> Color {
484 Color::Green
485 }
486 fn get_json_number_color(&self) -> Color {
487 Color::Yellow
488 }
489 fn get_json_bool_color(&self) -> Color {
490 Color::Magenta
491 }
492 fn get_json_null_color(&self) -> Color {
493 Color::DarkGray
494 }
495 fn get_accent_yellow(&self) -> Color {
496 Color::Yellow
497 }
498}