1use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
6pub struct Color {
7 pub r: u8,
8 pub g: u8,
9 pub b: u8,
10}
11
12impl Color {
13 pub const fn new(r: u8, g: u8, b: u8) -> Self {
14 Self { r, g, b }
15 }
16
17 #[allow(dead_code)]
18 pub fn as_array(&self) -> [u8; 3] {
19 [self.r, self.g, self.b]
20 }
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct Theme {
26 pub name: String,
27 pub foreground: Color,
28 pub background: Color,
29 pub cursor: Color,
30 pub selection_bg: Color,
31 pub selection_fg: Color,
32
33 pub black: Color,
35 pub red: Color,
36 pub green: Color,
37 pub yellow: Color,
38 pub blue: Color,
39 pub magenta: Color,
40 pub cyan: Color,
41 pub white: Color,
42 pub bright_black: Color,
43 pub bright_red: Color,
44 pub bright_green: Color,
45 pub bright_yellow: Color,
46 pub bright_blue: Color,
47 pub bright_magenta: Color,
48 pub bright_cyan: Color,
49 pub bright_white: Color,
50}
51
52impl Theme {
53 #[allow(dead_code)]
55 pub fn ansi_color(&self, index: u8) -> Color {
56 match index {
57 0 => self.black,
58 1 => self.red,
59 2 => self.green,
60 3 => self.yellow,
61 4 => self.blue,
62 5 => self.magenta,
63 6 => self.cyan,
64 7 => self.white,
65 8 => self.bright_black,
66 9 => self.bright_red,
67 10 => self.bright_green,
68 11 => self.bright_yellow,
69 12 => self.bright_blue,
70 13 => self.bright_magenta,
71 14 => self.bright_cyan,
72 15 => self.bright_white,
73 _ => self.foreground,
74 }
75 }
76
77 pub fn dracula() -> Self {
79 Self {
80 name: "Dracula".to_string(),
81 foreground: Color::new(248, 248, 242),
82 background: Color::new(40, 42, 54),
83 cursor: Color::new(248, 248, 240),
84 selection_bg: Color::new(68, 71, 90),
85 selection_fg: Color::new(248, 248, 242),
86 black: Color::new(0, 0, 0),
87 red: Color::new(255, 85, 85),
88 green: Color::new(80, 250, 123),
89 yellow: Color::new(241, 250, 140),
90 blue: Color::new(189, 147, 249),
91 magenta: Color::new(255, 121, 198),
92 cyan: Color::new(139, 233, 253),
93 white: Color::new(255, 255, 255),
94 bright_black: Color::new(98, 114, 164),
95 bright_red: Color::new(255, 110, 103),
96 bright_green: Color::new(90, 247, 142),
97 bright_yellow: Color::new(244, 244, 161),
98 bright_blue: Color::new(189, 147, 249),
99 bright_magenta: Color::new(255, 121, 198),
100 bright_cyan: Color::new(139, 233, 253),
101 bright_white: Color::new(255, 255, 255),
102 }
103 }
104
105 pub fn solarized_dark() -> Self {
107 Self {
108 name: "Solarized Dark".to_string(),
109 foreground: Color::new(131, 148, 150),
110 background: Color::new(0, 43, 54),
111 cursor: Color::new(147, 161, 161),
112 selection_bg: Color::new(7, 54, 66),
113 selection_fg: Color::new(147, 161, 161),
114 black: Color::new(7, 54, 66),
115 red: Color::new(220, 50, 47),
116 green: Color::new(133, 153, 0),
117 yellow: Color::new(181, 137, 0),
118 blue: Color::new(38, 139, 210),
119 magenta: Color::new(211, 54, 130),
120 cyan: Color::new(42, 161, 152),
121 white: Color::new(238, 232, 213),
122 bright_black: Color::new(0, 43, 54),
123 bright_red: Color::new(203, 75, 22),
124 bright_green: Color::new(88, 110, 117),
125 bright_yellow: Color::new(101, 123, 131),
126 bright_blue: Color::new(131, 148, 150),
127 bright_magenta: Color::new(108, 113, 196),
128 bright_cyan: Color::new(147, 161, 161),
129 bright_white: Color::new(253, 246, 227),
130 }
131 }
132
133 pub fn nord() -> Self {
135 Self {
136 name: "Nord".to_string(),
137 foreground: Color::new(216, 222, 233),
138 background: Color::new(46, 52, 64),
139 cursor: Color::new(216, 222, 233),
140 selection_bg: Color::new(59, 66, 82),
141 selection_fg: Color::new(216, 222, 233),
142 black: Color::new(59, 66, 82),
143 red: Color::new(191, 97, 106),
144 green: Color::new(163, 190, 140),
145 yellow: Color::new(235, 203, 139),
146 blue: Color::new(129, 161, 193),
147 magenta: Color::new(180, 142, 173),
148 cyan: Color::new(136, 192, 208),
149 white: Color::new(229, 233, 240),
150 bright_black: Color::new(76, 86, 106),
151 bright_red: Color::new(191, 97, 106),
152 bright_green: Color::new(163, 190, 140),
153 bright_yellow: Color::new(235, 203, 139),
154 bright_blue: Color::new(129, 161, 193),
155 bright_magenta: Color::new(180, 142, 173),
156 bright_cyan: Color::new(143, 188, 187),
157 bright_white: Color::new(236, 239, 244),
158 }
159 }
160
161 pub fn monokai() -> Self {
163 Self {
164 name: "Monokai".to_string(),
165 foreground: Color::new(248, 248, 242),
166 background: Color::new(39, 40, 34),
167 cursor: Color::new(253, 254, 236),
168 selection_bg: Color::new(73, 72, 62),
169 selection_fg: Color::new(248, 248, 242),
170 black: Color::new(39, 40, 34),
171 red: Color::new(249, 38, 114),
172 green: Color::new(166, 226, 46),
173 yellow: Color::new(244, 191, 117),
174 blue: Color::new(102, 217, 239),
175 magenta: Color::new(174, 129, 255),
176 cyan: Color::new(161, 239, 228),
177 white: Color::new(248, 248, 242),
178 bright_black: Color::new(117, 113, 94),
179 bright_red: Color::new(249, 38, 114),
180 bright_green: Color::new(166, 226, 46),
181 bright_yellow: Color::new(244, 191, 117),
182 bright_blue: Color::new(102, 217, 239),
183 bright_magenta: Color::new(174, 129, 255),
184 bright_cyan: Color::new(161, 239, 228),
185 bright_white: Color::new(249, 248, 245),
186 }
187 }
188
189 pub fn one_dark() -> Self {
191 Self {
192 name: "One Dark".to_string(),
193 foreground: Color::new(171, 178, 191),
194 background: Color::new(40, 44, 52),
195 cursor: Color::new(171, 178, 191),
196 selection_bg: Color::new(56, 61, 71),
197 selection_fg: Color::new(171, 178, 191),
198 black: Color::new(40, 44, 52),
199 red: Color::new(224, 108, 117),
200 green: Color::new(152, 195, 121),
201 yellow: Color::new(229, 192, 123),
202 blue: Color::new(97, 175, 239),
203 magenta: Color::new(198, 120, 221),
204 cyan: Color::new(86, 182, 194),
205 white: Color::new(171, 178, 191),
206 bright_black: Color::new(92, 99, 112),
207 bright_red: Color::new(224, 108, 117),
208 bright_green: Color::new(152, 195, 121),
209 bright_yellow: Color::new(229, 192, 123),
210 bright_blue: Color::new(97, 175, 239),
211 bright_magenta: Color::new(198, 120, 221),
212 bright_cyan: Color::new(86, 182, 194),
213 bright_white: Color::new(255, 255, 255),
214 }
215 }
216
217 pub fn default_dark() -> Self {
219 Self {
220 name: "Default Dark".to_string(),
221 foreground: Color::new(255, 255, 255),
222 background: Color::new(0, 0, 0),
223 cursor: Color::new(255, 255, 255),
224 selection_bg: Color::new(100, 100, 100),
225 selection_fg: Color::new(255, 255, 255),
226 black: Color::new(0, 0, 0),
227 red: Color::new(205, 0, 0),
228 green: Color::new(0, 205, 0),
229 yellow: Color::new(205, 205, 0),
230 blue: Color::new(0, 0, 238),
231 magenta: Color::new(205, 0, 205),
232 cyan: Color::new(0, 205, 205),
233 white: Color::new(229, 229, 229),
234 bright_black: Color::new(127, 127, 127),
235 bright_red: Color::new(255, 0, 0),
236 bright_green: Color::new(0, 255, 0),
237 bright_yellow: Color::new(255, 255, 0),
238 bright_blue: Color::new(92, 92, 255),
239 bright_magenta: Color::new(255, 0, 255),
240 bright_cyan: Color::new(0, 255, 255),
241 bright_white: Color::new(255, 255, 255),
242 }
243 }
244
245 pub fn dark_background() -> Self {
247 Self {
248 name: "Dark Background".to_string(),
249 foreground: Color::new(187, 187, 187),
250 background: Color::new(0, 0, 0),
251 cursor: Color::new(187, 187, 187),
252 selection_bg: Color::new(181, 213, 255),
253 selection_fg: Color::new(0, 0, 0),
254 black: Color::new(0, 0, 0),
255 red: Color::new(187, 0, 0),
256 green: Color::new(0, 187, 0),
257 yellow: Color::new(187, 187, 0),
258 blue: Color::new(0, 0, 187),
259 magenta: Color::new(187, 0, 187),
260 cyan: Color::new(0, 187, 187),
261 white: Color::new(187, 187, 187),
262 bright_black: Color::new(85, 85, 85),
263 bright_red: Color::new(255, 85, 85),
264 bright_green: Color::new(85, 255, 85),
265 bright_yellow: Color::new(255, 255, 85),
266 bright_blue: Color::new(85, 85, 255),
267 bright_magenta: Color::new(255, 85, 255),
268 bright_cyan: Color::new(85, 255, 255),
269 bright_white: Color::new(255, 255, 255),
270 }
271 }
272
273 pub fn high_contrast() -> Self {
275 Self {
276 name: "High Contrast".to_string(),
277 foreground: Color::new(255, 255, 255),
278 background: Color::new(0, 0, 0),
279 cursor: Color::new(255, 255, 255),
280 selection_bg: Color::new(51, 51, 51),
281 selection_fg: Color::new(255, 255, 255),
282 black: Color::new(0, 0, 0),
283 red: Color::new(255, 0, 0),
284 green: Color::new(0, 255, 0),
285 yellow: Color::new(255, 255, 0),
286 blue: Color::new(0, 0, 255),
287 magenta: Color::new(255, 0, 255),
288 cyan: Color::new(0, 255, 255),
289 white: Color::new(255, 255, 255),
290 bright_black: Color::new(127, 127, 127),
291 bright_red: Color::new(255, 127, 127),
292 bright_green: Color::new(127, 255, 127),
293 bright_yellow: Color::new(255, 255, 127),
294 bright_blue: Color::new(127, 127, 255),
295 bright_magenta: Color::new(255, 127, 255),
296 bright_cyan: Color::new(127, 255, 255),
297 bright_white: Color::new(255, 255, 255),
298 }
299 }
300
301 pub fn light_background() -> Self {
303 Self {
304 name: "Light Background".to_string(),
305 foreground: Color::new(0, 0, 0),
306 background: Color::new(255, 255, 255),
307 cursor: Color::new(0, 0, 0),
308 selection_bg: Color::new(203, 228, 255),
309 selection_fg: Color::new(0, 0, 0),
310 black: Color::new(0, 0, 0),
311 red: Color::new(187, 0, 0),
312 green: Color::new(0, 187, 0),
313 yellow: Color::new(187, 187, 0),
314 blue: Color::new(0, 0, 187),
315 magenta: Color::new(187, 0, 187),
316 cyan: Color::new(0, 187, 187),
317 white: Color::new(187, 187, 187),
318 bright_black: Color::new(85, 85, 85),
319 bright_red: Color::new(255, 85, 85),
320 bright_green: Color::new(85, 255, 85),
321 bright_yellow: Color::new(255, 255, 85),
322 bright_blue: Color::new(85, 85, 255),
323 bright_magenta: Color::new(255, 85, 255),
324 bright_cyan: Color::new(85, 255, 255),
325 bright_white: Color::new(255, 255, 255),
326 }
327 }
328
329 pub fn pastel_dark() -> Self {
331 Self {
332 name: "Pastel (Dark Background)".to_string(),
333 foreground: Color::new(187, 187, 187),
334 background: Color::new(0, 0, 0),
335 cursor: Color::new(255, 165, 96),
336 selection_bg: Color::new(54, 57, 131),
337 selection_fg: Color::new(242, 242, 242),
338 black: Color::new(79, 79, 79),
339 red: Color::new(255, 108, 96),
340 green: Color::new(168, 255, 96),
341 yellow: Color::new(255, 255, 182),
342 blue: Color::new(150, 203, 254),
343 magenta: Color::new(255, 115, 253),
344 cyan: Color::new(198, 197, 254),
345 white: Color::new(238, 238, 238),
346 bright_black: Color::new(124, 124, 124),
347 bright_red: Color::new(255, 182, 176),
348 bright_green: Color::new(206, 255, 172),
349 bright_yellow: Color::new(255, 255, 204),
350 bright_blue: Color::new(181, 220, 255),
351 bright_magenta: Color::new(255, 156, 254),
352 bright_cyan: Color::new(223, 223, 254),
353 bright_white: Color::new(255, 255, 255),
354 }
355 }
356
357 pub fn regular() -> Self {
359 Self {
360 name: "Regular".to_string(),
361 foreground: Color::new(16, 16, 16),
362 background: Color::new(250, 250, 250),
363 cursor: Color::new(0, 0, 0),
364 selection_bg: Color::new(179, 215, 255),
365 selection_fg: Color::new(0, 0, 0),
366 black: Color::new(20, 25, 30),
367 red: Color::new(180, 60, 42),
368 green: Color::new(0, 194, 0),
369 yellow: Color::new(199, 196, 0),
370 blue: Color::new(39, 68, 199),
371 magenta: Color::new(192, 64, 190),
372 cyan: Color::new(0, 197, 199),
373 white: Color::new(199, 199, 199),
374 bright_black: Color::new(104, 104, 104),
375 bright_red: Color::new(221, 121, 117),
376 bright_green: Color::new(88, 231, 144),
377 bright_yellow: Color::new(236, 225, 0),
378 bright_blue: Color::new(167, 171, 242),
379 bright_magenta: Color::new(225, 126, 225),
380 bright_cyan: Color::new(96, 253, 255),
381 bright_white: Color::new(255, 255, 255),
382 }
383 }
384
385 pub fn smoooooth() -> Self {
387 Self {
388 name: "Smoooooth".to_string(),
389 foreground: Color::new(220, 220, 220),
390 background: Color::new(21, 25, 31),
391 cursor: Color::new(255, 255, 255),
392 selection_bg: Color::new(179, 215, 255),
393 selection_fg: Color::new(0, 0, 0),
394 black: Color::new(20, 25, 30),
395 red: Color::new(180, 60, 42),
396 green: Color::new(0, 194, 0),
397 yellow: Color::new(199, 196, 0),
398 blue: Color::new(39, 68, 199),
399 magenta: Color::new(192, 64, 190),
400 cyan: Color::new(0, 197, 199),
401 white: Color::new(199, 199, 199),
402 bright_black: Color::new(104, 104, 104),
403 bright_red: Color::new(221, 121, 117),
404 bright_green: Color::new(88, 231, 144),
405 bright_yellow: Color::new(236, 225, 0),
406 bright_blue: Color::new(167, 171, 242),
407 bright_magenta: Color::new(225, 126, 225),
408 bright_cyan: Color::new(96, 253, 255),
409 bright_white: Color::new(255, 255, 255),
410 }
411 }
412
413 pub fn solarized() -> Self {
415 Self {
416 name: "Solarized".to_string(),
417 foreground: Color::new(131, 148, 150),
418 background: Color::new(0, 43, 54),
419 cursor: Color::new(131, 148, 150),
420 selection_bg: Color::new(7, 54, 66),
421 selection_fg: Color::new(147, 161, 161),
422 black: Color::new(7, 54, 66),
423 red: Color::new(220, 50, 47),
424 green: Color::new(133, 153, 0),
425 yellow: Color::new(181, 137, 0),
426 blue: Color::new(38, 139, 210),
427 magenta: Color::new(211, 54, 130),
428 cyan: Color::new(42, 161, 152),
429 white: Color::new(238, 232, 213),
430 bright_black: Color::new(0, 43, 54),
431 bright_red: Color::new(203, 75, 22),
432 bright_green: Color::new(88, 110, 117),
433 bright_yellow: Color::new(101, 123, 131),
434 bright_blue: Color::new(131, 148, 150),
435 bright_magenta: Color::new(108, 113, 196),
436 bright_cyan: Color::new(147, 161, 161),
437 bright_white: Color::new(253, 246, 227),
438 }
439 }
440
441 pub fn solarized_light() -> Self {
443 Self {
444 name: "Solarized Light".to_string(),
445 foreground: Color::new(101, 123, 131),
446 background: Color::new(253, 246, 227),
447 cursor: Color::new(88, 110, 117),
448 selection_bg: Color::new(238, 232, 213),
449 selection_fg: Color::new(88, 110, 117),
450 black: Color::new(238, 232, 213),
451 red: Color::new(220, 50, 47),
452 green: Color::new(133, 153, 0),
453 yellow: Color::new(181, 137, 0),
454 blue: Color::new(38, 139, 210),
455 magenta: Color::new(211, 54, 130),
456 cyan: Color::new(42, 161, 152),
457 white: Color::new(7, 54, 66),
458 bright_black: Color::new(253, 246, 227),
459 bright_red: Color::new(203, 75, 22),
460 bright_green: Color::new(147, 161, 161),
461 bright_yellow: Color::new(131, 148, 150),
462 bright_blue: Color::new(101, 123, 131),
463 bright_magenta: Color::new(108, 113, 196),
464 bright_cyan: Color::new(88, 110, 117),
465 bright_white: Color::new(0, 43, 54),
466 }
467 }
468
469 pub fn iterm2_dark() -> Self {
471 Self {
472 name: "iTerm2 Dark".to_string(),
473 foreground: Color::new(178, 178, 178),
474 background: Color::new(0, 0, 0),
475 cursor: Color::new(255, 255, 255),
476 selection_bg: Color::new(179, 215, 255),
477 selection_fg: Color::new(0, 0, 0),
478 black: Color::new(0, 0, 0),
479 red: Color::new(171, 53, 37),
480 green: Color::new(87, 191, 55),
481 yellow: Color::new(198, 196, 63),
482 blue: Color::new(45, 66, 192),
483 magenta: Color::new(177, 72, 184),
484 cyan: Color::new(88, 194, 197),
485 white: Color::new(199, 199, 199),
486 bright_black: Color::new(103, 103, 103),
487 bright_red: Color::new(207, 126, 119),
488 bright_green: Color::new(129, 227, 151),
489 bright_yellow: Color::new(233, 221, 0),
490 bright_blue: Color::new(167, 170, 236),
491 bright_magenta: Color::new(211, 130, 219),
492 bright_cyan: Color::new(142, 249, 253),
493 bright_white: Color::new(254, 254, 254),
494 }
495 }
496
497 pub fn tango_dark() -> Self {
499 Self {
500 name: "Tango Dark".to_string(),
501 foreground: Color::new(211, 215, 207),
502 background: Color::new(46, 52, 54),
503 cursor: Color::new(211, 215, 207),
504 selection_bg: Color::new(238, 238, 236),
505 selection_fg: Color::new(85, 87, 83),
506 black: Color::new(46, 52, 54),
507 red: Color::new(204, 0, 0),
508 green: Color::new(78, 154, 6),
509 yellow: Color::new(196, 160, 0),
510 blue: Color::new(52, 101, 164),
511 magenta: Color::new(117, 80, 123),
512 cyan: Color::new(6, 152, 154),
513 white: Color::new(211, 215, 207),
514 bright_black: Color::new(85, 87, 83),
515 bright_red: Color::new(239, 41, 41),
516 bright_green: Color::new(138, 226, 52),
517 bright_yellow: Color::new(252, 233, 79),
518 bright_blue: Color::new(114, 159, 207),
519 bright_magenta: Color::new(173, 127, 168),
520 bright_cyan: Color::new(52, 226, 226),
521 bright_white: Color::new(238, 238, 236),
522 }
523 }
524
525 pub fn tango_light() -> Self {
527 Self {
528 name: "Tango Light".to_string(),
529 foreground: Color::new(46, 52, 54),
530 background: Color::new(255, 255, 255),
531 cursor: Color::new(46, 52, 54),
532 selection_bg: Color::new(203, 228, 255),
533 selection_fg: Color::new(46, 52, 54),
534 black: Color::new(46, 52, 54),
535 red: Color::new(204, 0, 0),
536 green: Color::new(78, 154, 6),
537 yellow: Color::new(196, 160, 0),
538 blue: Color::new(52, 101, 164),
539 magenta: Color::new(117, 80, 123),
540 cyan: Color::new(6, 152, 154),
541 white: Color::new(211, 215, 207),
542 bright_black: Color::new(85, 87, 83),
543 bright_red: Color::new(239, 41, 41),
544 bright_green: Color::new(138, 226, 52),
545 bright_yellow: Color::new(252, 233, 79),
546 bright_blue: Color::new(114, 159, 207),
547 bright_magenta: Color::new(173, 127, 168),
548 bright_cyan: Color::new(52, 226, 226),
549 bright_white: Color::new(238, 238, 236),
550 }
551 }
552
553 #[allow(dead_code)]
555 pub fn by_name(name: &str) -> Option<Self> {
556 let normalized = name.trim().to_lowercase().replace(['_', ' '], "-");
557
558 match normalized.as_str() {
559 "dracula" => Some(Self::dracula()),
560 "solarized" => Some(Self::solarized()),
561 "solarized-dark" => Some(Self::solarized_dark()),
562 "solarized-light" => Some(Self::solarized_light()),
563 "nord" => Some(Self::nord()),
564 "monokai" => Some(Self::monokai()),
565 "one-dark" | "onedark" => Some(Self::one_dark()),
566 "default-dark" | "default" => Some(Self::default_dark()),
567 "dark-background" => Some(Self::dark_background()),
568 "high-contrast" => Some(Self::high_contrast()),
569 "light-background" => Some(Self::light_background()),
570 "pastel-dark" => Some(Self::pastel_dark()),
571 "regular" => Some(Self::regular()),
572 "smoooooth" => Some(Self::smoooooth()),
573 "iterm2-dark" | "iterm2" => Some(Self::iterm2_dark()),
574 "tango-dark" => Some(Self::tango_dark()),
575 "tango-light" => Some(Self::tango_light()),
576 _ => None,
577 }
578 }
579
580 #[allow(dead_code)]
582 pub fn available_themes() -> Vec<&'static str> {
583 vec![
584 "Dark Background",
585 "Default Dark",
586 "Dracula",
587 "High Contrast",
588 "iTerm2 Dark",
589 "Light Background",
590 "Monokai",
591 "Nord",
592 "One Dark",
593 "Pastel (Dark Background)",
594 "Regular",
595 "Smoooooth",
596 "Solarized",
597 "Solarized Dark",
598 "Solarized Light",
599 "Tango Dark",
600 "Tango Light",
601 ]
602 }
603}
604
605impl Default for Theme {
606 fn default() -> Self {
607 Self::default_dark()
608 }
609}