gpui_component/theme/
schema.rs

1use std::{rc::Rc, sync::Arc};
2
3use anyhow::Result;
4use gpui::{Hsla, SharedString};
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7
8use crate::{
9    highlighter::{HighlightTheme, HighlightThemeStyle},
10    Colorize, Theme, ThemeColor, ThemeMode,
11};
12
13/// Represents a theme configuration.
14#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
15#[serde(default)]
16pub struct ThemeSet {
17    /// The name of the theme set.
18    pub name: SharedString,
19    /// The author of the theme.
20    pub author: Option<SharedString>,
21    /// The URL of the theme.
22    pub url: Option<SharedString>,
23
24    /// The base font size, default is 16.
25    #[serde(rename = "font.size")]
26    pub font_size: Option<f32>,
27
28    #[serde(rename = "themes")]
29    pub themes: Vec<ThemeConfig>,
30}
31
32#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
33#[serde(default)]
34pub struct ThemeConfig {
35    /// Whether this theme is the default theme.
36    pub is_default: bool,
37    /// The name of the theme.
38    pub name: SharedString,
39    /// The mode of the theme, default is light.
40    pub mode: ThemeMode,
41    /// The colors of the theme.
42    pub colors: ThemeConfigColors,
43    /// The highlight theme, this part is combilbility with `style` section in Zed theme.
44    ///
45    /// https://github.com/zed-industries/zed/blob/f50041779dcfd7a76c8aec293361c60c53f02d51/assets/themes/ayu/ayu.json#L9
46    pub highlight: Option<HighlightThemeStyle>,
47}
48
49#[derive(Debug, Default, Clone, JsonSchema, Serialize, Deserialize)]
50pub struct ThemeConfigColors {
51    /// Used for accents such as hover background on MenuItem, ListItem, etc.
52    #[serde(rename = "accent.background")]
53    pub accent: Option<SharedString>,
54    /// Used for accent text color.
55    #[serde(rename = "accent.foreground")]
56    pub accent_foreground: Option<SharedString>,
57    /// Accordion background color.
58    #[serde(rename = "accordion.background")]
59    pub accordion: Option<SharedString>,
60    /// Accordion hover background color.
61    #[serde(rename = "accordion.hover.background")]
62    pub accordion_hover: Option<SharedString>,
63    /// Default background color.
64    #[serde(rename = "background")]
65    pub background: Option<SharedString>,
66    /// Default border color
67    #[serde(rename = "border")]
68    pub border: Option<SharedString>,
69    /// Background color for GroupBox.
70    #[serde(rename = "group_box.background")]
71    pub group_box: Option<SharedString>,
72    /// Text color for GroupBox.
73    #[serde(rename = "group_box.foreground")]
74    pub group_box_foreground: Option<SharedString>,
75    /// Title text color for GroupBox.
76    #[serde(rename = "group_box.title.foreground")]
77    pub group_box_title_foreground: Option<SharedString>,
78    /// Input caret color (Blinking cursor).
79    #[serde(rename = "caret")]
80    pub caret: Option<SharedString>,
81    /// Chart 1 color.
82    #[serde(rename = "chart.1")]
83    pub chart_1: Option<SharedString>,
84    /// Chart 2 color.
85    #[serde(rename = "chart.2")]
86    pub chart_2: Option<SharedString>,
87    /// Chart 3 color.
88    #[serde(rename = "chart.3")]
89    pub chart_3: Option<SharedString>,
90    /// Chart 4 color.
91    #[serde(rename = "chart.4")]
92    pub chart_4: Option<SharedString>,
93    /// Chart 5 color.
94    #[serde(rename = "chart.5")]
95    pub chart_5: Option<SharedString>,
96    /// Danger background color.
97    #[serde(rename = "danger.background")]
98    pub danger: Option<SharedString>,
99    /// Danger active background color.
100    #[serde(rename = "danger.active.background")]
101    pub danger_active: Option<SharedString>,
102    /// Danger text color.
103    #[serde(rename = "danger.foreground")]
104    pub danger_foreground: Option<SharedString>,
105    /// Danger hover background color.
106    #[serde(rename = "danger.hover.background")]
107    pub danger_hover: Option<SharedString>,
108    /// Description List label background color.
109    #[serde(rename = "description_list.label.background")]
110    pub description_list_label: Option<SharedString>,
111    /// Description List label foreground color.
112    #[serde(rename = "description_list.label.foreground")]
113    pub description_list_label_foreground: Option<SharedString>,
114    /// Drag border color.
115    #[serde(rename = "drag.border")]
116    pub drag_border: Option<SharedString>,
117    /// Drop target background color.
118    #[serde(rename = "drop_target.background")]
119    pub drop_target: Option<SharedString>,
120    /// Default text color.
121    #[serde(rename = "foreground")]
122    pub foreground: Option<SharedString>,
123    /// Info background color.
124    #[serde(rename = "info.background")]
125    pub info: Option<SharedString>,
126    /// Info active background color.
127    #[serde(rename = "info.active.background")]
128    pub info_active: Option<SharedString>,
129    /// Info text color.
130    #[serde(rename = "info.foreground")]
131    pub info_foreground: Option<SharedString>,
132    /// Info hover background color.
133    #[serde(rename = "info.hover.background")]
134    pub info_hover: Option<SharedString>,
135    /// Border color for inputs such as Input, Dropdown, etc.
136    #[serde(rename = "input.border")]
137    pub input: Option<SharedString>,
138    /// Link text color.
139    #[serde(rename = "link")]
140    pub link: Option<SharedString>,
141    /// Active link text color.
142    #[serde(rename = "link.active")]
143    pub link_active: Option<SharedString>,
144    /// Hover link text color.
145    #[serde(rename = "link.hover")]
146    pub link_hover: Option<SharedString>,
147    /// Background color for List and ListItem.
148    #[serde(rename = "list.background")]
149    pub list: Option<SharedString>,
150    /// Background color for active ListItem.
151    #[serde(rename = "list.active.background")]
152    pub list_active: Option<SharedString>,
153    /// Border color for active ListItem.
154    #[serde(rename = "list.active.border")]
155    pub list_active_border: Option<SharedString>,
156    /// Stripe background color for even ListItem.
157    #[serde(rename = "list.even.background")]
158    pub list_even: Option<SharedString>,
159    /// Background color for List header.
160    #[serde(rename = "list.head.background")]
161    pub list_head: Option<SharedString>,
162    /// Hover background color for ListItem.
163    #[serde(rename = "list.hover.background")]
164    pub list_hover: Option<SharedString>,
165    /// Muted backgrounds such as Skeleton and Switch.
166    #[serde(rename = "muted.background")]
167    pub muted: Option<SharedString>,
168    /// Muted text color, as used in disabled text.
169    #[serde(rename = "muted.foreground")]
170    pub muted_foreground: Option<SharedString>,
171    /// Background color for Popover.
172    #[serde(rename = "popover.background")]
173    pub popover: Option<SharedString>,
174    /// Text color for Popover.
175    #[serde(rename = "popover.foreground")]
176    pub popover_foreground: Option<SharedString>,
177    /// Primary background color.
178    #[serde(rename = "primary.background")]
179    pub primary: Option<SharedString>,
180    /// Active primary background color.
181    #[serde(rename = "primary.active.background")]
182    pub primary_active: Option<SharedString>,
183    /// Primary text color.
184    #[serde(rename = "primary.foreground")]
185    pub primary_foreground: Option<SharedString>,
186    /// Hover primary background color.
187    #[serde(rename = "primary.hover.background")]
188    pub primary_hover: Option<SharedString>,
189    /// Progress bar background color.
190    #[serde(rename = "progress.bar.background")]
191    pub progress_bar: Option<SharedString>,
192    /// Used for focus ring.
193    #[serde(rename = "ring")]
194    pub ring: Option<SharedString>,
195    /// Scrollbar background color.
196    #[serde(rename = "scrollbar.background")]
197    pub scrollbar: Option<SharedString>,
198    /// Scrollbar thumb background color.
199    #[serde(rename = "scrollbar.thumb.background")]
200    pub scrollbar_thumb: Option<SharedString>,
201    /// Scrollbar thumb hover background color.
202    #[serde(rename = "scrollbar.thumb.hover.background")]
203    pub scrollbar_thumb_hover: Option<SharedString>,
204    /// Secondary background color.
205    #[serde(rename = "secondary.background")]
206    pub secondary: Option<SharedString>,
207    /// Active secondary background color.
208    #[serde(rename = "secondary.active.background")]
209    pub secondary_active: Option<SharedString>,
210    /// Secondary text color, used for secondary Button text color or secondary text.
211    #[serde(rename = "secondary.foreground")]
212    pub secondary_foreground: Option<SharedString>,
213    /// Hover secondary background color.
214    #[serde(rename = "secondary.hover.background")]
215    pub secondary_hover: Option<SharedString>,
216    /// Input selection background color.
217    #[serde(rename = "selection.background")]
218    pub selection: Option<SharedString>,
219    /// Sidebar background color.
220    #[serde(rename = "sidebar.background")]
221    pub sidebar: Option<SharedString>,
222    /// Sidebar accent background color.
223    #[serde(rename = "sidebar.accent.background")]
224    pub sidebar_accent: Option<SharedString>,
225    /// Sidebar accent text color.
226    #[serde(rename = "sidebar.accent.foreground")]
227    pub sidebar_accent_foreground: Option<SharedString>,
228    /// Sidebar border color.
229    #[serde(rename = "sidebar.border")]
230    pub sidebar_border: Option<SharedString>,
231    /// Sidebar text color.
232    #[serde(rename = "sidebar.foreground")]
233    pub sidebar_foreground: Option<SharedString>,
234    /// Sidebar primary background color.
235    #[serde(rename = "sidebar.primary.background")]
236    pub sidebar_primary: Option<SharedString>,
237    /// Sidebar primary text color.
238    #[serde(rename = "sidebar.primary.foreground")]
239    pub sidebar_primary_foreground: Option<SharedString>,
240    /// Skeleton background color.
241    #[serde(rename = "skeleton.background")]
242    pub skeleton: Option<SharedString>,
243    /// Slider bar background color.
244    #[serde(rename = "slider.background")]
245    pub slider_bar: Option<SharedString>,
246    /// Slider thumb background color.
247    #[serde(rename = "slider.thumb.background")]
248    pub slider_thumb: Option<SharedString>,
249    /// Success background color.
250    #[serde(rename = "success.background")]
251    pub success: Option<SharedString>,
252    /// Success text color.
253    #[serde(rename = "success.foreground")]
254    pub success_foreground: Option<SharedString>,
255    /// Success hover background color.
256    #[serde(rename = "success.hover.background")]
257    pub success_hover: Option<SharedString>,
258    /// Success active background color.
259    #[serde(rename = "success.active.background")]
260    pub success_active: Option<SharedString>,
261    /// Switch background color.
262    #[serde(rename = "switch.background")]
263    pub switch: Option<SharedString>,
264    /// Tab background color.
265    #[serde(rename = "tab.background")]
266    pub tab: Option<SharedString>,
267    /// Tab active background color.
268    #[serde(rename = "tab.active.background")]
269    pub tab_active: Option<SharedString>,
270    /// Tab active text color.
271    #[serde(rename = "tab.active.foreground")]
272    pub tab_active_foreground: Option<SharedString>,
273    /// TabBar background color.
274    #[serde(rename = "tab_bar.background")]
275    pub tab_bar: Option<SharedString>,
276    /// TabBar segmented background color.
277    #[serde(rename = "tab_bar.segmented.background")]
278    pub tab_bar_segmented: Option<SharedString>,
279    /// Tab text color.
280    #[serde(rename = "tab.foreground")]
281    pub tab_foreground: Option<SharedString>,
282    /// Table background color.
283    #[serde(rename = "table.background")]
284    pub table: Option<SharedString>,
285    /// Table active item background color.
286    #[serde(rename = "table.active.background")]
287    pub table_active: Option<SharedString>,
288    /// Table active item border color.
289    #[serde(rename = "table.active.border")]
290    pub table_active_border: Option<SharedString>,
291    /// Stripe background color for even TableRow.
292    #[serde(rename = "table.even.background")]
293    pub table_even: Option<SharedString>,
294    /// Table head background color.
295    #[serde(rename = "table.head.background")]
296    pub table_head: Option<SharedString>,
297    /// Table head text color.
298    #[serde(rename = "table.head.foreground")]
299    pub table_head_foreground: Option<SharedString>,
300    /// Table item hover background color.
301    #[serde(rename = "table.hover.background")]
302    pub table_hover: Option<SharedString>,
303    /// Table row border color.
304    #[serde(rename = "table.row.border")]
305    pub table_row_border: Option<SharedString>,
306    /// TitleBar background color, use for Window title bar.
307    #[serde(rename = "title_bar.background")]
308    pub title_bar: Option<SharedString>,
309    /// TitleBar border color.
310    #[serde(rename = "title_bar.border")]
311    pub title_bar_border: Option<SharedString>,
312    /// Background color for Tiles.
313    #[serde(rename = "tiles.background")]
314    pub tiles: Option<SharedString>,
315    /// Warning background color.
316    #[serde(rename = "warning.background")]
317    pub warning: Option<SharedString>,
318    /// Warning active background color.
319    #[serde(rename = "warning.active.background")]
320    pub warning_active: Option<SharedString>,
321    /// Warning hover background color.
322    #[serde(rename = "warning.hover.background")]
323    pub warning_hover: Option<SharedString>,
324    /// Warning foreground color.
325    #[serde(rename = "warning.foreground")]
326    pub warning_foreground: Option<SharedString>,
327    /// Overlay background color.
328    #[serde(rename = "overlay")]
329    pub overlay: Option<SharedString>,
330    /// Window border color.
331    ///
332    /// # Platform specific:
333    ///
334    /// This is only works on Linux, other platforms we can't change the window border color.
335    #[serde(rename = "window.border")]
336    pub window_border: Option<SharedString>,
337
338    /// Base blue color.
339    #[serde(rename = "base.blue")]
340    blue: Option<String>,
341    /// Base light blue color.
342    #[serde(rename = "base.blue.light")]
343    blue_light: Option<String>,
344    /// Base cyan color.
345    #[serde(rename = "base.cyan")]
346    cyan: Option<String>,
347    /// Base light cyan color.
348    #[serde(rename = "base.cyan.light")]
349    cyan_light: Option<String>,
350    /// Base green color.
351    #[serde(rename = "base.green")]
352    green: Option<String>,
353    /// Base light green color.
354    #[serde(rename = "base.green.light")]
355    green_light: Option<String>,
356    /// Base magenta color.
357    #[serde(rename = "base.magenta")]
358    magenta: Option<String>,
359    #[serde(rename = "base.magenta.light")]
360    magenta_light: Option<String>,
361    /// Base red color.
362    #[serde(rename = "base.red")]
363    red: Option<String>,
364    /// Base light red color.
365    #[serde(rename = "base.red.light")]
366    red_light: Option<String>,
367    /// Base yellow color.
368    #[serde(rename = "base.yellow")]
369    yellow: Option<String>,
370    /// Base light yellow color.
371    #[serde(rename = "base.yellow.light")]
372    yellow_light: Option<String>,
373}
374
375/// Try to parse HEX color, `#RRGGBB` or `#RRGGBBAA`
376fn try_parse_color(color: &str) -> Result<Hsla> {
377    let rgba = gpui::Rgba::try_from(color)?;
378    Ok(rgba.into())
379}
380
381impl ThemeColor {
382    /// Create a new `ThemeColor` from a `ThemeConfig`.
383    pub(crate) fn apply_config(&mut self, config: &ThemeConfig, default_theme: &ThemeColor) {
384        let colors = config.colors.clone();
385
386        macro_rules! apply_color {
387            ($config_field:ident) => {
388                if let Some(value) = colors.$config_field {
389                    if let Ok(color) = try_parse_color(&value) {
390                        self.$config_field = color;
391                    } else {
392                        self.$config_field = default_theme.$config_field;
393                    }
394                } else {
395                    self.$config_field = default_theme.$config_field;
396                }
397            };
398            // With fallback
399            ($config_field:ident, fallback = $fallback:expr) => {
400                if let Some(value) = colors.$config_field {
401                    if let Ok(color) = try_parse_color(&value) {
402                        self.$config_field = color;
403                    }
404                } else {
405                    self.$config_field = $fallback;
406                }
407            };
408        }
409
410        apply_color!(background);
411
412        // Base colors for fallback
413        apply_color!(red);
414        apply_color!(
415            red_light,
416            fallback = self.background.blend(self.red.opacity(0.8))
417        );
418        apply_color!(green);
419        apply_color!(
420            green_light,
421            fallback = self.background.blend(self.green.opacity(0.8))
422        );
423        apply_color!(blue);
424        apply_color!(
425            blue_light,
426            fallback = self.background.blend(self.blue.opacity(0.8))
427        );
428        apply_color!(magenta);
429        apply_color!(
430            magenta_light,
431            fallback = self.background.blend(self.magenta.opacity(0.8))
432        );
433        apply_color!(yellow);
434        apply_color!(
435            yellow_light,
436            fallback = self.background.blend(self.yellow.opacity(0.8))
437        );
438        apply_color!(cyan);
439        apply_color!(
440            cyan_light,
441            fallback = self.background.blend(self.cyan.opacity(0.8))
442        );
443
444        apply_color!(border);
445        apply_color!(foreground);
446        apply_color!(muted);
447        apply_color!(
448            muted_foreground,
449            fallback = self.muted.blend(self.foreground.opacity(0.7))
450        );
451
452        // Button colors
453        let active_darken = if config.mode.is_dark() { 0.2 } else { 0.1 };
454        let hover_opacity = 0.9;
455        apply_color!(primary);
456        apply_color!(primary_foreground, fallback = self.foreground);
457        apply_color!(
458            primary_hover,
459            fallback = self.background.blend(self.primary.opacity(hover_opacity))
460        );
461        apply_color!(
462            primary_active,
463            fallback = self.primary.darken(active_darken)
464        );
465        apply_color!(secondary);
466        apply_color!(secondary_foreground, fallback = self.foreground);
467        apply_color!(
468            secondary_hover,
469            fallback = self.background.blend(self.secondary.opacity(hover_opacity))
470        );
471        apply_color!(
472            secondary_active,
473            fallback = self.secondary.darken(active_darken)
474        );
475        apply_color!(success, fallback = self.green);
476        apply_color!(success_foreground, fallback = self.primary_foreground);
477        apply_color!(
478            success_hover,
479            fallback = self.background.blend(self.success.opacity(hover_opacity))
480        );
481        apply_color!(
482            success_active,
483            fallback = self.success.darken(active_darken)
484        );
485        apply_color!(info, fallback = self.cyan);
486        apply_color!(info_foreground, fallback = self.primary_foreground);
487        apply_color!(
488            info_hover,
489            fallback = self.background.blend(self.info.opacity(hover_opacity))
490        );
491        apply_color!(info_active, fallback = self.info.darken(active_darken));
492        apply_color!(warning, fallback = self.yellow);
493        apply_color!(warning_foreground, fallback = self.primary_foreground);
494        apply_color!(
495            warning_hover,
496            fallback = self.background.blend(self.warning.opacity(0.9))
497        );
498        apply_color!(
499            warning_active,
500            fallback = self.background.blend(self.warning.darken(active_darken))
501        );
502
503        // Other colors
504        apply_color!(accent, fallback = self.secondary);
505        apply_color!(accent_foreground, fallback = self.secondary_foreground);
506        apply_color!(accordion, fallback = self.background);
507        apply_color!(accordion_hover, fallback = self.accent.opacity(0.8));
508        apply_color!(
509            group_box,
510            fallback = self
511                .background
512                .blend(
513                    self.secondary
514                        .opacity(if config.mode.is_dark() { 0.3 } else { 0.4 })
515                )
516        );
517        apply_color!(group_box_foreground, fallback = self.secondary_foreground);
518        apply_color!(caret, fallback = self.primary);
519        apply_color!(chart_1, fallback = self.blue.lighten(0.4));
520        apply_color!(chart_2, fallback = self.blue.lighten(0.2));
521        apply_color!(chart_3, fallback = self.blue);
522        apply_color!(chart_4, fallback = self.blue.darken(0.2));
523        apply_color!(chart_5, fallback = self.blue.darken(0.4));
524        apply_color!(danger, fallback = self.red);
525        apply_color!(danger_active, fallback = self.danger.darken(active_darken));
526        apply_color!(danger_foreground, fallback = self.primary_foreground);
527        apply_color!(
528            danger_hover,
529            fallback = self.background.blend(self.danger.opacity(0.9))
530        );
531        apply_color!(
532            description_list_label,
533            fallback = self.background.blend(self.border.opacity(0.2))
534        );
535        apply_color!(
536            description_list_label_foreground,
537            fallback = self.secondary_foreground
538        );
539        apply_color!(drag_border, fallback = self.primary.opacity(0.65));
540        apply_color!(drop_target, fallback = self.primary.opacity(0.2));
541        apply_color!(input, fallback = self.border);
542        apply_color!(link, fallback = self.primary);
543        apply_color!(link_active, fallback = self.link);
544        apply_color!(link_hover, fallback = self.link);
545        apply_color!(list, fallback = self.background);
546        apply_color!(
547            list_active,
548            fallback = self.background.blend(self.primary.opacity(0.1))
549        );
550        apply_color!(
551            list_active_border,
552            fallback = self.background.blend(self.primary.opacity(0.6))
553        );
554        apply_color!(list_even, fallback = self.list);
555        apply_color!(list_head, fallback = self.list);
556        apply_color!(list_hover, fallback = self.secondary_hover);
557        apply_color!(popover, fallback = self.background);
558        apply_color!(popover_foreground, fallback = self.foreground);
559        apply_color!(progress_bar, fallback = self.primary);
560        apply_color!(ring, fallback = self.blue);
561        apply_color!(scrollbar, fallback = self.background);
562        apply_color!(scrollbar_thumb, fallback = self.accent);
563        apply_color!(scrollbar_thumb_hover, fallback = self.scrollbar_thumb);
564        apply_color!(selection, fallback = self.primary);
565        apply_color!(sidebar, fallback = self.background);
566        apply_color!(sidebar_accent, fallback = self.accent);
567        apply_color!(sidebar_accent_foreground, fallback = self.accent_foreground);
568        apply_color!(sidebar_border, fallback = self.border);
569        apply_color!(sidebar_foreground, fallback = self.foreground);
570        apply_color!(sidebar_primary, fallback = self.primary);
571        apply_color!(
572            sidebar_primary_foreground,
573            fallback = self.primary_foreground
574        );
575        apply_color!(skeleton, fallback = self.secondary);
576        apply_color!(slider_bar, fallback = self.primary);
577        apply_color!(slider_thumb, fallback = self.primary_foreground);
578        apply_color!(switch, fallback = self.secondary);
579        apply_color!(tab, fallback = self.background);
580        apply_color!(tab_active, fallback = self.background);
581        apply_color!(tab_active_foreground, fallback = self.foreground);
582        apply_color!(tab_bar, fallback = self.background);
583        apply_color!(tab_bar_segmented, fallback = self.secondary);
584        apply_color!(tab_foreground, fallback = self.secondary_foreground);
585        apply_color!(table, fallback = self.list);
586        apply_color!(table_active, fallback = self.list_active);
587        apply_color!(table_active_border, fallback = self.list_active_border);
588        apply_color!(table_even, fallback = self.list_even);
589        apply_color!(table_head, fallback = self.list_head);
590        apply_color!(table_head_foreground, fallback = self.muted_foreground);
591        apply_color!(table_hover, fallback = self.list_hover);
592        apply_color!(table_row_border, fallback = self.border);
593        apply_color!(title_bar, fallback = self.background);
594        apply_color!(title_bar_border, fallback = self.border);
595        apply_color!(tiles, fallback = self.background);
596        apply_color!(overlay);
597        apply_color!(window_border, fallback = self.border);
598
599        // TODO: Apply default fallback colors to highlight.
600
601        // Ensure opacity for list_active, table_active
602        self.list_active = self.list_active.alpha(0.2);
603        self.table_active = self.table_active.alpha(0.2);
604        self.selection = self.selection.alpha(0.3);
605    }
606}
607
608impl Theme {
609    /// Apply the given theme configuration to the current theme.
610    pub fn apply_config(&mut self, config: &Rc<ThemeConfig>) {
611        if config.mode.is_dark() {
612            self.dark_theme = config.clone();
613        } else {
614            self.light_theme = config.clone();
615        }
616        if let Some(style) = &config.highlight {
617            let highlight_theme = Arc::new(HighlightTheme {
618                name: config.name.to_string(),
619                appearance: config.mode,
620                style: style.clone(),
621            });
622            self.highlight_theme = highlight_theme.clone();
623        }
624
625        let default_theme = if config.mode.is_dark() {
626            ThemeColor::dark()
627        } else {
628            ThemeColor::light()
629        };
630
631        self.colors.apply_config(&config, &default_theme);
632        self.mode = config.mode;
633    }
634}
635
636#[cfg(test)]
637mod tests {
638    use super::try_parse_color;
639    use gpui::hsla;
640
641    #[test]
642    fn test_try_parse_color() {
643        assert_eq!(
644            try_parse_color("#F2F200").ok(),
645            Some(hsla(0.16666667, 1., 0.4745098, 1.0))
646        );
647        assert_eq!(
648            try_parse_color("#00f21888").ok(),
649            Some(hsla(0.34986225, 1.0, 0.4745098, 0.53333336))
650        );
651    }
652}