Skip to main content

vtcode_theme/
registry.rs

1use anstyle::RgbColor;
2use catppuccin::PALETTE;
3use hashbrown::HashMap;
4use once_cell::sync::Lazy;
5
6use crate::types::{ThemeDefinition, ThemePalette, ThemeSuite};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
9enum CatppuccinFlavorKind {
10    Latte,
11    Frappe,
12    Macchiato,
13    Mocha,
14}
15
16impl CatppuccinFlavorKind {
17    const fn id(self) -> &'static str {
18        match self {
19            Self::Latte => "catppuccin-latte",
20            Self::Frappe => "catppuccin-frappe",
21            Self::Macchiato => "catppuccin-macchiato",
22            Self::Mocha => "catppuccin-mocha",
23        }
24    }
25
26    const fn label(self) -> &'static str {
27        match self {
28            Self::Latte => "Catppuccin Latte",
29            Self::Frappe => "Catppuccin Frappé",
30            Self::Macchiato => "Catppuccin Macchiato",
31            Self::Mocha => "Catppuccin Mocha",
32        }
33    }
34
35    fn flavor(self) -> catppuccin::Flavor {
36        match self {
37            Self::Latte => PALETTE.latte,
38            Self::Frappe => PALETTE.frappe,
39            Self::Macchiato => PALETTE.macchiato,
40            Self::Mocha => PALETTE.mocha,
41        }
42    }
43}
44
45static CATPPUCCIN_FLAVORS: &[CatppuccinFlavorKind] = &[
46    CatppuccinFlavorKind::Latte,
47    CatppuccinFlavorKind::Frappe,
48    CatppuccinFlavorKind::Macchiato,
49    CatppuccinFlavorKind::Mocha,
50];
51
52static REGISTRY: Lazy<HashMap<&'static str, ThemeDefinition>> = Lazy::new(|| {
53    let mut map = HashMap::new();
54    map.insert(
55        "ciapre-dark",
56        ThemeDefinition {
57            id: "ciapre-dark",
58            label: "Ciapre Dark",
59            palette: ThemePalette {
60                primary_accent: RgbColor(0xBF, 0xB3, 0x8F),
61                background: RgbColor(0x26, 0x26, 0x26),
62                foreground: RgbColor(0xBF, 0xB3, 0x8F),
63                secondary_accent: RgbColor(0xD9, 0x9A, 0x4E),
64                alert: RgbColor(0xFF, 0x8A, 0x8A),
65                logo_accent: RgbColor(0xD9, 0x9A, 0x4E),
66            },
67        },
68    );
69    map.insert(
70        "ciapre-blue",
71        ThemeDefinition {
72            id: "ciapre-blue",
73            label: "Ciapre Blue",
74            palette: ThemePalette {
75                primary_accent: RgbColor(0xBF, 0xB3, 0x8F),
76                background: RgbColor(0x17, 0x1C, 0x26),
77                foreground: RgbColor(0xBF, 0xB3, 0x8F),
78                secondary_accent: RgbColor(0xBF, 0xB3, 0x8F),
79                alert: RgbColor(0xFF, 0x8A, 0x8A),
80                logo_accent: RgbColor(0xD9, 0x9A, 0x4E),
81            },
82        },
83    );
84    map.insert(
85        "ciapre",
86        ThemeDefinition {
87            id: "ciapre",
88            label: "Ciapre",
89            palette: ThemePalette {
90                primary_accent: RgbColor(0xAE, 0xA4, 0x7F),
91                background: RgbColor(0x18, 0x18, 0x18),
92                foreground: RgbColor(0xAE, 0xA4, 0x7F),
93                secondary_accent: RgbColor(0xCC, 0x8A, 0x3E),
94                alert: RgbColor(0xAC, 0x38, 0x35),
95                logo_accent: RgbColor(0xCC, 0x8A, 0x3E),
96            },
97        },
98    );
99    map.insert(
100        "solarized-dark",
101        ThemeDefinition {
102            id: "solarized-dark",
103            label: "Solarized Dark",
104            palette: ThemePalette {
105                primary_accent: RgbColor(0x83, 0x94, 0x96),
106                background: RgbColor(0x00, 0x2B, 0x36),
107                foreground: RgbColor(0x83, 0x94, 0x96),
108                secondary_accent: RgbColor(0x26, 0x8B, 0xD2),
109                alert: RgbColor(0xDC, 0x32, 0x2F),
110                logo_accent: RgbColor(0xB5, 0x89, 0x00),
111            },
112        },
113    );
114    map.insert(
115        "solarized-light",
116        ThemeDefinition {
117            id: "solarized-light",
118            label: "Solarized Light",
119            palette: ThemePalette {
120                primary_accent: RgbColor(0x58, 0x6E, 0x75),
121                background: RgbColor(0xFD, 0xF6, 0xE3),
122                foreground: RgbColor(0x58, 0x6E, 0x75),
123                secondary_accent: RgbColor(0x26, 0x8B, 0xD2),
124                alert: RgbColor(0xDC, 0x32, 0x2F),
125                logo_accent: RgbColor(0xB5, 0x89, 0x00),
126            },
127        },
128    );
129    map.insert(
130        "solarized-dark-hc",
131        ThemeDefinition {
132            id: "solarized-dark-hc",
133            label: "Solarized Dark Higher Contrast",
134            palette: ThemePalette {
135                primary_accent: RgbColor(0x83, 0x94, 0x96),
136                background: RgbColor(0x00, 0x28, 0x31),
137                foreground: RgbColor(0xE9, 0xE3, 0xCC),
138                secondary_accent: RgbColor(0x20, 0x76, 0xC7),
139                alert: RgbColor(0xD1, 0x1C, 0x24),
140                logo_accent: RgbColor(0xA5, 0x77, 0x06),
141            },
142        },
143    );
144    map.insert(
145        "gruvbox-dark",
146        ThemeDefinition {
147            id: "gruvbox-dark",
148            label: "Gruvbox Dark",
149            palette: ThemePalette {
150                primary_accent: RgbColor(0xA8, 0x99, 0x84),
151                background: RgbColor(0x28, 0x28, 0x28),
152                foreground: RgbColor(0xA8, 0x99, 0x84),
153                secondary_accent: RgbColor(0x45, 0x85, 0x88),
154                alert: RgbColor(0xCC, 0x24, 0x1D),
155                logo_accent: RgbColor(0xD7, 0x99, 0x21),
156            },
157        },
158    );
159    map.insert(
160        "gruvbox-dark-hard",
161        ThemeDefinition {
162            id: "gruvbox-dark-hard",
163            label: "Gruvbox Dark Hard",
164            palette: ThemePalette {
165                primary_accent: RgbColor(0xA8, 0x99, 0x84),
166                background: RgbColor(0x1D, 0x20, 0x21),
167                foreground: RgbColor(0xA8, 0x99, 0x84),
168                secondary_accent: RgbColor(0x45, 0x85, 0x88),
169                alert: RgbColor(0xCC, 0x24, 0x1D),
170                logo_accent: RgbColor(0xD7, 0x99, 0x21),
171            },
172        },
173    );
174    map.insert(
175        "gruvbox-light",
176        ThemeDefinition {
177            id: "gruvbox-light",
178            label: "Gruvbox Light",
179            palette: ThemePalette {
180                primary_accent: RgbColor(0x7C, 0x6F, 0x64),
181                background: RgbColor(0xFB, 0xF4, 0xE8),
182                foreground: RgbColor(0x7C, 0x6F, 0x64),
183                secondary_accent: RgbColor(0x45, 0x85, 0x88),
184                alert: RgbColor(0x9D, 0x00, 0x06),
185                logo_accent: RgbColor(0xB5, 0x76, 0x14),
186            },
187        },
188    );
189    map.insert(
190        "gruvbox-light-hard",
191        ThemeDefinition {
192            id: "gruvbox-light-hard",
193            label: "Gruvbox Light Hard",
194            palette: ThemePalette {
195                primary_accent: RgbColor(0x50, 0x49, 0x45),
196                background: RgbColor(0xF9, 0xF5, 0xD7),
197                foreground: RgbColor(0x50, 0x49, 0x45),
198                secondary_accent: RgbColor(0x45, 0x85, 0x88),
199                alert: RgbColor(0x9D, 0x00, 0x06),
200                logo_accent: RgbColor(0xB5, 0x76, 0x14),
201            },
202        },
203    );
204    map.insert(
205        "gruvbox-material",
206        ThemeDefinition {
207            id: "gruvbox-material",
208            label: "Gruvbox Material",
209            palette: ThemePalette {
210                primary_accent: RgbColor(0xD4, 0xBE, 0x98),
211                background: RgbColor(0x28, 0x2E, 0x33),
212                foreground: RgbColor(0xD4, 0xBE, 0x98),
213                secondary_accent: RgbColor(0x89, 0xB4, 0x82),
214                alert: RgbColor(0xEA, 0x69, 0x62),
215                logo_accent: RgbColor(0xE7, 0xA7, 0x2F),
216            },
217        },
218    );
219    map.insert(
220        "gruvbox-material-dark",
221        ThemeDefinition {
222            id: "gruvbox-material-dark",
223            label: "Gruvbox Material Dark",
224            palette: ThemePalette {
225                primary_accent: RgbColor(0xD4, 0xBE, 0x98),
226                background: RgbColor(0x28, 0x2E, 0x33),
227                foreground: RgbColor(0xD4, 0xBE, 0x98),
228                secondary_accent: RgbColor(0x89, 0xB4, 0x82),
229                alert: RgbColor(0xEA, 0x69, 0x62),
230                logo_accent: RgbColor(0xE7, 0xA7, 0x2F),
231            },
232        },
233    );
234    map.insert(
235        "gruvbox-material-light",
236        ThemeDefinition {
237            id: "gruvbox-material-light",
238            label: "Gruvbox Material Light",
239            palette: ThemePalette {
240                primary_accent: RgbColor(0x65, 0x49, 0x31),
241                background: RgbColor(0xFB, 0xF1, 0xC7),
242                foreground: RgbColor(0x65, 0x49, 0x31),
243                secondary_accent: RgbColor(0x4C, 0x7A, 0x5D),
244                alert: RgbColor(0xC1, 0x4A, 0x4A),
245                logo_accent: RgbColor(0xB4, 0x71, 0x09),
246            },
247        },
248    );
249    map.insert(
250        "ayu",
251        ThemeDefinition {
252            id: "ayu",
253            label: "Ayu Dark",
254            palette: ThemePalette {
255                primary_accent: RgbColor(0xE6, 0xE1, 0xCF),
256                background: RgbColor(0x0F, 0x14, 0x19),
257                foreground: RgbColor(0xE6, 0xE1, 0xCF),
258                secondary_accent: RgbColor(0x39, 0xBA, 0xE6),
259                alert: RgbColor(0xFF, 0x33, 0x33),
260                logo_accent: RgbColor(0xE6, 0xB4, 0x50),
261            },
262        },
263    );
264    map.insert(
265        "ayu-mirage",
266        ThemeDefinition {
267            id: "ayu-mirage",
268            label: "Ayu Mirage",
269            palette: ThemePalette {
270                primary_accent: RgbColor(0xCB, 0xCC, 0xCC),
271                background: RgbColor(0x1F, 0x24, 0x2D),
272                foreground: RgbColor(0xCB, 0xCC, 0xCC),
273                secondary_accent: RgbColor(0x5C, 0xC5, 0xFF),
274                alert: RgbColor(0xFF, 0x66, 0x66),
275                logo_accent: RgbColor(0xFF, 0xCC, 0x66),
276            },
277        },
278    );
279    map.insert(
280        "dracula",
281        ThemeDefinition {
282            id: "dracula",
283            label: "Dracula",
284            palette: ThemePalette {
285                primary_accent: RgbColor(0xF8, 0xF8, 0xF2),
286                background: RgbColor(0x28, 0x2A, 0x36),
287                foreground: RgbColor(0xF8, 0xF8, 0xF2),
288                secondary_accent: RgbColor(0x8B, 0xE9, 0xFD),
289                alert: RgbColor(0xFF, 0x55, 0x55),
290                logo_accent: RgbColor(0xFF, 0xB8, 0x6C),
291            },
292        },
293    );
294    map.insert(
295        "github-dark",
296        ThemeDefinition {
297            id: "github-dark",
298            label: "GitHub Dark",
299            palette: ThemePalette {
300                primary_accent: RgbColor(0xC9, 0xD1, 0xD9),
301                background: RgbColor(0x0D, 0x11, 0x17),
302                foreground: RgbColor(0xC9, 0xD1, 0xD9),
303                secondary_accent: RgbColor(0x58, 0xA6, 0xFF),
304                alert: RgbColor(0xF8, 0x51, 0x49),
305                logo_accent: RgbColor(0xD2, 0x99, 0x22),
306            },
307        },
308    );
309    map.insert(
310        "github",
311        ThemeDefinition {
312            id: "github",
313            label: "GitHub Light",
314            palette: ThemePalette {
315                primary_accent: RgbColor(0x24, 0x29, 0x2E),
316                background: RgbColor(0xFF, 0xFF, 0xFF),
317                foreground: RgbColor(0x24, 0x29, 0x2E),
318                secondary_accent: RgbColor(0x03, 0x66, 0xD6),
319                alert: RgbColor(0xD7, 0x3A, 0x49),
320                logo_accent: RgbColor(0xB0, 0x88, 0x00),
321            },
322        },
323    );
324    map.insert(
325        "atom-one-dark",
326        ThemeDefinition {
327            id: "atom-one-dark",
328            label: "Atom One Dark",
329            palette: ThemePalette {
330                primary_accent: RgbColor(0xAB, 0xB2, 0xBF),
331                background: RgbColor(0x28, 0x2C, 0x34),
332                foreground: RgbColor(0xAB, 0xB2, 0xBF),
333                secondary_accent: RgbColor(0x61, 0xAF, 0xEF),
334                alert: RgbColor(0xE0, 0x6C, 0x75),
335                logo_accent: RgbColor(0xE5, 0xC0, 0x7B),
336            },
337        },
338    );
339    map.insert(
340        "atom-one-light",
341        ThemeDefinition {
342            id: "atom-one-light",
343            label: "Atom One Light",
344            palette: ThemePalette {
345                primary_accent: RgbColor(0x38, 0x3A, 0x42),
346                background: RgbColor(0xFA, 0xFA, 0xFA),
347                foreground: RgbColor(0x38, 0x3A, 0x42),
348                secondary_accent: RgbColor(0x40, 0x73, 0xC9),
349                alert: RgbColor(0xE4, 0x56, 0x49),
350                logo_accent: RgbColor(0x98, 0x62, 0x00),
351            },
352        },
353    );
354    map.insert(
355        "tomorrow",
356        ThemeDefinition {
357            id: "tomorrow",
358            label: "Tomorrow",
359            palette: ThemePalette {
360                primary_accent: RgbColor(0x4D, 0x4D, 0x4C),
361                background: RgbColor(0xFF, 0xFF, 0xFF),
362                foreground: RgbColor(0x4D, 0x4D, 0x4C),
363                secondary_accent: RgbColor(0x42, 0x7B, 0xA4),
364                alert: RgbColor(0xC8, 0x28, 0x29),
365                logo_accent: RgbColor(0xAE, 0x7B, 0x03),
366            },
367        },
368    );
369    map.insert(
370        "tomorrow-night",
371        ThemeDefinition {
372            id: "tomorrow-night",
373            label: "Tomorrow Night",
374            palette: ThemePalette {
375                primary_accent: RgbColor(0xC5, 0xC8, 0xC6),
376                background: RgbColor(0x1D, 0x1F, 0x21),
377                foreground: RgbColor(0xC5, 0xC8, 0xC6),
378                secondary_accent: RgbColor(0x81, 0xA2, 0xBE),
379                alert: RgbColor(0xCC, 0x66, 0x66),
380                logo_accent: RgbColor(0xDE, 0x93, 0x5F),
381            },
382        },
383    );
384    map.insert(
385        "tomorrow-night-blue",
386        ThemeDefinition {
387            id: "tomorrow-night-blue",
388            label: "Tomorrow Night Blue",
389            palette: ThemePalette {
390                primary_accent: RgbColor(0xFF, 0xFF, 0xFF),
391                background: RgbColor(0x00, 0x2E, 0x4E),
392                foreground: RgbColor(0xFF, 0xFF, 0xFF),
393                secondary_accent: RgbColor(0x7A, 0xBD, 0xFF),
394                alert: RgbColor(0xFF, 0x9D, 0x9D),
395                logo_accent: RgbColor(0xFF, 0xC8, 0x80),
396            },
397        },
398    );
399    map.insert(
400        "tomorrow-night-bright",
401        ThemeDefinition {
402            id: "tomorrow-night-bright",
403            label: "Tomorrow Night Bright",
404            palette: ThemePalette {
405                primary_accent: RgbColor(0xDE, 0xDE, 0xDE),
406                background: RgbColor(0x00, 0x00, 0x00),
407                foreground: RgbColor(0xDE, 0xDE, 0xDE),
408                secondary_accent: RgbColor(0x7A, 0xBD, 0xFF),
409                alert: RgbColor(0xFF, 0x87, 0x87),
410                logo_accent: RgbColor(0xFF, 0xC8, 0x80),
411            },
412        },
413    );
414    map.insert(
415        "tomorrow-night-eighties",
416        ThemeDefinition {
417            id: "tomorrow-night-eighties",
418            label: "Tomorrow Night Eighties",
419            palette: ThemePalette {
420                primary_accent: RgbColor(0xCC, 0xCC, 0xCC),
421                background: RgbColor(0x2D, 0x2D, 0x2D),
422                foreground: RgbColor(0xCC, 0xCC, 0xCC),
423                secondary_accent: RgbColor(0x66, 0x99, 0xCC),
424                alert: RgbColor(0xF2, 0x77, 0x7A),
425                logo_accent: RgbColor(0xF9, 0x91, 0x57),
426            },
427        },
428    );
429    map.insert(
430        "tomorrow-night-burns",
431        ThemeDefinition {
432            id: "tomorrow-night-burns",
433            label: "Tomorrow Night Burns",
434            palette: ThemePalette {
435                primary_accent: RgbColor(0xD0, 0xD0, 0xD0),
436                background: RgbColor(0x15, 0x12, 0x0E),
437                foreground: RgbColor(0xD0, 0xD0, 0xD0),
438                secondary_accent: RgbColor(0x6C, 0x99, 0xB4),
439                alert: RgbColor(0xB7, 0x4E, 0x4E),
440                logo_accent: RgbColor(0xC4, 0x8D, 0x53),
441            },
442        },
443    );
444    map.insert(
445        "material-ocean",
446        ThemeDefinition {
447            id: "material-ocean",
448            label: "Material Ocean",
449            palette: ThemePalette {
450                primary_accent: RgbColor(0xEE, 0xEE, 0xEE),
451                background: RgbColor(0x0F, 0x11, 0x1A),
452                foreground: RgbColor(0xEE, 0xEE, 0xEE),
453                secondary_accent: RgbColor(0x82, 0xAA, 0xFF),
454                alert: RgbColor(0xF0, 0x71, 0x78),
455                logo_accent: RgbColor(0xFF, 0xCB, 0x6B),
456            },
457        },
458    );
459    map.insert(
460        "material-dark",
461        ThemeDefinition {
462            id: "material-dark",
463            label: "Material Dark",
464            palette: ThemePalette {
465                primary_accent: RgbColor(0xEE, 0xEE, 0xEE),
466                background: RgbColor(0x26, 0x32, 0x38),
467                foreground: RgbColor(0xEE, 0xEE, 0xEE),
468                secondary_accent: RgbColor(0x82, 0xAA, 0xFF),
469                alert: RgbColor(0xF0, 0x71, 0x78),
470                logo_accent: RgbColor(0xFF, 0xCB, 0x6B),
471            },
472        },
473    );
474    map.insert(
475        "material",
476        ThemeDefinition {
477            id: "material",
478            label: "Material",
479            palette: ThemePalette {
480                primary_accent: RgbColor(0xEE, 0xEE, 0xEE),
481                background: RgbColor(0x26, 0x32, 0x38),
482                foreground: RgbColor(0xEE, 0xEE, 0xEE),
483                secondary_accent: RgbColor(0x82, 0xAA, 0xFF),
484                alert: RgbColor(0xF0, 0x71, 0x78),
485                logo_accent: RgbColor(0xFF, 0xCB, 0x6B),
486            },
487        },
488    );
489    map.insert(
490        "monokai-classic",
491        ThemeDefinition {
492            id: "monokai-classic",
493            label: "Monokai Classic",
494            palette: ThemePalette {
495                primary_accent: RgbColor(0xF8, 0xF8, 0xF2),
496                background: RgbColor(0x27, 0x28, 0x22),
497                foreground: RgbColor(0xF8, 0xF8, 0xF2),
498                secondary_accent: RgbColor(0x66, 0xD9, 0xEF),
499                alert: RgbColor(0xF9, 0x26, 0x72),
500                logo_accent: RgbColor(0xFD, 0x97, 0x1F),
501            },
502        },
503    );
504    map.insert(
505        "night-owl",
506        ThemeDefinition {
507            id: "night-owl",
508            label: "Night Owl",
509            palette: ThemePalette {
510                primary_accent: RgbColor(0xD6, 0xDE, 0xEB),
511                background: RgbColor(0x01, 0x17, 0x27),
512                foreground: RgbColor(0xD6, 0xDE, 0xEB),
513                secondary_accent: RgbColor(0x82, 0xAA, 0xFF),
514                alert: RgbColor(0xEF, 0x53, 0x50),
515                logo_accent: RgbColor(0xFA, 0xC8, 0x63),
516            },
517        },
518    );
519    map.insert(
520        "zenburn",
521        ThemeDefinition {
522            id: "zenburn",
523            label: "Zenburn",
524            palette: ThemePalette {
525                primary_accent: RgbColor(0xDC, 0xDC, 0xCC),
526                background: RgbColor(0x3F, 0x3F, 0x3F),
527                foreground: RgbColor(0xDC, 0xDC, 0xCC),
528                secondary_accent: RgbColor(0x8C, 0xA8, 0x7D),
529                alert: RgbColor(0xCC, 0x93, 0x93),
530                logo_accent: RgbColor(0xDF, 0xAF, 0x8F),
531            },
532        },
533    );
534    map.insert(
535        "jetbrains-darcula",
536        ThemeDefinition {
537            id: "jetbrains-darcula",
538            label: "JetBrains Darcula",
539            palette: ThemePalette {
540                primary_accent: RgbColor(0xA9, 0xB7, 0xC6),
541                background: RgbColor(0x2B, 0x2B, 0x2B),
542                foreground: RgbColor(0xA9, 0xB7, 0xC6),
543                secondary_accent: RgbColor(0x68, 0x8B, 0xB5),
544                alert: RgbColor(0xCC, 0x78, 0x75),
545                logo_accent: RgbColor(0xBB, 0xA2, 0x6C),
546            },
547        },
548    );
549    map.insert(
550        "spacegray",
551        ThemeDefinition {
552            id: "spacegray",
553            label: "Spacegray",
554            palette: ThemePalette {
555                primary_accent: RgbColor(0xBD, 0xC3, 0xCE),
556                background: RgbColor(0x20, 0x22, 0x2B),
557                foreground: RgbColor(0xBD, 0xC3, 0xCE),
558                secondary_accent: RgbColor(0x7F, 0xA0, 0xC0),
559                alert: RgbColor(0xB0, 0x6B, 0x6B),
560                logo_accent: RgbColor(0xC0, 0x99, 0x70),
561            },
562        },
563    );
564    map.insert(
565        "spacegray-bright",
566        ThemeDefinition {
567            id: "spacegray-bright",
568            label: "Spacegray Bright",
569            palette: ThemePalette {
570                primary_accent: RgbColor(0xF2, 0xF2, 0xF2),
571                background: RgbColor(0x1A, 0x1A, 0x1A),
572                foreground: RgbColor(0xF2, 0xF2, 0xF2),
573                secondary_accent: RgbColor(0x88, 0xB0, 0xD0),
574                alert: RgbColor(0xD0, 0x70, 0x70),
575                logo_accent: RgbColor(0xD0, 0xA0, 0x60),
576            },
577        },
578    );
579    map.insert(
580        "spacegray-eighties",
581        ThemeDefinition {
582            id: "spacegray-eighties",
583            label: "Spacegray Eighties",
584            palette: ThemePalette {
585                primary_accent: RgbColor(0xEC, 0xEC, 0xEC),
586                background: RgbColor(0x22, 0x22, 0x2B),
587                foreground: RgbColor(0xEC, 0xEC, 0xEC),
588                secondary_accent: RgbColor(0x7A, 0x9F, 0xC2),
589                alert: RgbColor(0xC7, 0x6B, 0x6B),
590                logo_accent: RgbColor(0xC2, 0x95, 0x62),
591            },
592        },
593    );
594    map.insert(
595        "spacegray-eighties-dull",
596        ThemeDefinition {
597            id: "spacegray-eighties-dull",
598            label: "Spacegray Eighties Dull",
599            palette: ThemePalette {
600                primary_accent: RgbColor(0xC2, 0xC8, 0xD0),
601                background: RgbColor(0x2D, 0x30, 0x3A),
602                foreground: RgbColor(0xC2, 0xC8, 0xD0),
603                secondary_accent: RgbColor(0x6E, 0x8F, 0xB0),
604                alert: RgbColor(0xB0, 0x6A, 0x6A),
605                logo_accent: RgbColor(0xB0, 0x8C, 0x60),
606            },
607        },
608    );
609    map.insert(
610        "apple-classic",
611        ThemeDefinition {
612            id: "apple-classic",
613            label: "Apple Classic",
614            palette: ThemePalette {
615                primary_accent: RgbColor(0x00, 0x00, 0x00),
616                background: RgbColor(0xF6, 0xF4, 0xEC),
617                foreground: RgbColor(0x00, 0x00, 0x00),
618                secondary_accent: RgbColor(0x00, 0x66, 0x99),
619                alert: RgbColor(0xB0, 0x00, 0x00),
620                logo_accent: RgbColor(0x8B, 0x6F, 0x00),
621            },
622        },
623    );
624    map.insert(
625        "apple-system-colors",
626        ThemeDefinition {
627            id: "apple-system-colors",
628            label: "Apple System Colors",
629            palette: ThemePalette {
630                primary_accent: RgbColor(0xF5, 0xF5, 0xF7),
631                background: RgbColor(0x1C, 0x1C, 0x1E),
632                foreground: RgbColor(0xF5, 0xF5, 0xF7),
633                secondary_accent: RgbColor(0x0A, 0x84, 0xFF),
634                alert: RgbColor(0xFF, 0x45, 0x3A),
635                logo_accent: RgbColor(0xFF, 0x9F, 0x0A),
636            },
637        },
638    );
639    map.insert(
640        "apple-system-colors-light",
641        ThemeDefinition {
642            id: "apple-system-colors-light",
643            label: "Apple System Colors Light",
644            palette: ThemePalette {
645                primary_accent: RgbColor(0x1C, 0x1C, 0x1E),
646                background: RgbColor(0xF5, 0xF5, 0xF7),
647                foreground: RgbColor(0x1C, 0x1C, 0x1E),
648                secondary_accent: RgbColor(0x0A, 0x84, 0xFF),
649                alert: RgbColor(0xFF, 0x3B, 0x30),
650                logo_accent: RgbColor(0xFF, 0x95, 0x00),
651            },
652        },
653    );
654    map.insert(
655        "vitesse-black",
656        ThemeDefinition {
657            id: "vitesse-black",
658            label: "Vitesse Black",
659            palette: ThemePalette {
660                primary_accent: RgbColor(0xDB, 0xD7, 0xCA),
661                background: RgbColor(0x12, 0x12, 0x12),
662                foreground: RgbColor(0xDB, 0xD7, 0xCA),
663                secondary_accent: RgbColor(0x4D, 0x93, 0x8F),
664                alert: RgbColor(0xAB, 0x59, 0x59),
665                logo_accent: RgbColor(0xFF, 0xA6, 0x57),
666            },
667        },
668    );
669    map.insert(
670        "vitesse-dark",
671        ThemeDefinition {
672            id: "vitesse-dark",
673            label: "Vitesse Dark",
674            palette: ThemePalette {
675                primary_accent: RgbColor(0xDB, 0xD7, 0xCA),
676                background: RgbColor(0x18, 0x18, 0x18),
677                foreground: RgbColor(0xDB, 0xD7, 0xCA),
678                secondary_accent: RgbColor(0x4D, 0x93, 0x8F),
679                alert: RgbColor(0xAB, 0x59, 0x59),
680                logo_accent: RgbColor(0xFF, 0xA6, 0x57),
681            },
682        },
683    );
684    map.insert(
685        "vitesse-dark-soft",
686        ThemeDefinition {
687            id: "vitesse-dark-soft",
688            label: "Vitesse Dark Soft",
689            palette: ThemePalette {
690                primary_accent: RgbColor(0xDB, 0xD7, 0xCA),
691                background: RgbColor(0x20, 0x1F, 0x1F),
692                foreground: RgbColor(0xDB, 0xD7, 0xCA),
693                secondary_accent: RgbColor(0x4D, 0x93, 0x8F),
694                alert: RgbColor(0xAB, 0x59, 0x59),
695                logo_accent: RgbColor(0xFF, 0xA6, 0x57),
696            },
697        },
698    );
699    map.insert(
700        "vitesse-light",
701        ThemeDefinition {
702            id: "vitesse-light",
703            label: "Vitesse Light",
704            palette: ThemePalette {
705                primary_accent: RgbColor(0x39, 0x3A, 0x34),
706                background: RgbColor(0xF6, 0xF1, 0xE5),
707                foreground: RgbColor(0x39, 0x3A, 0x34),
708                secondary_accent: RgbColor(0x1C, 0x6B, 0x48),
709                alert: RgbColor(0xAB, 0x59, 0x59),
710                logo_accent: RgbColor(0xB0, 0x70, 0x00),
711            },
712        },
713    );
714    map.insert(
715        "vitesse-light-soft",
716        ThemeDefinition {
717            id: "vitesse-light-soft",
718            label: "Vitesse Light Soft",
719            palette: ThemePalette {
720                primary_accent: RgbColor(0x39, 0x3A, 0x34),
721                background: RgbColor(0xFA, 0xF5, 0xEB),
722                foreground: RgbColor(0x39, 0x3A, 0x34),
723                secondary_accent: RgbColor(0x1C, 0x6B, 0x48),
724                alert: RgbColor(0xAB, 0x59, 0x59),
725                logo_accent: RgbColor(0xB0, 0x70, 0x00),
726            },
727        },
728    );
729    map.insert(
730        "homebrew",
731        ThemeDefinition {
732            id: "homebrew",
733            label: "Homebrew",
734            palette: ThemePalette {
735                primary_accent: RgbColor(0xCC, 0xCC, 0xCC),
736                background: RgbColor(0x00, 0x00, 0x00),
737                foreground: RgbColor(0xCC, 0xCC, 0xCC),
738                secondary_accent: RgbColor(0x00, 0x99, 0xCC),
739                alert: RgbColor(0xCC, 0x33, 0x33),
740                logo_accent: RgbColor(0xCC, 0x99, 0x00),
741            },
742        },
743    );
744    map.insert(
745        "man-page",
746        ThemeDefinition {
747            id: "man-page",
748            label: "Man Page",
749            palette: ThemePalette {
750                primary_accent: RgbColor(0x00, 0x00, 0x00),
751                background: RgbColor(0xF2, 0xF2, 0xE6),
752                foreground: RgbColor(0x00, 0x00, 0x00),
753                secondary_accent: RgbColor(0x00, 0x66, 0x66),
754                alert: RgbColor(0x99, 0x00, 0x00),
755                logo_accent: RgbColor(0x7A, 0x5D, 0x00),
756            },
757        },
758    );
759    map.insert(
760        "framer",
761        ThemeDefinition {
762            id: "framer",
763            label: "Framer",
764            palette: ThemePalette {
765                primary_accent: RgbColor(0xF5, 0xF5, 0xF5),
766                background: RgbColor(0x10, 0x10, 0x10),
767                foreground: RgbColor(0xF5, 0xF5, 0xF5),
768                secondary_accent: RgbColor(0x7A, 0x5A, 0xFF),
769                alert: RgbColor(0xFF, 0x5C, 0x5C),
770                logo_accent: RgbColor(0xFF, 0xAF, 0x3F),
771            },
772        },
773    );
774    map.insert(
775        "espresso",
776        ThemeDefinition {
777            id: "espresso",
778            label: "Espresso",
779            palette: ThemePalette {
780                primary_accent: RgbColor(0xD0, 0xC8, 0xB8),
781                background: RgbColor(0x2A, 0x21, 0x1C),
782                foreground: RgbColor(0xD0, 0xC8, 0xB8),
783                secondary_accent: RgbColor(0x6F, 0xB3, 0xC2),
784                alert: RgbColor(0xD2, 0x52, 0x52),
785                logo_accent: RgbColor(0xC8, 0x92, 0x2D),
786            },
787        },
788    );
789    map.insert(
790        "adventure-time",
791        ThemeDefinition {
792            id: "adventure-time",
793            label: "Adventure Time",
794            palette: ThemePalette {
795                primary_accent: RgbColor(0xF8, 0xF8, 0xF8),
796                background: RgbColor(0x1F, 0x1D, 0x45),
797                foreground: RgbColor(0xF8, 0xF8, 0xF8),
798                secondary_accent: RgbColor(0x8A, 0x9B, 0xFF),
799                alert: RgbColor(0xD7, 0x56, 0x56),
800                logo_accent: RgbColor(0xF5, 0xB8, 0x4A),
801            },
802        },
803    );
804    map.insert(
805        "afterglow",
806        ThemeDefinition {
807            id: "afterglow",
808            label: "Afterglow",
809            palette: ThemePalette {
810                primary_accent: RgbColor(0xD6, 0xD6, 0xD6),
811                background: RgbColor(0x22, 0x22, 0x22),
812                foreground: RgbColor(0xD6, 0xD6, 0xD6),
813                secondary_accent: RgbColor(0x7F, 0xB0, 0xD0),
814                alert: RgbColor(0xE5, 0x72, 0x72),
815                logo_accent: RgbColor(0xD0, 0xA0, 0x60),
816            },
817        },
818    );
819    map.insert(
820        "mono",
821        ThemeDefinition {
822            id: "mono",
823            label: "Mono",
824            palette: ThemePalette {
825                primary_accent: RgbColor(0xFF, 0xFF, 0xFF),
826                background: RgbColor(0x00, 0x00, 0x00),
827                foreground: RgbColor(0xDB, 0xD7, 0xCA),
828                secondary_accent: RgbColor(0xBB, 0xBB, 0xBB),
829                alert: RgbColor(0xFF, 0xFF, 0xFF),
830                logo_accent: RgbColor(0xFF, 0xFF, 0xFF),
831            },
832        },
833    );
834    map.insert(
835        "ansi-classic",
836        ThemeDefinition {
837            id: "ansi-classic",
838            label: "ANSI Classic",
839            palette: ThemePalette {
840                primary_accent: RgbColor(0xC0, 0xC0, 0xC0),
841                background: RgbColor(0x00, 0x00, 0x00),
842                foreground: RgbColor(0xC0, 0xC0, 0xC0),
843                secondary_accent: RgbColor(0x00, 0xAA, 0xAA),
844                alert: RgbColor(0xAA, 0x00, 0x00),
845                logo_accent: RgbColor(0xAA, 0xAA, 0x00),
846            },
847        },
848    );
849
850    register_catppuccin_themes(&mut map);
851    map
852});
853
854fn register_catppuccin_themes(map: &mut HashMap<&'static str, ThemeDefinition>) {
855    for &flavor_kind in CATPPUCCIN_FLAVORS {
856        let flavor = flavor_kind.flavor();
857        map.insert(
858            flavor_kind.id(),
859            ThemeDefinition {
860                id: flavor_kind.id(),
861                label: flavor_kind.label(),
862                palette: catppuccin_palette(flavor),
863            },
864        );
865    }
866}
867
868fn catppuccin_palette(flavor: catppuccin::Flavor) -> ThemePalette {
869    let colors = flavor.colors;
870    ThemePalette {
871        primary_accent: catppuccin_rgb(colors.lavender),
872        background: catppuccin_rgb(colors.base),
873        foreground: catppuccin_rgb(colors.text),
874        secondary_accent: catppuccin_rgb(colors.sapphire),
875        alert: catppuccin_rgb(colors.red),
876        logo_accent: catppuccin_rgb(colors.peach),
877    }
878}
879
880fn catppuccin_rgb(color: catppuccin::Color) -> RgbColor {
881    RgbColor(color.rgb.r, color.rgb.g, color.rgb.b)
882}
883
884pub(crate) fn theme_definition(theme_id: &str) -> Option<&'static ThemeDefinition> {
885    REGISTRY.get(theme_id)
886}
887
888#[cfg(test)]
889pub(crate) fn all_theme_definitions() -> &'static HashMap<&'static str, ThemeDefinition> {
890    &REGISTRY
891}
892
893/// Return the list of built-in theme identifiers in sorted order.
894pub fn available_themes() -> Vec<&'static str> {
895    let mut keys: Vec<_> = REGISTRY.keys().copied().collect();
896    keys.sort();
897    keys
898}
899
900/// Return the display label for a built-in theme.
901pub fn theme_label(theme_id: &str) -> Option<&'static str> {
902    theme_definition(theme_id).map(|definition| definition.label)
903}
904
905fn suite_id_for_theme(theme_id: &str) -> Option<&'static str> {
906    if theme_id.starts_with("catppuccin-") {
907        Some("catppuccin")
908    } else if theme_id.starts_with("vitesse-") {
909        Some("vitesse")
910    } else if theme_id.starts_with("ciapre-") {
911        Some("ciapre")
912    } else if theme_id == "mono" {
913        Some("mono")
914    } else {
915        None
916    }
917}
918
919fn suite_label(suite_id: &str) -> Option<&'static str> {
920    match suite_id {
921        "catppuccin" => Some("Catppuccin"),
922        "vitesse" => Some("Vitesse"),
923        "ciapre" => Some("Ciapre"),
924        "mono" => Some("Mono"),
925        _ => None,
926    }
927}
928
929/// Return the logical theme suite identifier for a built-in theme.
930pub fn theme_suite_id(theme_id: &str) -> Option<&'static str> {
931    suite_id_for_theme(theme_id)
932}
933
934/// Return the logical theme suite label for a built-in theme.
935pub fn theme_suite_label(theme_id: &str) -> Option<&'static str> {
936    suite_id_for_theme(theme_id).and_then(suite_label)
937}
938
939/// Return the built-in theme suites and their member theme identifiers.
940pub fn available_theme_suites() -> Vec<ThemeSuite> {
941    const ORDER: &[&str] = &["ciapre", "vitesse", "catppuccin", "mono"];
942
943    ORDER
944        .iter()
945        .filter_map(|suite_id| {
946            let mut theme_ids: Vec<&'static str> = available_themes()
947                .into_iter()
948                .filter(|theme_id| suite_id_for_theme(theme_id) == Some(*suite_id))
949                .collect();
950            if theme_ids.is_empty() {
951                return None;
952            }
953            theme_ids.sort_unstable();
954            Some(ThemeSuite {
955                id: suite_id,
956                label: suite_label(suite_id)?,
957                theme_ids,
958            })
959        })
960        .collect()
961}