1use once_cell::sync::Lazy;
12use std::collections::HashMap;
13
14use crate::error::ParseError;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
22pub struct ColorTriplet {
23 pub red: u8,
25 pub green: u8,
27 pub blue: u8,
29}
30
31impl ColorTriplet {
32 pub const fn new(red: u8, green: u8, blue: u8) -> Self {
34 Self { red, green, blue }
35 }
36
37 pub fn hex(&self) -> String {
39 format!("#{:02x}{:02x}{:02x}", self.red, self.green, self.blue)
40 }
41
42 pub fn rgb(&self) -> String {
44 format!("rgb({},{},{})", self.red, self.green, self.blue)
45 }
46
47 pub fn normalized(&self) -> (f64, f64, f64) {
49 (
50 self.red as f64 / 255.0,
51 self.green as f64 / 255.0,
52 self.blue as f64 / 255.0,
53 )
54 }
55}
56
57impl From<(u8, u8, u8)> for ColorTriplet {
58 fn from((r, g, b): (u8, u8, u8)) -> Self {
59 Self::new(r, g, b)
60 }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
69pub enum ColorSystem {
70 Standard = 1,
72 EightBit = 2,
74 TrueColor = 3,
76 Windows = 4,
78}
79
80impl ColorSystem {
81 pub fn color_count(&self) -> usize {
83 match self {
84 ColorSystem::Standard => 16,
85 ColorSystem::EightBit => 256,
86 ColorSystem::TrueColor => 16_777_216,
87 ColorSystem::Windows => 16,
88 }
89 }
90
91 fn rank(&self) -> u8 {
96 match self {
97 ColorSystem::Standard => 1,
98 ColorSystem::Windows => 1, ColorSystem::EightBit => 2,
100 ColorSystem::TrueColor => 3,
101 }
102 }
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
111pub enum ColorType {
112 #[default]
114 Default,
115 Standard,
117 EightBit,
119 TrueColor,
121 Windows,
123}
124
125impl ColorType {
126 pub fn system(&self) -> ColorSystem {
128 match self {
129 ColorType::Default => ColorSystem::Standard,
130 ColorType::Standard => ColorSystem::Standard,
131 ColorType::EightBit => ColorSystem::EightBit,
132 ColorType::TrueColor => ColorSystem::TrueColor,
133 ColorType::Windows => ColorSystem::Windows,
134 }
135 }
136}
137
138#[derive(Debug, Clone)]
144pub struct Palette {
145 colors: Vec<ColorTriplet>,
146}
147
148impl Palette {
149 pub fn new(colors: &[(u8, u8, u8)]) -> Self {
151 Self {
152 colors: colors.iter().map(|&c| ColorTriplet::from(c)).collect(),
153 }
154 }
155
156 pub fn get(&self, index: usize) -> Option<ColorTriplet> {
158 self.colors.get(index).copied()
159 }
160
161 pub fn len(&self) -> usize {
163 self.colors.len()
164 }
165
166 pub fn is_empty(&self) -> bool {
168 self.colors.is_empty()
169 }
170
171 pub fn match_color(&self, triplet: ColorTriplet) -> usize {
176 let red1 = triplet.red as i32;
177 let green1 = triplet.green as i32;
178 let blue1 = triplet.blue as i32;
179
180 let mut min_distance = f64::MAX;
181 let mut min_index = 0;
182
183 for (index, color) in self.colors.iter().enumerate() {
184 let red2 = color.red as i32;
185 let green2 = color.green as i32;
186 let blue2 = color.blue as i32;
187
188 let red_mean = (red1 + red2) / 2;
190 let red_diff = red1 - red2;
191 let green_diff = green1 - green2;
192 let blue_diff = blue1 - blue2;
193
194 let distance = (((512 + red_mean) * red_diff * red_diff) >> 8) as f64
195 + (4 * green_diff * green_diff) as f64
196 + (((767 - red_mean) * blue_diff * blue_diff) >> 8) as f64;
197 let distance = distance.sqrt();
198
199 if distance < min_distance {
200 min_distance = distance;
201 min_index = index;
202 }
203 }
204
205 min_index
206 }
207}
208
209impl std::ops::Index<usize> for Palette {
210 type Output = ColorTriplet;
211
212 fn index(&self, index: usize) -> &Self::Output {
213 &self.colors[index]
214 }
215}
216
217pub static WINDOWS_PALETTE: Lazy<Palette> = Lazy::new(|| {
223 Palette::new(&[
224 (12, 12, 12),
225 (197, 15, 31),
226 (19, 161, 14),
227 (193, 156, 0),
228 (0, 55, 218),
229 (136, 23, 152),
230 (58, 150, 221),
231 (204, 204, 204),
232 (118, 118, 118),
233 (231, 72, 86),
234 (22, 198, 12),
235 (249, 241, 165),
236 (59, 120, 255),
237 (180, 0, 158),
238 (97, 214, 214),
239 (242, 242, 242),
240 ])
241});
242
243pub static STANDARD_PALETTE: Lazy<Palette> = Lazy::new(|| {
245 Palette::new(&[
246 (0, 0, 0),
247 (170, 0, 0),
248 (0, 170, 0),
249 (170, 85, 0),
250 (0, 0, 170),
251 (170, 0, 170),
252 (0, 170, 170),
253 (170, 170, 170),
254 (85, 85, 85),
255 (255, 85, 85),
256 (85, 255, 85),
257 (255, 255, 85),
258 (85, 85, 255),
259 (255, 85, 255),
260 (85, 255, 255),
261 (255, 255, 255),
262 ])
263});
264
265pub static EIGHT_BIT_PALETTE: Lazy<Palette> = Lazy::new(|| {
267 Palette::new(&[
268 (0, 0, 0),
270 (128, 0, 0),
271 (0, 128, 0),
272 (128, 128, 0),
273 (0, 0, 128),
274 (128, 0, 128),
275 (0, 128, 128),
276 (192, 192, 192),
277 (128, 128, 128),
278 (255, 0, 0),
279 (0, 255, 0),
280 (255, 255, 0),
281 (0, 0, 255),
282 (255, 0, 255),
283 (0, 255, 255),
284 (255, 255, 255),
285 (0, 0, 0),
287 (0, 0, 95),
288 (0, 0, 135),
289 (0, 0, 175),
290 (0, 0, 215),
291 (0, 0, 255),
292 (0, 95, 0),
293 (0, 95, 95),
294 (0, 95, 135),
295 (0, 95, 175),
296 (0, 95, 215),
297 (0, 95, 255),
298 (0, 135, 0),
299 (0, 135, 95),
300 (0, 135, 135),
301 (0, 135, 175),
302 (0, 135, 215),
303 (0, 135, 255),
304 (0, 175, 0),
305 (0, 175, 95),
306 (0, 175, 135),
307 (0, 175, 175),
308 (0, 175, 215),
309 (0, 175, 255),
310 (0, 215, 0),
311 (0, 215, 95),
312 (0, 215, 135),
313 (0, 215, 175),
314 (0, 215, 215),
315 (0, 215, 255),
316 (0, 255, 0),
317 (0, 255, 95),
318 (0, 255, 135),
319 (0, 255, 175),
320 (0, 255, 215),
321 (0, 255, 255),
322 (95, 0, 0),
323 (95, 0, 95),
324 (95, 0, 135),
325 (95, 0, 175),
326 (95, 0, 215),
327 (95, 0, 255),
328 (95, 95, 0),
329 (95, 95, 95),
330 (95, 95, 135),
331 (95, 95, 175),
332 (95, 95, 215),
333 (95, 95, 255),
334 (95, 135, 0),
335 (95, 135, 95),
336 (95, 135, 135),
337 (95, 135, 175),
338 (95, 135, 215),
339 (95, 135, 255),
340 (95, 175, 0),
341 (95, 175, 95),
342 (95, 175, 135),
343 (95, 175, 175),
344 (95, 175, 215),
345 (95, 175, 255),
346 (95, 215, 0),
347 (95, 215, 95),
348 (95, 215, 135),
349 (95, 215, 175),
350 (95, 215, 215),
351 (95, 215, 255),
352 (95, 255, 0),
353 (95, 255, 95),
354 (95, 255, 135),
355 (95, 255, 175),
356 (95, 255, 215),
357 (95, 255, 255),
358 (135, 0, 0),
359 (135, 0, 95),
360 (135, 0, 135),
361 (135, 0, 175),
362 (135, 0, 215),
363 (135, 0, 255),
364 (135, 95, 0),
365 (135, 95, 95),
366 (135, 95, 135),
367 (135, 95, 175),
368 (135, 95, 215),
369 (135, 95, 255),
370 (135, 135, 0),
371 (135, 135, 95),
372 (135, 135, 135),
373 (135, 135, 175),
374 (135, 135, 215),
375 (135, 135, 255),
376 (135, 175, 0),
377 (135, 175, 95),
378 (135, 175, 135),
379 (135, 175, 175),
380 (135, 175, 215),
381 (135, 175, 255),
382 (135, 215, 0),
383 (135, 215, 95),
384 (135, 215, 135),
385 (135, 215, 175),
386 (135, 215, 215),
387 (135, 215, 255),
388 (135, 255, 0),
389 (135, 255, 95),
390 (135, 255, 135),
391 (135, 255, 175),
392 (135, 255, 215),
393 (135, 255, 255),
394 (175, 0, 0),
395 (175, 0, 95),
396 (175, 0, 135),
397 (175, 0, 175),
398 (175, 0, 215),
399 (175, 0, 255),
400 (175, 95, 0),
401 (175, 95, 95),
402 (175, 95, 135),
403 (175, 95, 175),
404 (175, 95, 215),
405 (175, 95, 255),
406 (175, 135, 0),
407 (175, 135, 95),
408 (175, 135, 135),
409 (175, 135, 175),
410 (175, 135, 215),
411 (175, 135, 255),
412 (175, 175, 0),
413 (175, 175, 95),
414 (175, 175, 135),
415 (175, 175, 175),
416 (175, 175, 215),
417 (175, 175, 255),
418 (175, 215, 0),
419 (175, 215, 95),
420 (175, 215, 135),
421 (175, 215, 175),
422 (175, 215, 215),
423 (175, 215, 255),
424 (175, 255, 0),
425 (175, 255, 95),
426 (175, 255, 135),
427 (175, 255, 175),
428 (175, 255, 215),
429 (175, 255, 255),
430 (215, 0, 0),
431 (215, 0, 95),
432 (215, 0, 135),
433 (215, 0, 175),
434 (215, 0, 215),
435 (215, 0, 255),
436 (215, 95, 0),
437 (215, 95, 95),
438 (215, 95, 135),
439 (215, 95, 175),
440 (215, 95, 215),
441 (215, 95, 255),
442 (215, 135, 0),
443 (215, 135, 95),
444 (215, 135, 135),
445 (215, 135, 175),
446 (215, 135, 215),
447 (215, 135, 255),
448 (215, 175, 0),
449 (215, 175, 95),
450 (215, 175, 135),
451 (215, 175, 175),
452 (215, 175, 215),
453 (215, 175, 255),
454 (215, 215, 0),
455 (215, 215, 95),
456 (215, 215, 135),
457 (215, 215, 175),
458 (215, 215, 215),
459 (215, 215, 255),
460 (215, 255, 0),
461 (215, 255, 95),
462 (215, 255, 135),
463 (215, 255, 175),
464 (215, 255, 215),
465 (215, 255, 255),
466 (255, 0, 0),
467 (255, 0, 95),
468 (255, 0, 135),
469 (255, 0, 175),
470 (255, 0, 215),
471 (255, 0, 255),
472 (255, 95, 0),
473 (255, 95, 95),
474 (255, 95, 135),
475 (255, 95, 175),
476 (255, 95, 215),
477 (255, 95, 255),
478 (255, 135, 0),
479 (255, 135, 95),
480 (255, 135, 135),
481 (255, 135, 175),
482 (255, 135, 215),
483 (255, 135, 255),
484 (255, 175, 0),
485 (255, 175, 95),
486 (255, 175, 135),
487 (255, 175, 175),
488 (255, 175, 215),
489 (255, 175, 255),
490 (255, 215, 0),
491 (255, 215, 95),
492 (255, 215, 135),
493 (255, 215, 175),
494 (255, 215, 215),
495 (255, 215, 255),
496 (255, 255, 0),
497 (255, 255, 95),
498 (255, 255, 135),
499 (255, 255, 175),
500 (255, 255, 215),
501 (255, 255, 255),
502 (8, 8, 8),
504 (18, 18, 18),
505 (28, 28, 28),
506 (38, 38, 38),
507 (48, 48, 48),
508 (58, 58, 58),
509 (68, 68, 68),
510 (78, 78, 78),
511 (88, 88, 88),
512 (98, 98, 98),
513 (108, 108, 108),
514 (118, 118, 118),
515 (128, 128, 128),
516 (138, 138, 138),
517 (148, 148, 148),
518 (158, 158, 158),
519 (168, 168, 168),
520 (178, 178, 178),
521 (188, 188, 188),
522 (198, 198, 198),
523 (208, 208, 208),
524 (218, 218, 218),
525 (228, 228, 228),
526 (238, 238, 238),
527 ])
528});
529
530pub static ANSI_COLOR_NAMES: Lazy<HashMap<&'static str, u8>> = Lazy::new(|| {
537 let mut m = HashMap::new();
538 m.insert("black", 0);
540 m.insert("red", 1);
541 m.insert("green", 2);
542 m.insert("yellow", 3);
543 m.insert("blue", 4);
544 m.insert("magenta", 5);
545 m.insert("cyan", 6);
546 m.insert("white", 7);
547 m.insert("bright_black", 8);
548 m.insert("bright_red", 9);
549 m.insert("bright_green", 10);
550 m.insert("bright_yellow", 11);
551 m.insert("bright_blue", 12);
552 m.insert("bright_magenta", 13);
553 m.insert("bright_cyan", 14);
554 m.insert("bright_white", 15);
555 m.insert("grey0", 16);
557 m.insert("gray0", 16);
558 m.insert("navy_blue", 17);
559 m.insert("dark_blue", 18);
560 m.insert("blue3", 20);
561 m.insert("blue1", 21);
562 m.insert("dark_green", 22);
563 m.insert("deep_sky_blue4", 25);
564 m.insert("dodger_blue3", 26);
565 m.insert("dodger_blue2", 27);
566 m.insert("green4", 28);
567 m.insert("spring_green4", 29);
568 m.insert("turquoise4", 30);
569 m.insert("deep_sky_blue3", 32);
570 m.insert("dodger_blue1", 33);
571 m.insert("green3", 40);
572 m.insert("spring_green3", 41);
573 m.insert("dark_cyan", 36);
574 m.insert("light_sea_green", 37);
575 m.insert("deep_sky_blue2", 38);
576 m.insert("deep_sky_blue1", 39);
577 m.insert("spring_green2", 47);
578 m.insert("cyan3", 43);
579 m.insert("dark_turquoise", 44);
580 m.insert("turquoise2", 45);
581 m.insert("green1", 46);
582 m.insert("spring_green1", 48);
583 m.insert("medium_spring_green", 49);
584 m.insert("cyan2", 50);
585 m.insert("cyan1", 51);
586 m.insert("dark_red", 88);
587 m.insert("deep_pink4", 125);
588 m.insert("purple4", 55);
589 m.insert("purple3", 56);
590 m.insert("blue_violet", 57);
591 m.insert("orange4", 94);
592 m.insert("grey37", 59);
593 m.insert("gray37", 59);
594 m.insert("medium_purple4", 60);
595 m.insert("slate_blue3", 62);
596 m.insert("royal_blue1", 63);
597 m.insert("chartreuse4", 64);
598 m.insert("dark_sea_green4", 71);
599 m.insert("pale_turquoise4", 66);
600 m.insert("steel_blue", 67);
601 m.insert("steel_blue3", 68);
602 m.insert("cornflower_blue", 69);
603 m.insert("chartreuse3", 76);
604 m.insert("cadet_blue", 73);
605 m.insert("sky_blue3", 74);
606 m.insert("steel_blue1", 81);
607 m.insert("pale_green3", 114);
608 m.insert("sea_green3", 78);
609 m.insert("aquamarine3", 79);
610 m.insert("medium_turquoise", 80);
611 m.insert("chartreuse2", 112);
612 m.insert("sea_green2", 83);
613 m.insert("sea_green1", 85);
614 m.insert("aquamarine1", 122);
615 m.insert("dark_slate_gray2", 87);
616 m.insert("dark_magenta", 91);
617 m.insert("dark_violet", 128);
618 m.insert("purple", 129);
619 m.insert("light_pink4", 95);
620 m.insert("plum4", 96);
621 m.insert("medium_purple3", 98);
622 m.insert("slate_blue1", 99);
623 m.insert("yellow4", 106);
624 m.insert("wheat4", 101);
625 m.insert("grey53", 102);
626 m.insert("gray53", 102);
627 m.insert("light_slate_grey", 103);
628 m.insert("light_slate_gray", 103);
629 m.insert("medium_purple", 104);
630 m.insert("light_slate_blue", 105);
631 m.insert("dark_olive_green3", 149);
632 m.insert("dark_sea_green", 108);
633 m.insert("light_sky_blue3", 110);
634 m.insert("sky_blue2", 111);
635 m.insert("dark_sea_green3", 150);
636 m.insert("dark_slate_gray3", 116);
637 m.insert("sky_blue1", 117);
638 m.insert("chartreuse1", 118);
639 m.insert("light_green", 120);
640 m.insert("pale_green1", 156);
641 m.insert("dark_slate_gray1", 123);
642 m.insert("red3", 160);
643 m.insert("medium_violet_red", 126);
644 m.insert("magenta3", 164);
645 m.insert("dark_orange3", 166);
646 m.insert("indian_red", 167);
647 m.insert("hot_pink3", 168);
648 m.insert("medium_orchid3", 133);
649 m.insert("medium_orchid", 134);
650 m.insert("medium_purple2", 140);
651 m.insert("dark_goldenrod", 136);
652 m.insert("light_salmon3", 173);
653 m.insert("rosy_brown", 138);
654 m.insert("grey63", 139);
655 m.insert("gray63", 139);
656 m.insert("medium_purple1", 141);
657 m.insert("gold3", 178);
658 m.insert("dark_khaki", 143);
659 m.insert("navajo_white3", 144);
660 m.insert("grey69", 145);
661 m.insert("gray69", 145);
662 m.insert("light_steel_blue3", 146);
663 m.insert("light_steel_blue", 147);
664 m.insert("yellow3", 184);
665 m.insert("dark_sea_green2", 157);
666 m.insert("light_cyan3", 152);
667 m.insert("light_sky_blue1", 153);
668 m.insert("green_yellow", 154);
669 m.insert("dark_olive_green2", 155);
670 m.insert("dark_sea_green1", 193);
671 m.insert("pale_turquoise1", 159);
672 m.insert("deep_pink3", 162);
673 m.insert("magenta2", 200);
674 m.insert("hot_pink2", 169);
675 m.insert("orchid", 170);
676 m.insert("medium_orchid1", 207);
677 m.insert("orange3", 172);
678 m.insert("light_pink3", 174);
679 m.insert("pink3", 175);
680 m.insert("plum3", 176);
681 m.insert("violet", 177);
682 m.insert("light_goldenrod3", 179);
683 m.insert("tan", 180);
684 m.insert("misty_rose3", 181);
685 m.insert("thistle3", 182);
686 m.insert("plum2", 183);
687 m.insert("khaki3", 185);
688 m.insert("light_goldenrod2", 222);
689 m.insert("light_yellow3", 187);
690 m.insert("grey84", 188);
691 m.insert("gray84", 188);
692 m.insert("light_steel_blue1", 189);
693 m.insert("yellow2", 190);
694 m.insert("dark_olive_green1", 192);
695 m.insert("honeydew2", 194);
696 m.insert("light_cyan1", 195);
697 m.insert("red1", 196);
698 m.insert("deep_pink2", 197);
699 m.insert("deep_pink1", 199);
700 m.insert("magenta1", 201);
701 m.insert("orange_red1", 202);
702 m.insert("indian_red1", 204);
703 m.insert("hot_pink", 206);
704 m.insert("dark_orange", 208);
705 m.insert("salmon1", 209);
706 m.insert("light_coral", 210);
707 m.insert("pale_violet_red1", 211);
708 m.insert("orchid2", 212);
709 m.insert("orchid1", 213);
710 m.insert("orange1", 214);
711 m.insert("sandy_brown", 215);
712 m.insert("light_salmon1", 216);
713 m.insert("light_pink1", 217);
714 m.insert("pink1", 218);
715 m.insert("plum1", 219);
716 m.insert("gold1", 220);
717 m.insert("navajo_white1", 223);
718 m.insert("misty_rose1", 224);
719 m.insert("thistle1", 225);
720 m.insert("yellow1", 226);
721 m.insert("light_goldenrod1", 227);
722 m.insert("khaki1", 228);
723 m.insert("wheat1", 229);
724 m.insert("cornsilk1", 230);
725 m.insert("grey100", 231);
726 m.insert("gray100", 231);
727 m.insert("grey3", 232);
728 m.insert("gray3", 232);
729 m.insert("grey7", 233);
730 m.insert("gray7", 233);
731 m.insert("grey11", 234);
732 m.insert("gray11", 234);
733 m.insert("grey15", 235);
734 m.insert("gray15", 235);
735 m.insert("grey19", 236);
736 m.insert("gray19", 236);
737 m.insert("grey23", 237);
738 m.insert("gray23", 237);
739 m.insert("grey27", 238);
740 m.insert("gray27", 238);
741 m.insert("grey30", 239);
742 m.insert("gray30", 239);
743 m.insert("grey35", 240);
744 m.insert("gray35", 240);
745 m.insert("grey39", 241);
746 m.insert("gray39", 241);
747 m.insert("grey42", 242);
748 m.insert("gray42", 242);
749 m.insert("grey46", 243);
750 m.insert("gray46", 243);
751 m.insert("grey50", 244);
752 m.insert("gray50", 244);
753 m.insert("grey54", 245);
754 m.insert("gray54", 245);
755 m.insert("grey58", 246);
756 m.insert("gray58", 246);
757 m.insert("grey62", 247);
758 m.insert("gray62", 247);
759 m.insert("grey66", 248);
760 m.insert("gray66", 248);
761 m.insert("grey70", 249);
762 m.insert("gray70", 249);
763 m.insert("grey74", 250);
764 m.insert("gray74", 250);
765 m.insert("grey78", 251);
766 m.insert("gray78", 251);
767 m.insert("grey82", 252);
768 m.insert("gray82", 252);
769 m.insert("grey85", 253);
770 m.insert("gray85", 253);
771 m.insert("grey89", 254);
772 m.insert("gray89", 254);
773 m.insert("grey93", 255);
774 m.insert("gray93", 255);
775 m.insert("grey", 8);
777 m.insert("gray", 8);
778 m
779});
780
781#[derive(Debug, Clone, PartialEq, Eq, Hash)]
808pub struct Color {
809 pub name: String,
811 pub color_type: ColorType,
813 pub number: Option<u8>,
815 pub triplet: Option<ColorTriplet>,
817}
818
819impl Default for Color {
820 fn default() -> Self {
821 Self::default_color()
822 }
823}
824
825impl Color {
826 pub fn new(
828 name: impl Into<String>,
829 color_type: ColorType,
830 number: Option<u8>,
831 triplet: Option<ColorTriplet>,
832 ) -> Self {
833 Self {
834 name: name.into(),
835 color_type,
836 number,
837 triplet,
838 }
839 }
840
841 pub fn default_color() -> Self {
843 Self::new("default", ColorType::Default, None, None)
844 }
845
846 pub fn from_ansi(number: u8) -> Self {
848 let color_type = if number < 16 {
849 ColorType::Standard
850 } else {
851 ColorType::EightBit
852 };
853 Self::new(format!("color({})", number), color_type, Some(number), None)
854 }
855
856 pub fn from_triplet(triplet: ColorTriplet) -> Self {
858 Self::new(triplet.hex(), ColorType::TrueColor, None, Some(triplet))
859 }
860
861 pub fn from_rgb(red: u8, green: u8, blue: u8) -> Self {
863 Self::from_triplet(ColorTriplet::new(red, green, blue))
864 }
865
866 pub fn system(&self) -> ColorSystem {
868 self.color_type.system()
869 }
870
871 pub fn is_system_defined(&self) -> bool {
873 matches!(
874 self.color_type.system(),
875 ColorSystem::Standard | ColorSystem::Windows
876 )
877 }
878
879 pub fn is_default(&self) -> bool {
881 self.color_type == ColorType::Default
882 }
883
884 pub fn get_truecolor(&self, foreground: bool) -> ColorTriplet {
889 match self.color_type {
890 ColorType::TrueColor => self.triplet.unwrap_or_default(),
891 ColorType::EightBit => {
892 let number = self.number.unwrap_or(0) as usize;
893 EIGHT_BIT_PALETTE.get(number).unwrap_or_default()
894 }
895 ColorType::Standard => {
896 let number = self.number.unwrap_or(0) as usize;
897 STANDARD_PALETTE.get(number).unwrap_or_default()
898 }
899 ColorType::Windows => {
900 let number = self.number.unwrap_or(0) as usize;
901 WINDOWS_PALETTE.get(number).unwrap_or_default()
902 }
903 ColorType::Default => {
904 if foreground {
906 ColorTriplet::new(255, 255, 255) } else {
908 ColorTriplet::new(0, 0, 0) }
910 }
911 }
912 }
913
914 pub fn parse(color: &str) -> Result<Self, ParseError> {
935 let original_color = color;
936 let color = color.to_lowercase();
937 let color = color.trim();
938
939 if color == "default" {
941 return Ok(Self::default_color());
942 }
943
944 if let Some(&number) = ANSI_COLOR_NAMES.get(color) {
946 let color_type = if number < 16 {
947 ColorType::Standard
948 } else {
949 ColorType::EightBit
950 };
951 return Ok(Self::new(color.to_string(), color_type, Some(number), None));
952 }
953
954 if let Some(hex) = color.strip_prefix('#') {
956 return Self::parse_hex(hex, original_color);
957 }
958
959 if let Some(inner) = color.strip_prefix("rgb(").and_then(|s| s.strip_suffix(')')) {
961 return Self::parse_rgb_string(inner, original_color);
962 }
963
964 if let Some(inner) = color
966 .strip_prefix("color(")
967 .and_then(|s| s.strip_suffix(')'))
968 {
969 return Self::parse_color_number(inner, original_color);
970 }
971
972 Err(ParseError::invalid_color(format!(
973 "{:?} is not a valid color",
974 original_color
975 )))
976 }
977
978 fn parse_hex(hex: &str, original: &str) -> Result<Self, ParseError> {
979 let make_err =
980 || ParseError::invalid_color(format!("{:?} is not a valid hex color", original));
981
982 match hex.len() {
983 3 => {
984 let chars: Vec<char> = hex.chars().collect();
986 let r = u8::from_str_radix(&chars[0].to_string(), 16).map_err(|_| make_err())? * 17;
987 let g = u8::from_str_radix(&chars[1].to_string(), 16).map_err(|_| make_err())? * 17;
988 let b = u8::from_str_radix(&chars[2].to_string(), 16).map_err(|_| make_err())? * 17;
989 let triplet = ColorTriplet::new(r, g, b);
990 Ok(Self::new(
991 triplet.hex(),
992 ColorType::TrueColor,
993 None,
994 Some(triplet),
995 ))
996 }
997 6 => {
998 let r = u8::from_str_radix(&hex[0..2], 16).map_err(|_| make_err())?;
999 let g = u8::from_str_radix(&hex[2..4], 16).map_err(|_| make_err())?;
1000 let b = u8::from_str_radix(&hex[4..6], 16).map_err(|_| make_err())?;
1001 let triplet = ColorTriplet::new(r, g, b);
1002 Ok(Self::new(
1003 triplet.hex(),
1004 ColorType::TrueColor,
1005 None,
1006 Some(triplet),
1007 ))
1008 }
1009 _ => Err(make_err()),
1010 }
1011 }
1012
1013 fn parse_rgb_string(inner: &str, original: &str) -> Result<Self, ParseError> {
1014 let components: Vec<&str> = inner.split(',').map(|s| s.trim()).collect();
1015 if components.len() != 3 {
1016 return Err(ParseError::invalid_color(format!(
1017 "expected three components in {:?}",
1018 original
1019 )));
1020 }
1021
1022 let parse_component = |s: &str| -> Result<u8, ParseError> {
1023 s.parse::<u16>()
1024 .map_err(|_| {
1025 ParseError::invalid_color(format!("invalid RGB component in {:?}", original))
1026 })
1027 .and_then(|v| {
1028 if v > 255 {
1029 Err(ParseError::invalid_color(format!(
1030 "color components must be <= 255 in {:?}",
1031 original
1032 )))
1033 } else {
1034 Ok(v as u8)
1035 }
1036 })
1037 };
1038
1039 let r = parse_component(components[0])?;
1040 let g = parse_component(components[1])?;
1041 let b = parse_component(components[2])?;
1042
1043 let triplet = ColorTriplet::new(r, g, b);
1044 Ok(Self::new(
1045 format!("rgb({},{},{})", r, g, b),
1046 ColorType::TrueColor,
1047 None,
1048 Some(triplet),
1049 ))
1050 }
1051
1052 fn parse_color_number(inner: &str, original: &str) -> Result<Self, ParseError> {
1053 let number: u16 = inner.trim().parse().map_err(|_| {
1054 ParseError::invalid_color(format!("invalid color number in {:?}", original))
1055 })?;
1056
1057 if number > 255 {
1058 return Err(ParseError::invalid_color(format!(
1059 "color number must be <= 255 in {:?}",
1060 original
1061 )));
1062 }
1063
1064 let number = number as u8;
1065 let color_type = if number < 16 {
1066 ColorType::Standard
1067 } else {
1068 ColorType::EightBit
1069 };
1070
1071 Ok(Self::new(
1072 format!("color({})", number),
1073 color_type,
1074 Some(number),
1075 None,
1076 ))
1077 }
1078
1079 pub fn get_ansi_codes(&self, foreground: bool) -> Vec<String> {
1107 match self.color_type {
1108 ColorType::Default => {
1109 vec![if foreground { "39" } else { "49" }.to_string()]
1110 }
1111 ColorType::Standard | ColorType::Windows => {
1112 let number = self.number.unwrap_or(0);
1113 let (fore_base, back_base) = if number < 8 { (30, 40) } else { (90, 100) };
1114 let code = if foreground {
1115 fore_base + (number % 8) as u16
1116 } else {
1117 back_base + (number % 8) as u16
1118 };
1119 vec![code.to_string()]
1120 }
1121 ColorType::EightBit => {
1122 let number = self.number.unwrap_or(0);
1123 vec![
1124 if foreground { "38" } else { "48" }.to_string(),
1125 "5".to_string(),
1126 number.to_string(),
1127 ]
1128 }
1129 ColorType::TrueColor => {
1130 let triplet = self.triplet.unwrap_or_default();
1131 vec![
1132 if foreground { "38" } else { "48" }.to_string(),
1133 "2".to_string(),
1134 triplet.red.to_string(),
1135 triplet.green.to_string(),
1136 triplet.blue.to_string(),
1137 ]
1138 }
1139 }
1140 }
1141
1142 pub fn downgrade(&self, system: ColorSystem) -> Self {
1162 if self.color_type == ColorType::Default {
1164 return self.clone();
1165 }
1166
1167 let current_system = self.color_type.system();
1168
1169 if current_system.rank() <= system.rank() {
1172 return self.clone();
1173 }
1174
1175 match system {
1176 ColorSystem::TrueColor => self.clone(),
1177
1178 ColorSystem::EightBit => {
1179 if current_system == ColorSystem::TrueColor {
1181 let triplet = self.triplet.unwrap_or_default();
1182 let (_, l, s) = rgb_to_hls(triplet);
1183
1184 if s < 0.15 {
1186 let gray = (l * 25.0).round() as u8;
1187 let color_number = if gray == 0 {
1188 16
1189 } else if gray == 25 {
1190 231
1191 } else {
1192 231 + gray
1193 };
1194 return Self::new(
1195 self.name.clone(),
1196 ColorType::EightBit,
1197 Some(color_number),
1198 None,
1199 );
1200 }
1201
1202 let r = triplet.red as f64;
1204 let g = triplet.green as f64;
1205 let b = triplet.blue as f64;
1206
1207 let six_red = if r < 95.0 {
1208 r / 95.0
1209 } else {
1210 1.0 + (r - 95.0) / 40.0
1211 };
1212 let six_green = if g < 95.0 {
1213 g / 95.0
1214 } else {
1215 1.0 + (g - 95.0) / 40.0
1216 };
1217 let six_blue = if b < 95.0 {
1218 b / 95.0
1219 } else {
1220 1.0 + (b - 95.0) / 40.0
1221 };
1222
1223 let color_number = 16
1224 + 36 * six_red.round() as u8
1225 + 6 * six_green.round() as u8
1226 + six_blue.round() as u8;
1227
1228 Self::new(
1229 self.name.clone(),
1230 ColorType::EightBit,
1231 Some(color_number),
1232 None,
1233 )
1234 } else {
1235 self.clone()
1236 }
1237 }
1238
1239 ColorSystem::Standard => {
1240 let triplet = match self.color_type {
1242 ColorType::TrueColor => self.triplet.unwrap_or_default(),
1243 ColorType::EightBit => {
1244 let number = self.number.unwrap_or(0) as usize;
1245 EIGHT_BIT_PALETTE.get(number).unwrap_or_default()
1246 }
1247 _ => return self.clone(),
1248 };
1249
1250 let color_number = STANDARD_PALETTE.match_color(triplet) as u8;
1251 Self::new(
1252 self.name.clone(),
1253 ColorType::Standard,
1254 Some(color_number),
1255 None,
1256 )
1257 }
1258
1259 ColorSystem::Windows => {
1260 let triplet = match self.color_type {
1262 ColorType::TrueColor => self.triplet.unwrap_or_default(),
1263 ColorType::EightBit => {
1264 let number = self.number.unwrap_or(0) as usize;
1265 if number < 16 {
1266 return Self::new(
1267 self.name.clone(),
1268 ColorType::Windows,
1269 Some(number as u8),
1270 None,
1271 );
1272 }
1273 EIGHT_BIT_PALETTE.get(number).unwrap_or_default()
1274 }
1275 _ => return self.clone(),
1276 };
1277
1278 let color_number = WINDOWS_PALETTE.match_color(triplet) as u8;
1279 Self::new(
1280 self.name.clone(),
1281 ColorType::Windows,
1282 Some(color_number),
1283 None,
1284 )
1285 }
1286 }
1287 }
1288}
1289
1290fn rgb_to_hls(triplet: ColorTriplet) -> (f64, f64, f64) {
1294 let (r, g, b) = triplet.normalized();
1295
1296 let max_c = r.max(g).max(b);
1297 let min_c = r.min(g).min(b);
1298 let l = (max_c + min_c) / 2.0;
1299
1300 if (max_c - min_c).abs() < f64::EPSILON {
1301 return (0.0, l, 0.0);
1302 }
1303
1304 let s = if l <= 0.5 {
1305 (max_c - min_c) / (max_c + min_c)
1306 } else {
1307 (max_c - min_c) / (2.0 - max_c - min_c)
1308 };
1309
1310 let rc = (max_c - r) / (max_c - min_c);
1311 let gc = (max_c - g) / (max_c - min_c);
1312 let bc = (max_c - b) / (max_c - min_c);
1313
1314 let h = if (r - max_c).abs() < f64::EPSILON {
1315 bc - gc
1316 } else if (g - max_c).abs() < f64::EPSILON {
1317 2.0 + rc - bc
1318 } else {
1319 4.0 + gc - rc
1320 };
1321
1322 let h = (h / 6.0).rem_euclid(1.0);
1323
1324 (h, l, s)
1325}
1326
1327pub fn parse_rgb_hex(hex_color: &str) -> Result<ColorTriplet, ParseError> {
1329 if hex_color.len() != 6 {
1330 return Err(ParseError::invalid_color("hex color must be 6 characters"));
1331 }
1332 let r = u8::from_str_radix(&hex_color[0..2], 16)
1333 .map_err(|_| ParseError::invalid_color("invalid hex color"))?;
1334 let g = u8::from_str_radix(&hex_color[2..4], 16)
1335 .map_err(|_| ParseError::invalid_color("invalid hex color"))?;
1336 let b = u8::from_str_radix(&hex_color[4..6], 16)
1337 .map_err(|_| ParseError::invalid_color("invalid hex color"))?;
1338 Ok(ColorTriplet::new(r, g, b))
1339}
1340
1341pub fn blend_rgb(color1: ColorTriplet, color2: ColorTriplet, cross_fade: f64) -> ColorTriplet {
1349 let r1 = color1.red as f64;
1350 let g1 = color1.green as f64;
1351 let b1 = color1.blue as f64;
1352 let r2 = color2.red as f64;
1353 let g2 = color2.green as f64;
1354 let b2 = color2.blue as f64;
1355
1356 ColorTriplet::new(
1357 (r1 + (r2 - r1) * cross_fade) as u8,
1358 (g1 + (g2 - g1) * cross_fade) as u8,
1359 (b1 + (b2 - b1) * cross_fade) as u8,
1360 )
1361}
1362
1363#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1376pub enum SimpleColor {
1377 #[default]
1379 Default,
1380 Standard(u8),
1382 EightBit(u8),
1384 Rgb { r: u8, g: u8, b: u8 },
1386}
1387
1388impl SimpleColor {
1389 pub fn rgb(r: u8, g: u8, b: u8) -> Self {
1391 SimpleColor::Rgb { r, g, b }
1392 }
1393
1394 pub fn parse(s: &str) -> Option<Self> {
1398 let s = s.trim().to_lowercase();
1399
1400 if let Some(hex) = s.strip_prefix('#') {
1402 return Self::parse_hex(hex);
1403 }
1404
1405 if let Some(inner) = s.strip_prefix("rgb(").and_then(|s| s.strip_suffix(')')) {
1407 let parts: Vec<&str> = inner.split(',').map(|p| p.trim()).collect();
1408 if parts.len() == 3 {
1409 let r = parts[0].parse().ok()?;
1410 let g = parts[1].parse().ok()?;
1411 let b = parts[2].parse().ok()?;
1412 return Some(SimpleColor::Rgb { r, g, b });
1413 }
1414 return None;
1415 }
1416
1417 if let Some(inner) = s.strip_prefix("color(").and_then(|s| s.strip_suffix(')')) {
1419 let n: u8 = inner.trim().parse().ok()?;
1420 return Some(if n < 16 {
1421 SimpleColor::Standard(n)
1422 } else {
1423 SimpleColor::EightBit(n)
1424 });
1425 }
1426
1427 if let Some(&number) = ANSI_COLOR_NAMES.get(s.as_str()) {
1429 return Some(if number < 16 {
1430 SimpleColor::Standard(number)
1431 } else {
1432 SimpleColor::EightBit(number)
1433 });
1434 }
1435
1436 if s == "default" {
1437 return Some(SimpleColor::Default);
1438 }
1439
1440 None
1441 }
1442
1443 fn parse_hex(hex: &str) -> Option<Self> {
1444 let hex = hex.trim_start_matches('#');
1445 match hex.len() {
1446 3 => {
1447 let r = u8::from_str_radix(&hex[0..1], 16).ok()? * 17;
1448 let g = u8::from_str_radix(&hex[1..2], 16).ok()? * 17;
1449 let b = u8::from_str_radix(&hex[2..3], 16).ok()? * 17;
1450 Some(SimpleColor::Rgb { r, g, b })
1451 }
1452 6 => {
1453 let r = u8::from_str_radix(&hex[0..2], 16).ok()?;
1454 let g = u8::from_str_radix(&hex[2..4], 16).ok()?;
1455 let b = u8::from_str_radix(&hex[4..6], 16).ok()?;
1456 Some(SimpleColor::Rgb { r, g, b })
1457 }
1458 _ => None,
1459 }
1460 }
1461
1462 pub fn to_color(&self) -> Color {
1464 match self {
1465 SimpleColor::Default => Color::default_color(),
1466 SimpleColor::Standard(n) => Color::from_ansi(*n),
1467 SimpleColor::EightBit(n) => Color::from_ansi(*n),
1468 SimpleColor::Rgb { r, g, b } => Color::from_rgb(*r, *g, *b),
1469 }
1470 }
1471
1472 pub fn get_ansi_codes(&self, foreground: bool) -> Vec<String> {
1474 self.to_color().get_ansi_codes(foreground)
1475 }
1476
1477 pub fn downgrade(&self, system: ColorSystem) -> Self {
1487 self.to_color().downgrade(system).into()
1488 }
1489
1490 pub fn get_hex(&self) -> String {
1495 match self {
1496 SimpleColor::Rgb { r, g, b } => format!("#{:02x}{:02x}{:02x}", r, g, b),
1497 SimpleColor::Default => "#ffffff".to_string(), SimpleColor::Standard(n) => {
1499 let triplet = STANDARD_PALETTE.get(*n as usize).unwrap_or_default();
1500 triplet.hex()
1501 }
1502 SimpleColor::EightBit(n) => {
1503 let triplet = EIGHT_BIT_PALETTE.get(*n as usize).unwrap_or_default();
1504 triplet.hex()
1505 }
1506 }
1507 }
1508}
1509
1510impl From<SimpleColor> for Color {
1511 fn from(simple: SimpleColor) -> Self {
1512 simple.to_color()
1513 }
1514}
1515
1516impl From<Color> for SimpleColor {
1517 fn from(color: Color) -> Self {
1518 match color.color_type {
1519 ColorType::Default => SimpleColor::Default,
1520 ColorType::Standard | ColorType::Windows => {
1521 SimpleColor::Standard(color.number.unwrap_or(0))
1522 }
1523 ColorType::EightBit => SimpleColor::EightBit(color.number.unwrap_or(0)),
1524 ColorType::TrueColor => {
1525 let t = color.triplet.unwrap_or_default();
1526 SimpleColor::Rgb {
1527 r: t.red,
1528 g: t.green,
1529 b: t.blue,
1530 }
1531 }
1532 }
1533 }
1534}
1535
1536#[cfg(test)]
1541mod tests {
1542 use super::*;
1543
1544 #[test]
1547 fn test_color_triplet_new() {
1548 let t = ColorTriplet::new(255, 128, 64);
1549 assert_eq!(t.red, 255);
1550 assert_eq!(t.green, 128);
1551 assert_eq!(t.blue, 64);
1552 }
1553
1554 #[test]
1555 fn test_color_triplet_hex() {
1556 assert_eq!(ColorTriplet::new(255, 0, 0).hex(), "#ff0000");
1557 assert_eq!(ColorTriplet::new(0, 255, 0).hex(), "#00ff00");
1558 assert_eq!(ColorTriplet::new(0, 0, 255).hex(), "#0000ff");
1559 assert_eq!(ColorTriplet::new(18, 52, 86).hex(), "#123456");
1560 }
1561
1562 #[test]
1563 fn test_color_triplet_rgb() {
1564 assert_eq!(ColorTriplet::new(255, 0, 0).rgb(), "rgb(255,0,0)");
1565 assert_eq!(ColorTriplet::new(128, 64, 32).rgb(), "rgb(128,64,32)");
1566 }
1567
1568 #[test]
1569 fn test_color_triplet_normalized() {
1570 let (r, g, b) = ColorTriplet::new(255, 127, 0).normalized();
1571 assert!((r - 1.0).abs() < 0.001);
1572 assert!((g - 0.498).abs() < 0.01);
1573 assert!((b - 0.0).abs() < 0.001);
1574 }
1575
1576 #[test]
1579 fn test_palette_match() {
1580 let palette = Palette::new(&[(0, 0, 0), (255, 255, 255), (255, 0, 0)]);
1581
1582 assert_eq!(palette.match_color(ColorTriplet::new(0, 0, 0)), 0);
1584 assert_eq!(palette.match_color(ColorTriplet::new(255, 255, 255)), 1);
1585 assert_eq!(palette.match_color(ColorTriplet::new(255, 0, 0)), 2);
1586
1587 assert_eq!(palette.match_color(ColorTriplet::new(10, 10, 10)), 0);
1589
1590 assert_eq!(palette.match_color(ColorTriplet::new(240, 240, 240)), 1);
1592 }
1593
1594 #[test]
1597 fn test_parse_named() {
1598 let red = Color::parse("red").unwrap();
1599 assert_eq!(red.color_type, ColorType::Standard);
1600 assert_eq!(red.number, Some(1));
1601
1602 let bright_blue = Color::parse("bright_blue").unwrap();
1603 assert_eq!(bright_blue.color_type, ColorType::Standard);
1604 assert_eq!(bright_blue.number, Some(12));
1605
1606 let blue = Color::parse("BLUE").unwrap();
1608 assert_eq!(blue.number, Some(4));
1609
1610 let orchid = Color::parse("orchid").unwrap();
1612 assert_eq!(orchid.color_type, ColorType::EightBit);
1613 assert_eq!(orchid.number, Some(170));
1614 }
1615
1616 #[test]
1617 fn test_parse_hex() {
1618 let red = Color::parse("#ff0000").unwrap();
1619 assert_eq!(red.color_type, ColorType::TrueColor);
1620 assert_eq!(red.triplet, Some(ColorTriplet::new(255, 0, 0)));
1621
1622 let white = Color::parse("#fff").unwrap();
1624 assert_eq!(white.triplet, Some(ColorTriplet::new(255, 255, 255)));
1625
1626 let color = Color::parse("#AbCdEf").unwrap();
1628 assert_eq!(color.triplet, Some(ColorTriplet::new(171, 205, 239)));
1629 }
1630
1631 #[test]
1632 fn test_parse_rgb() {
1633 let red = Color::parse("rgb(255,0,0)").unwrap();
1634 assert_eq!(red.color_type, ColorType::TrueColor);
1635 assert_eq!(red.triplet, Some(ColorTriplet::new(255, 0, 0)));
1636
1637 let green = Color::parse("rgb(0, 255, 0)").unwrap();
1639 assert_eq!(green.triplet, Some(ColorTriplet::new(0, 255, 0)));
1640 }
1641
1642 #[test]
1643 fn test_parse_color_number() {
1644 let standard = Color::parse("color(1)").unwrap();
1645 assert_eq!(standard.color_type, ColorType::Standard);
1646 assert_eq!(standard.number, Some(1));
1647
1648 let extended = Color::parse("color(196)").unwrap();
1649 assert_eq!(extended.color_type, ColorType::EightBit);
1650 assert_eq!(extended.number, Some(196));
1651 }
1652
1653 #[test]
1654 fn test_parse_default() {
1655 let default = Color::parse("default").unwrap();
1656 assert_eq!(default.color_type, ColorType::Default);
1657 }
1658
1659 #[test]
1660 fn test_parse_invalid() {
1661 assert!(Color::parse("not_a_color").is_err());
1662 assert!(Color::parse("#gggggg").is_err());
1663 assert!(Color::parse("rgb(256,0,0)").is_err());
1664 assert!(Color::parse("color(256)").is_err());
1665 }
1666
1667 #[test]
1670 fn test_ansi_codes_standard() {
1671 let black = Color::parse("black").unwrap();
1672 assert_eq!(black.get_ansi_codes(true), vec!["30"]);
1673 assert_eq!(black.get_ansi_codes(false), vec!["40"]);
1674
1675 let red = Color::parse("red").unwrap();
1676 assert_eq!(red.get_ansi_codes(true), vec!["31"]);
1677 assert_eq!(red.get_ansi_codes(false), vec!["41"]);
1678
1679 let bright_red = Color::parse("bright_red").unwrap();
1680 assert_eq!(bright_red.get_ansi_codes(true), vec!["91"]);
1681 assert_eq!(bright_red.get_ansi_codes(false), vec!["101"]);
1682 }
1683
1684 #[test]
1685 fn test_ansi_codes_eight_bit() {
1686 let color = Color::parse("color(196)").unwrap();
1687 assert_eq!(color.get_ansi_codes(true), vec!["38", "5", "196"]);
1688 assert_eq!(color.get_ansi_codes(false), vec!["48", "5", "196"]);
1689 }
1690
1691 #[test]
1692 fn test_ansi_codes_truecolor() {
1693 let color = Color::parse("#ff8000").unwrap();
1694 assert_eq!(
1695 color.get_ansi_codes(true),
1696 vec!["38", "2", "255", "128", "0"]
1697 );
1698 assert_eq!(
1699 color.get_ansi_codes(false),
1700 vec!["48", "2", "255", "128", "0"]
1701 );
1702 }
1703
1704 #[test]
1705 fn test_ansi_codes_default() {
1706 let default = Color::default_color();
1707 assert_eq!(default.get_ansi_codes(true), vec!["39"]);
1708 assert_eq!(default.get_ansi_codes(false), vec!["49"]);
1709 }
1710
1711 #[test]
1714 fn test_downgrade_truecolor_to_eight_bit() {
1715 let rgb = Color::from_rgb(255, 0, 0);
1716 let downgraded = rgb.downgrade(ColorSystem::EightBit);
1717 assert_eq!(downgraded.color_type, ColorType::EightBit);
1718 assert!(downgraded.number.is_some());
1720 }
1721
1722 #[test]
1723 fn test_downgrade_to_standard() {
1724 let rgb = Color::from_rgb(255, 0, 0);
1725 let downgraded = rgb.downgrade(ColorSystem::Standard);
1726 assert_eq!(downgraded.color_type, ColorType::Standard);
1727 let num = downgraded.number.unwrap();
1729 assert!(num == 1 || num == 9);
1730 }
1731
1732 #[test]
1733 fn test_downgrade_grayscale() {
1734 let gray = Color::from_rgb(128, 128, 128);
1736 let downgraded = gray.downgrade(ColorSystem::EightBit);
1737 assert_eq!(downgraded.color_type, ColorType::EightBit);
1738 let num = downgraded.number.unwrap();
1740 assert!(num >= 232 || num == 16 || num == 231);
1741 }
1742
1743 #[test]
1744 fn test_downgrade_no_change() {
1745 let default = Color::default_color();
1747 let downgraded = default.downgrade(ColorSystem::Standard);
1748 assert_eq!(downgraded.color_type, ColorType::Default);
1749
1750 let standard = Color::parse("red").unwrap();
1752 let downgraded = standard.downgrade(ColorSystem::Standard);
1753 assert_eq!(downgraded.number, Some(1));
1754 }
1755
1756 #[test]
1757 fn test_downgrade_to_windows() {
1758 let rgb = Color::from_rgb(255, 0, 0);
1761 let downgraded = rgb.downgrade(ColorSystem::Windows);
1762 assert_eq!(downgraded.color_type, ColorType::Windows);
1763 assert!(downgraded.number.is_some());
1765
1766 let eight_bit = Color::from_ansi(196); let downgraded = eight_bit.downgrade(ColorSystem::Windows);
1769 assert_eq!(downgraded.color_type, ColorType::Windows);
1770 assert!(downgraded.number.is_some());
1771 }
1772
1773 #[test]
1776 fn test_simple_color_parse_named() {
1777 assert_eq!(SimpleColor::parse("red"), Some(SimpleColor::Standard(1)));
1778 assert_eq!(SimpleColor::parse("BLUE"), Some(SimpleColor::Standard(4)));
1779 }
1780
1781 #[test]
1782 fn test_simple_color_parse_hex() {
1783 assert_eq!(
1784 SimpleColor::parse("#ff0000"),
1785 Some(SimpleColor::Rgb { r: 255, g: 0, b: 0 })
1786 );
1787 assert_eq!(
1788 SimpleColor::parse("#f00"),
1789 Some(SimpleColor::Rgb { r: 255, g: 0, b: 0 })
1790 );
1791 }
1792
1793 #[test]
1794 fn test_simple_color_to_color() {
1795 let simple = SimpleColor::Standard(1);
1796 let color = simple.to_color();
1797 assert_eq!(color.color_type, ColorType::Standard);
1798 assert_eq!(color.number, Some(1));
1799 }
1800
1801 #[test]
1804 fn test_rgb_to_hls() {
1805 let (h, l, s) = rgb_to_hls(ColorTriplet::new(255, 0, 0));
1807 assert!((h - 0.0).abs() < 0.01);
1808 assert!((l - 0.5).abs() < 0.01);
1809 assert!((s - 1.0).abs() < 0.01);
1810
1811 let (_, _, s) = rgb_to_hls(ColorTriplet::new(255, 255, 255));
1813 assert!(s < 0.01);
1814
1815 let (_, _, s) = rgb_to_hls(ColorTriplet::new(0, 0, 0));
1817 assert!(s < 0.01);
1818 }
1819
1820 #[test]
1823 fn test_blend_rgb() {
1824 let black = ColorTriplet::new(0, 0, 0);
1825 let white = ColorTriplet::new(255, 255, 255);
1826
1827 let mid = blend_rgb(black, white, 0.5);
1828 assert_eq!(mid.red, 127);
1829 assert_eq!(mid.green, 127);
1830 assert_eq!(mid.blue, 127);
1831
1832 let quarter = blend_rgb(black, white, 0.25);
1833 assert_eq!(quarter.red, 63);
1834 }
1835
1836 #[test]
1839 fn test_palette_sizes() {
1840 assert_eq!(STANDARD_PALETTE.len(), 16);
1841 assert_eq!(EIGHT_BIT_PALETTE.len(), 256);
1842 assert_eq!(WINDOWS_PALETTE.len(), 16);
1843 }
1844
1845 #[test]
1846 fn test_ansi_color_names_coverage() {
1847 assert!(ANSI_COLOR_NAMES.contains_key("red"));
1849 assert!(ANSI_COLOR_NAMES.contains_key("green"));
1850 assert!(ANSI_COLOR_NAMES.contains_key("blue"));
1851 assert!(ANSI_COLOR_NAMES.contains_key("bright_red"));
1852 assert!(ANSI_COLOR_NAMES.contains_key("grey"));
1853 assert!(ANSI_COLOR_NAMES.contains_key("gray")); assert!(ANSI_COLOR_NAMES.contains_key("orchid"));
1855 assert!(ANSI_COLOR_NAMES.contains_key("grey93"));
1856 }
1857}