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