1use crate::terminal_setup::detector::TerminalType;
7use anyhow::{Result, anyhow};
8
9pub struct VTCodeDarkTheme {
11 pub background: &'static str,
12 pub foreground: &'static str,
13 pub cursor: &'static str,
14 pub selection_bg: &'static str,
15 pub black: &'static str,
17 pub red: &'static str,
18 pub green: &'static str,
19 pub yellow: &'static str,
20 pub blue: &'static str,
21 pub magenta: &'static str,
22 pub cyan: &'static str,
23 pub white: &'static str,
24 pub bright_black: &'static str,
26 pub bright_red: &'static str,
27 pub bright_green: &'static str,
28 pub bright_yellow: &'static str,
29 pub bright_blue: &'static str,
30 pub bright_magenta: &'static str,
31 pub bright_cyan: &'static str,
32 pub bright_white: &'static str,
33}
34
35impl Default for VTCodeDarkTheme {
36 fn default() -> Self {
37 Self {
38 background: "#1e1e1e",
39 foreground: "#d4d4d4",
40 cursor: "#ffffff",
41 selection_bg: "#264f78",
42 black: "#000000",
44 red: "#cd3131",
45 green: "#0dbc79",
46 yellow: "#e5e510",
47 blue: "#2472c8",
48 magenta: "#bc3fbc",
49 cyan: "#11a8cd",
50 white: "#e5e5e5",
51 bright_black: "#666666",
53 bright_red: "#f14c4c",
54 bright_green: "#23d18b",
55 bright_yellow: "#f5f543",
56 bright_blue: "#3b8eea",
57 bright_magenta: "#d670d6",
58 bright_cyan: "#29b8db",
59 bright_white: "#ffffff",
60 }
61 }
62}
63
64impl VTCodeDarkTheme {
65 fn base16_colors(&self) -> [&'static str; 16] {
66 [
67 self.black,
68 self.red,
69 self.green,
70 self.yellow,
71 self.blue,
72 self.magenta,
73 self.cyan,
74 self.white,
75 self.bright_black,
76 self.bright_red,
77 self.bright_green,
78 self.bright_yellow,
79 self.bright_blue,
80 self.bright_magenta,
81 self.bright_cyan,
82 self.bright_white,
83 ]
84 }
85}
86
87#[derive(Clone, Copy, Debug)]
88struct Rgb {
89 r: u8,
90 g: u8,
91 b: u8,
92}
93
94#[derive(Clone, Copy, Debug)]
95struct Lab {
96 l: f64,
97 a: f64,
98 b: f64,
99}
100
101impl Rgb {
102 fn from_hex(hex: &str) -> Result<Self> {
103 let trimmed = hex.trim_start_matches('#');
104 if trimmed.len() != 6 {
105 return Err(anyhow!("Invalid hex color '{}': expected #RRGGBB", hex));
106 }
107
108 let r = u8::from_str_radix(&trimmed[0..2], 16)
109 .map_err(|_| anyhow!("Invalid red component in '{}'", hex))?;
110 let g = u8::from_str_radix(&trimmed[2..4], 16)
111 .map_err(|_| anyhow!("Invalid green component in '{}'", hex))?;
112 let b = u8::from_str_radix(&trimmed[4..6], 16)
113 .map_err(|_| anyhow!("Invalid blue component in '{}'", hex))?;
114
115 Ok(Self { r, g, b })
116 }
117
118 fn to_hex(self) -> String {
119 format!("#{:02x}{:02x}{:02x}", self.r, self.g, self.b)
120 }
121
122 fn to_lab(self) -> Lab {
123 let r = srgb_to_linear(self.r as f64 / 255.0);
124 let g = srgb_to_linear(self.g as f64 / 255.0);
125 let b = srgb_to_linear(self.b as f64 / 255.0);
126
127 let x = r * 0.412_456_4 + g * 0.357_576_1 + b * 0.180_437_5;
128 let y = r * 0.212_672_9 + g * 0.715_152_2 + b * 0.072_175;
129 let z = r * 0.019_333_9 + g * 0.119_192 + b * 0.950_304_1;
130
131 let fx = lab_f(x / 0.95047);
132 let fy = lab_f(y);
133 let fz = lab_f(z / 1.08883);
134
135 Lab {
136 l: 116.0 * fy - 16.0,
137 a: 500.0 * (fx - fy),
138 b: 200.0 * (fy - fz),
139 }
140 }
141
142 fn from_lab(lab: Lab) -> Self {
143 let fy = (lab.l + 16.0) / 116.0;
144 let fx = fy + (lab.a / 500.0);
145 let fz = fy - (lab.b / 200.0);
146
147 let x = 0.95047 * lab_f_inv(fx);
148 let y = lab_f_inv(fy);
149 let z = 1.08883 * lab_f_inv(fz);
150
151 let r_linear = x * 3.240_454_2 + y * -1.537_138_5 + z * -0.498_531_4;
152 let g_linear = x * -0.969_266 + y * 1.876_010_8 + z * 0.041_556;
153 let b_linear = x * 0.055_643_4 + y * -0.204_025_9 + z * 1.057_225_2;
154
155 Self {
156 r: to_u8(linear_to_srgb(r_linear)),
157 g: to_u8(linear_to_srgb(g_linear)),
158 b: to_u8(linear_to_srgb(b_linear)),
159 }
160 }
161}
162
163fn srgb_to_linear(channel: f64) -> f64 {
164 if channel <= 0.04045 {
165 channel / 12.92
166 } else {
167 ((channel + 0.055) / 1.055).powf(2.4)
168 }
169}
170
171fn linear_to_srgb(channel: f64) -> f64 {
172 if channel <= 0.0031308 {
173 12.92 * channel
174 } else {
175 1.055 * channel.powf(1.0 / 2.4) - 0.055
176 }
177}
178
179fn lab_f(value: f64) -> f64 {
180 if value > 216.0 / 24389.0 {
181 value.cbrt()
182 } else {
183 (24389.0 / 27.0 * value + 16.0) / 116.0
184 }
185}
186
187fn lab_f_inv(value: f64) -> f64 {
188 let cube = value * value * value;
189 if cube > 216.0 / 24389.0 {
190 cube
191 } else {
192 (116.0 * value - 16.0) / (24389.0 / 27.0)
193 }
194}
195
196fn to_u8(value: f64) -> u8 {
197 (value.clamp(0.0, 1.0) * 255.0).round() as u8
198}
199
200fn lerp_lab(t: f64, start: Lab, end: Lab) -> Lab {
201 Lab {
202 l: start.l + t * (end.l - start.l),
203 a: start.a + t * (end.a - start.a),
204 b: start.b + t * (end.b - start.b),
205 }
206}
207
208fn generate_256_palette(theme: &VTCodeDarkTheme, harmonious: bool) -> Result<Vec<Rgb>> {
209 let base16 = theme
210 .base16_colors()
211 .iter()
212 .map(|color| Rgb::from_hex(color))
213 .collect::<Result<Vec<_>>>()?;
214
215 let background = Rgb::from_hex(theme.background)?;
216 let foreground = Rgb::from_hex(theme.foreground)?;
217
218 let mut base8_lab = [
219 background.to_lab(),
220 base16[1].to_lab(),
221 base16[2].to_lab(),
222 base16[3].to_lab(),
223 base16[4].to_lab(),
224 base16[5].to_lab(),
225 base16[6].to_lab(),
226 foreground.to_lab(),
227 ];
228
229 let is_light_theme = base8_lab[7].l < base8_lab[0].l;
230 if is_light_theme && !harmonious {
231 base8_lab.swap(0, 7);
232 }
233
234 let mut palette = base16;
235
236 for r in 0..6 {
237 let t_r = r as f64 / 5.0;
238 let c0 = lerp_lab(t_r, base8_lab[0], base8_lab[1]);
239 let c1 = lerp_lab(t_r, base8_lab[2], base8_lab[3]);
240 let c2 = lerp_lab(t_r, base8_lab[4], base8_lab[5]);
241 let c3 = lerp_lab(t_r, base8_lab[6], base8_lab[7]);
242
243 for g in 0..6 {
244 let t_g = g as f64 / 5.0;
245 let c4 = lerp_lab(t_g, c0, c1);
246 let c5 = lerp_lab(t_g, c2, c3);
247
248 for b in 0..6 {
249 let t_b = b as f64 / 5.0;
250 let color = lerp_lab(t_b, c4, c5);
251 palette.push(Rgb::from_lab(color));
252 }
253 }
254 }
255
256 for shade in 0..24 {
257 let t = (shade as f64 + 1.0) / 25.0;
258 let color = lerp_lab(t, base8_lab[0], base8_lab[7]);
259 palette.push(Rgb::from_lab(color));
260 }
261
262 Ok(palette)
263}
264
265fn ghostty_palette_lines(palette: &[Rgb]) -> String {
266 palette
267 .iter()
268 .enumerate()
269 .map(|(index, color)| format!("palette = {index}={}", color.to_hex()))
270 .collect::<Vec<_>>()
271 .join("\n")
272}
273
274fn kitty_palette_lines(palette: &[Rgb]) -> String {
275 palette
276 .iter()
277 .enumerate()
278 .map(|(index, color)| format!("color{index} {}", color.to_hex()))
279 .collect::<Vec<_>>()
280 .join("\n")
281}
282
283pub fn generate_config(terminal: TerminalType) -> Result<String> {
285 let theme = VTCodeDarkTheme::default();
286 let generated_palette = generate_256_palette(&theme, false)?;
287
288 let config = match terminal {
289 TerminalType::Ghostty => {
290 let mut config = format!(
291 r#"# VT Code Dark Theme for Ghostty
292background = {background}
293foreground = {foreground}
294cursor-color = {cursor}
295selection-background = {selection_bg}
296"#,
297 background = theme.background,
298 foreground = theme.foreground,
299 cursor = theme.cursor,
300 selection_bg = theme.selection_bg,
301 );
302 config.push_str("\n# ANSI + 256-color palette generated from base colors\n");
303 config.push_str(&ghostty_palette_lines(&generated_palette));
304 config.push('\n');
305 config
306 }
307
308 TerminalType::Kitty => {
309 let mut config = format!(
310 r#"# VT Code Dark Theme for Kitty
311background {background}
312foreground {foreground}
313cursor {cursor}
314selection_background {selection_bg}
315"#,
316 background = theme.background,
317 foreground = theme.foreground,
318 cursor = theme.cursor,
319 selection_bg = theme.selection_bg,
320 );
321 config.push_str("\n# ANSI + 256-color palette generated from base colors\n");
322 config.push_str(&kitty_palette_lines(&generated_palette));
323 config.push('\n');
324 config
325 }
326
327 TerminalType::Alacritty => {
328 let mut config = format!(
329 r#"# VT Code Dark Theme for Alacritty
330[colors.primary]
331background = '{background}'
332foreground = '{foreground}'
333
334[colors.cursor]
335cursor = '{cursor}'
336
337[colors.selection]
338background = '{selection_bg}'
339
340[colors.normal]
341black = '{black}'
342red = '{red}'
343green = '{green}'
344yellow = '{yellow}'
345blue = '{blue}'
346magenta = '{magenta}'
347cyan = '{cyan}'
348white = '{white}'
349
350[colors.bright]
351black = '{bright_black}'
352red = '{bright_red}'
353green = '{bright_green}'
354yellow = '{bright_yellow}'
355blue = '{bright_blue}'
356magenta = '{bright_magenta}'
357cyan = '{bright_cyan}'
358white = '{bright_white}'
359"#,
360 background = theme.background,
361 foreground = theme.foreground,
362 cursor = theme.cursor,
363 selection_bg = theme.selection_bg,
364 black = theme.black,
365 red = theme.red,
366 green = theme.green,
367 yellow = theme.yellow,
368 blue = theme.blue,
369 magenta = theme.magenta,
370 cyan = theme.cyan,
371 white = theme.white,
372 bright_black = theme.bright_black,
373 bright_red = theme.bright_red,
374 bright_green = theme.bright_green,
375 bright_yellow = theme.bright_yellow,
376 bright_blue = theme.bright_blue,
377 bright_magenta = theme.bright_magenta,
378 bright_cyan = theme.bright_cyan,
379 bright_white = theme.bright_white,
380 );
381
382 config.push_str("\n# Extended indexed colors (16-255)\n");
383 for (index, color) in generated_palette.iter().enumerate().skip(16) {
384 config.push_str("[[colors.indexed_colors]]\n");
385 config.push_str(&format!("index = {index}\n"));
386 config.push_str(&format!("color = '{}'\n\n", color.to_hex()));
387 }
388
389 config
390 }
391
392 TerminalType::WezTerm => {
393 format!(
394 r#"-- VT Code Dark Theme for WezTerm
395return {{
396 colors = {{
397 background = "{background}",
398 foreground = "{foreground}",
399 cursor_bg = "{cursor}",
400 selection_bg = "{selection_bg}",
401 }},
402}}
403"#,
404 background = theme.background,
405 foreground = theme.foreground,
406 cursor = theme.cursor,
407 selection_bg = theme.selection_bg,
408 )
409 }
410
411 TerminalType::TerminalApp => {
412 r#"Terminal.app theme sync requires profile color configuration.
413Configure profile colors in Terminal → Settings → Profiles.
414"#
415 .to_string()
416 }
417
418 TerminalType::Xterm => {
419 r#"xterm theme sync is configured via X resources (e.g. ~/.Xresources).
420"#
421 .to_string()
422 }
423
424 TerminalType::Zed => {
425 format!(
426 r#"// VT Code Dark Theme for Zed
427{{
428 "theme": {{
429 "mode": "dark",
430 "terminal": {{
431 "background": "{background}",
432 "foreground": "{foreground}",
433 "cursor": "{cursor}",
434 "selectionBackground": "{selection_bg}",
435 "ansiBlack": "{black}",
436 "ansiRed": "{red}",
437 "ansiGreen": "{green}",
438 "ansiYellow": "{yellow}",
439 "ansiBlue": "{blue}",
440 "ansiMagenta": "{magenta}",
441 "ansiCyan": "{cyan}",
442 "ansiWhite": "{white}",
443 "ansiBrightBlack": "{bright_black}",
444 "ansiBrightRed": "{bright_red}",
445 "ansiBrightGreen": "{bright_green}",
446 "ansiBrightYellow": "{bright_yellow}",
447 "ansiBrightBlue": "{bright_blue}",
448 "ansiBrightMagenta": "{bright_magenta}",
449 "ansiBrightCyan": "{bright_cyan}",
450 "ansiBrightWhite": "{bright_white}"
451 }}
452 }}
453}}
454"#,
455 background = theme.background,
456 foreground = theme.foreground,
457 cursor = theme.cursor,
458 selection_bg = theme.selection_bg,
459 black = theme.black,
460 red = theme.red,
461 green = theme.green,
462 yellow = theme.yellow,
463 blue = theme.blue,
464 magenta = theme.magenta,
465 cyan = theme.cyan,
466 white = theme.white,
467 bright_black = theme.bright_black,
468 bright_red = theme.bright_red,
469 bright_green = theme.bright_green,
470 bright_yellow = theme.bright_yellow,
471 bright_blue = theme.bright_blue,
472 bright_magenta = theme.bright_magenta,
473 bright_cyan = theme.bright_cyan,
474 bright_white = theme.bright_white,
475 )
476 }
477
478 TerminalType::Warp => r#"# Warp Theme Synchronization
479# Warp uses its own theme system
480# To create a custom theme:
481# 1. Open Warp Settings
482# 2. Go to Appearance → Themes
483# 3. Click "New Theme" or "Import Theme"
484# 4. Use the VT Code color values provided in the wizard
485
486# VT Code colors are displayed in the terminal setup output
487# You can manually configure them in Warp's theme editor
488"#
489 .to_string(),
490
491 TerminalType::WindowsTerminal => {
492 format!(
493 r#"{{
494 "schemes": [
495 {{
496 "name": "VT Code Dark",
497 "background": "{background}",
498 "foreground": "{foreground}",
499 "cursorColor": "{cursor}",
500 "selectionBackground": "{selection_bg}",
501 "black": "{black}",
502 "red": "{red}",
503 "green": "{green}",
504 "yellow": "{yellow}",
505 "blue": "{blue}",
506 "purple": "{magenta}",
507 "cyan": "{cyan}",
508 "white": "{white}",
509 "brightBlack": "{bright_black}",
510 "brightRed": "{bright_red}",
511 "brightGreen": "{bright_green}",
512 "brightYellow": "{bright_yellow}",
513 "brightBlue": "{bright_blue}",
514 "brightPurple": "{bright_magenta}",
515 "brightCyan": "{bright_cyan}",
516 "brightWhite": "{bright_white}"
517 }}
518 ],
519 "profiles": {{
520 "defaults": {{
521 "colorScheme": "VT Code Dark"
522 }}
523 }}
524}}
525"#,
526 background = theme.background,
527 foreground = theme.foreground,
528 cursor = theme.cursor,
529 selection_bg = theme.selection_bg,
530 black = theme.black,
531 red = theme.red,
532 green = theme.green,
533 yellow = theme.yellow,
534 blue = theme.blue,
535 magenta = theme.magenta,
536 cyan = theme.cyan,
537 white = theme.white,
538 bright_black = theme.bright_black,
539 bright_red = theme.bright_red,
540 bright_green = theme.bright_green,
541 bright_yellow = theme.bright_yellow,
542 bright_blue = theme.bright_blue,
543 bright_magenta = theme.bright_magenta,
544 bright_cyan = theme.bright_cyan,
545 bright_white = theme.bright_white,
546 )
547 }
548
549 TerminalType::Hyper => {
550 format!(
551 r#"// VT Code Dark Theme for Hyper
552module.exports = {{
553 config: {{
554 backgroundColor: '{background}',
555 foregroundColor: '{foreground}',
556 cursorColor: '{cursor}',
557 selectionColor: '{selection_bg}',
558 colors: {{
559 black: '{black}',
560 red: '{red}',
561 green: '{green}',
562 yellow: '{yellow}',
563 blue: '{blue}',
564 magenta: '{magenta}',
565 cyan: '{cyan}',
566 white: '{white}',
567 lightBlack: '{bright_black}',
568 lightRed: '{bright_red}',
569 lightGreen: '{bright_green}',
570 lightYellow: '{bright_yellow}',
571 lightBlue: '{bright_blue}',
572 lightMagenta: '{bright_magenta}',
573 lightCyan: '{bright_cyan}',
574 lightWhite: '{bright_white}',
575 }}
576 }}
577}};
578"#,
579 background = theme.background,
580 foreground = theme.foreground,
581 cursor = theme.cursor,
582 selection_bg = theme.selection_bg,
583 black = theme.black,
584 red = theme.red,
585 green = theme.green,
586 yellow = theme.yellow,
587 blue = theme.blue,
588 magenta = theme.magenta,
589 cyan = theme.cyan,
590 white = theme.white,
591 bright_black = theme.bright_black,
592 bright_red = theme.bright_red,
593 bright_green = theme.bright_green,
594 bright_yellow = theme.bright_yellow,
595 bright_blue = theme.bright_blue,
596 bright_magenta = theme.bright_magenta,
597 bright_cyan = theme.bright_cyan,
598 bright_white = theme.bright_white,
599 )
600 }
601
602 TerminalType::Tabby => {
603 format!(
604 r#"# VT Code Dark Theme for Tabby
605appearance:
606 colorScheme:
607 name: "VT Code Dark"
608 foreground: "{foreground}"
609 background: "{background}"
610 cursor: "{cursor}"
611 selection: "{selection_bg}"
612 colors:
613 - "{black}"
614 - "{red}"
615 - "{green}"
616 - "{yellow}"
617 - "{blue}"
618 - "{magenta}"
619 - "{cyan}"
620 - "{white}"
621 - "{bright_black}"
622 - "{bright_red}"
623 - "{bright_green}"
624 - "{bright_yellow}"
625 - "{bright_blue}"
626 - "{bright_magenta}"
627 - "{bright_cyan}"
628 - "{bright_white}"
629"#,
630 background = theme.background,
631 foreground = theme.foreground,
632 cursor = theme.cursor,
633 selection_bg = theme.selection_bg,
634 black = theme.black,
635 red = theme.red,
636 green = theme.green,
637 yellow = theme.yellow,
638 blue = theme.blue,
639 magenta = theme.magenta,
640 cyan = theme.cyan,
641 white = theme.white,
642 bright_black = theme.bright_black,
643 bright_red = theme.bright_red,
644 bright_green = theme.bright_green,
645 bright_yellow = theme.bright_yellow,
646 bright_blue = theme.bright_blue,
647 bright_magenta = theme.bright_magenta,
648 bright_cyan = theme.bright_cyan,
649 bright_white = theme.bright_white,
650 )
651 }
652
653 TerminalType::ITerm2 => r#"Manual iTerm2 Theme Configuration:
654
6551. Open iTerm2 Preferences (Cmd+,)
6562. Go to Profiles → Colors
6573. Click "Color Presets..." → "Import..."
6584. Or manually configure colors:
659
660Background: #1e1e1e
661Foreground: #d4d4d4
662Cursor: #ffffff
663Selection: #264f78
664
665ANSI Colors:
666Black: #000000, Red: #cd3131, Green: #0dbc79, Yellow: #e5e510
667Blue: #2472c8, Magenta: #bc3fbc, Cyan: #11a8cd, White: #e5e5e5
668
669Bright Colors:
670Black: #666666, Red: #f14c4c, Green: #23d18b, Yellow: #f5f543
671Blue: #3b8eea, Magenta: #d670d6, Cyan: #29b8db, White: #ffffff
672
673Alternative: Download VT Code.itermcolors file and import
674"#
675 .to_string(),
676
677 TerminalType::VSCode => {
678 format!(
679 r#"VS Code Terminal Theme Configuration:
680
681The terminal automatically inherits your VS Code theme colors.
682
683To customize terminal colors independently, add to settings.json:
684{{
685 "workbench.colorCustomizations": {{
686 "terminal.background": "{background}",
687 "terminal.foreground": "{foreground}",
688 "terminalCursor.background": "{cursor}",
689 "terminal.selectionBackground": "{selection_bg}",
690 "terminal.ansiBlack": "{black}",
691 "terminal.ansiRed": "{red}",
692 "terminal.ansiGreen": "{green}",
693 "terminal.ansiYellow": "{yellow}",
694 "terminal.ansiBlue": "{blue}",
695 "terminal.ansiMagenta": "{magenta}",
696 "terminal.ansiCyan": "{cyan}",
697 "terminal.ansiWhite": "{white}",
698 "terminal.ansiBrightBlack": "{bright_black}",
699 "terminal.ansiBrightRed": "{bright_red}",
700 "terminal.ansiBrightGreen": "{bright_green}",
701 "terminal.ansiBrightYellow": "{bright_yellow}",
702 "terminal.ansiBrightBlue": "{bright_blue}",
703 "terminal.ansiBrightMagenta": "{bright_magenta}",
704 "terminal.ansiBrightCyan": "{bright_cyan}",
705 "terminal.ansiBrightWhite": "{bright_white}"
706 }}
707}}
708"#,
709 background = theme.background,
710 foreground = theme.foreground,
711 cursor = theme.cursor,
712 selection_bg = theme.selection_bg,
713 black = theme.black,
714 red = theme.red,
715 green = theme.green,
716 yellow = theme.yellow,
717 blue = theme.blue,
718 magenta = theme.magenta,
719 cyan = theme.cyan,
720 white = theme.white,
721 bright_black = theme.bright_black,
722 bright_red = theme.bright_red,
723 bright_green = theme.bright_green,
724 bright_yellow = theme.bright_yellow,
725 bright_blue = theme.bright_blue,
726 bright_magenta = theme.bright_magenta,
727 bright_cyan = theme.bright_cyan,
728 bright_white = theme.bright_white,
729 )
730 }
731
732 TerminalType::Unknown => {
733 anyhow::bail!("Cannot generate theme config for unknown terminal type");
734 }
735 };
736
737 Ok(config)
738}
739
740#[cfg(test)]
741mod tests {
742 use super::*;
743
744 #[test]
745 fn test_vtcode_dark_theme_defaults() {
746 let theme = VTCodeDarkTheme::default();
747 assert_eq!(theme.background, "#1e1e1e");
748 assert_eq!(theme.foreground, "#d4d4d4");
749 assert_eq!(theme.cursor, "#ffffff");
750 }
751
752 #[test]
753 fn test_generate_ghostty_config() {
754 let config = generate_config(TerminalType::Ghostty).unwrap();
755 assert!(config.contains("palette = 0="));
756 assert!(config.contains("palette = 255="));
757 assert!(config.contains("#1e1e1e"));
758 }
759
760 #[test]
761 fn test_generate_kitty_config() {
762 let config = generate_config(TerminalType::Kitty).unwrap();
763 assert!(config.contains("color0 "));
764 assert!(config.contains("color255 "));
765 }
766
767 #[test]
768 fn test_generate_alacritty_config() {
769 let config = generate_config(TerminalType::Alacritty).unwrap();
770 assert!(config.contains("[colors"));
771 assert!(config.contains("primary"));
772 assert!(config.contains("index = 255"));
773 }
774
775 #[test]
776 fn test_generate_windows_terminal_config() {
777 let config = generate_config(TerminalType::WindowsTerminal).unwrap();
778 assert!(config.contains("schemes"));
779 assert!(config.contains("VT Code Dark"));
780 }
781
782 #[test]
783 fn test_generate_vscode_instructions() {
784 let config = generate_config(TerminalType::VSCode).unwrap();
785 assert!(config.contains("workbench.colorCustomizations"));
786 assert!(config.contains("terminal.ansi"));
787 }
788
789 #[test]
790 fn test_unknown_terminal_error() {
791 let result = generate_config(TerminalType::Unknown);
792 result.unwrap_err();
793 }
794
795 #[test]
796 fn test_generate_config() {
797 generate_config(TerminalType::Kitty).unwrap();
799 }
800
801 #[test]
802 fn test_generated_palette_has_256_entries_and_preserves_base16() {
803 let theme = VTCodeDarkTheme::default();
804 let palette = generate_256_palette(&theme, false).unwrap();
805
806 assert_eq!(palette.len(), 256);
807
808 let expected_base16 = theme
809 .base16_colors()
810 .iter()
811 .map(|c| Rgb::from_hex(c).unwrap().to_hex())
812 .collect::<Vec<_>>();
813 let actual_base16 = palette
814 .iter()
815 .take(16)
816 .map(|rgb| rgb.to_hex())
817 .collect::<Vec<_>>();
818
819 assert_eq!(actual_base16, expected_base16);
820 }
821}