1#![allow(missing_docs)]
2
3use gpui::{App, Hsla, SharedString, WindowBackgroundAppearance};
4use refineable::Refineable;
5use std::sync::Arc;
6use strum::{AsRefStr, EnumIter, IntoEnumIterator};
7
8use crate::{
9 AccentColors, ActiveTheme, PlayerColors, StatusColors, StatusColorsRefinement, SyntaxTheme,
10 SystemColors,
11};
12
13#[derive(Refineable, Clone, Debug, PartialEq)]
14#[refineable(Debug, serde::Deserialize)]
15pub struct ThemeColors {
16 pub border: Hsla,
18 pub border_variant: Hsla,
20 pub border_focused: Hsla,
22 pub border_selected: Hsla,
24 pub border_transparent: Hsla,
26 pub border_disabled: Hsla,
28 pub elevated_surface_background: Hsla,
30 pub surface_background: Hsla,
32 pub background: Hsla,
34 pub element_background: Hsla,
40 pub element_hover: Hsla,
44 pub element_active: Hsla,
48 pub element_selected: Hsla,
54 pub element_selection_background: Hsla,
56 pub element_disabled: Hsla,
60 pub drop_target_background: Hsla,
62 pub drop_target_border: Hsla,
64 pub ghost_element_background: Hsla,
70 pub ghost_element_hover: Hsla,
74 pub ghost_element_active: Hsla,
78 pub ghost_element_selected: Hsla,
84 pub ghost_element_disabled: Hsla,
88 pub text: Hsla,
90 pub text_muted: Hsla,
92 pub text_placeholder: Hsla,
94 pub text_disabled: Hsla,
96 pub text_accent: Hsla,
98 pub icon: Hsla,
100 pub icon_muted: Hsla,
104 pub icon_disabled: Hsla,
108 pub icon_placeholder: Hsla,
112 pub icon_accent: Hsla,
116 pub debugger_accent: Hsla,
119
120 pub status_bar_background: Hsla,
124 pub title_bar_background: Hsla,
125 pub title_bar_inactive_background: Hsla,
126 pub toolbar_background: Hsla,
127 pub tab_bar_background: Hsla,
128 pub tab_inactive_background: Hsla,
129 pub tab_active_background: Hsla,
130 pub search_match_background: Hsla,
131 pub search_active_match_background: Hsla,
132 pub panel_background: Hsla,
133 pub panel_focused_border: Hsla,
134 pub panel_indent_guide: Hsla,
135 pub panel_indent_guide_hover: Hsla,
136 pub panel_indent_guide_active: Hsla,
137
138 pub panel_overlay_background: Hsla,
140 pub panel_overlay_hover: Hsla,
142
143 pub pane_focused_border: Hsla,
144 pub pane_group_border: Hsla,
145 pub scrollbar_thumb_background: Hsla,
147 pub scrollbar_thumb_hover_background: Hsla,
149 pub scrollbar_thumb_active_background: Hsla,
151 pub scrollbar_thumb_border: Hsla,
153 pub scrollbar_track_background: Hsla,
155 pub scrollbar_track_border: Hsla,
157 pub minimap_thumb_background: Hsla,
159 pub minimap_thumb_hover_background: Hsla,
161 pub minimap_thumb_active_background: Hsla,
163 pub minimap_thumb_border: Hsla,
165
166 pub vim_normal_background: Hsla,
168 pub vim_insert_background: Hsla,
170 pub vim_replace_background: Hsla,
172 pub vim_visual_background: Hsla,
174 pub vim_visual_line_background: Hsla,
176 pub vim_visual_block_background: Hsla,
178 pub vim_yank_background: Hsla,
180 pub vim_helix_jump_label_foreground: Hsla,
182 pub vim_helix_normal_background: Hsla,
184 pub vim_helix_select_background: Hsla,
186 pub vim_normal_foreground: Hsla,
188 pub vim_insert_foreground: Hsla,
190 pub vim_replace_foreground: Hsla,
192 pub vim_visual_foreground: Hsla,
194 pub vim_visual_line_foreground: Hsla,
196 pub vim_visual_block_foreground: Hsla,
198 pub vim_helix_normal_foreground: Hsla,
200 pub vim_helix_select_foreground: Hsla,
202
203 pub editor_foreground: Hsla,
207 pub editor_background: Hsla,
208 pub editor_gutter_background: Hsla,
209 pub editor_subheader_background: Hsla,
210 pub editor_active_line_background: Hsla,
211 pub editor_highlighted_line_background: Hsla,
212 pub editor_debugger_active_line_background: Hsla,
214 pub editor_line_number: Hsla,
216 pub editor_active_line_number: Hsla,
218 pub editor_hover_line_number: Hsla,
220 pub editor_invisible: Hsla,
224 pub editor_wrap_guide: Hsla,
225 pub editor_active_wrap_guide: Hsla,
226 pub editor_indent_guide: Hsla,
227 pub editor_indent_guide_active: Hsla,
228 pub editor_document_highlight_read_background: Hsla,
234 pub editor_document_highlight_write_background: Hsla,
240 pub editor_document_highlight_bracket_background: Hsla,
244
245 pub terminal_background: Hsla,
250 pub terminal_foreground: Hsla,
252 pub terminal_bright_foreground: Hsla,
254 pub terminal_dim_foreground: Hsla,
256 pub terminal_ansi_background: Hsla,
258 pub terminal_ansi_black: Hsla,
260 pub terminal_ansi_bright_black: Hsla,
262 pub terminal_ansi_dim_black: Hsla,
264 pub terminal_ansi_red: Hsla,
266 pub terminal_ansi_bright_red: Hsla,
268 pub terminal_ansi_dim_red: Hsla,
270 pub terminal_ansi_green: Hsla,
272 pub terminal_ansi_bright_green: Hsla,
274 pub terminal_ansi_dim_green: Hsla,
276 pub terminal_ansi_yellow: Hsla,
278 pub terminal_ansi_bright_yellow: Hsla,
280 pub terminal_ansi_dim_yellow: Hsla,
282 pub terminal_ansi_blue: Hsla,
284 pub terminal_ansi_bright_blue: Hsla,
286 pub terminal_ansi_dim_blue: Hsla,
288 pub terminal_ansi_magenta: Hsla,
290 pub terminal_ansi_bright_magenta: Hsla,
292 pub terminal_ansi_dim_magenta: Hsla,
294 pub terminal_ansi_cyan: Hsla,
296 pub terminal_ansi_bright_cyan: Hsla,
298 pub terminal_ansi_dim_cyan: Hsla,
300 pub terminal_ansi_white: Hsla,
302 pub terminal_ansi_bright_white: Hsla,
304 pub terminal_ansi_dim_white: Hsla,
306
307 pub link_text_hover: Hsla,
309
310 pub version_control_added: Hsla,
312 pub version_control_deleted: Hsla,
314 pub version_control_modified: Hsla,
316 pub version_control_renamed: Hsla,
318 pub version_control_conflict: Hsla,
320 pub version_control_ignored: Hsla,
322 pub version_control_word_added: Hsla,
324 pub version_control_word_deleted: Hsla,
326 pub version_control_conflict_marker_ours: Hsla,
328 pub version_control_conflict_marker_theirs: Hsla,
330}
331
332#[derive(EnumIter, Debug, Clone, Copy, AsRefStr)]
333#[strum(serialize_all = "snake_case")]
334pub enum ThemeColorField {
335 Border,
336 BorderVariant,
337 BorderFocused,
338 BorderSelected,
339 BorderTransparent,
340 BorderDisabled,
341 ElevatedSurfaceBackground,
342 SurfaceBackground,
343 Background,
344 ElementBackground,
345 ElementHover,
346 ElementActive,
347 ElementSelected,
348 ElementDisabled,
349 DropTargetBackground,
350 DropTargetBorder,
351 GhostElementBackground,
352 GhostElementHover,
353 GhostElementActive,
354 GhostElementSelected,
355 GhostElementDisabled,
356 Text,
357 TextMuted,
358 TextPlaceholder,
359 TextDisabled,
360 TextAccent,
361 Icon,
362 IconMuted,
363 IconDisabled,
364 IconPlaceholder,
365 IconAccent,
366 StatusBarBackground,
367 TitleBarBackground,
368 TitleBarInactiveBackground,
369 ToolbarBackground,
370 TabBarBackground,
371 TabInactiveBackground,
372 TabActiveBackground,
373 SearchMatchBackground,
374 SearchActiveMatchBackground,
375 PanelBackground,
376 PanelFocusedBorder,
377 PanelIndentGuide,
378 PanelIndentGuideHover,
379 PanelIndentGuideActive,
380 PanelOverlayBackground,
381 PanelOverlayHover,
382 PaneFocusedBorder,
383 PaneGroupBorder,
384 ScrollbarThumbBackground,
385 ScrollbarThumbHoverBackground,
386 ScrollbarThumbActiveBackground,
387 ScrollbarThumbBorder,
388 ScrollbarTrackBackground,
389 ScrollbarTrackBorder,
390 MinimapThumbBackground,
391 MinimapThumbHoverBackground,
392 MinimapThumbActiveBackground,
393 MinimapThumbBorder,
394 EditorForeground,
395 EditorBackground,
396 EditorGutterBackground,
397 EditorSubheaderBackground,
398 EditorActiveLineBackground,
399 EditorHighlightedLineBackground,
400 EditorLineNumber,
401 EditorActiveLineNumber,
402 EditorInvisible,
403 EditorWrapGuide,
404 EditorActiveWrapGuide,
405 EditorIndentGuide,
406 EditorIndentGuideActive,
407 EditorDocumentHighlightReadBackground,
408 EditorDocumentHighlightWriteBackground,
409 EditorDocumentHighlightBracketBackground,
410 TerminalBackground,
411 TerminalForeground,
412 TerminalBrightForeground,
413 TerminalDimForeground,
414 TerminalAnsiBackground,
415 TerminalAnsiBlack,
416 TerminalAnsiBrightBlack,
417 TerminalAnsiDimBlack,
418 TerminalAnsiRed,
419 TerminalAnsiBrightRed,
420 TerminalAnsiDimRed,
421 TerminalAnsiGreen,
422 TerminalAnsiBrightGreen,
423 TerminalAnsiDimGreen,
424 TerminalAnsiYellow,
425 TerminalAnsiBrightYellow,
426 TerminalAnsiDimYellow,
427 TerminalAnsiBlue,
428 TerminalAnsiBrightBlue,
429 TerminalAnsiDimBlue,
430 TerminalAnsiMagenta,
431 TerminalAnsiBrightMagenta,
432 TerminalAnsiDimMagenta,
433 TerminalAnsiCyan,
434 TerminalAnsiBrightCyan,
435 TerminalAnsiDimCyan,
436 TerminalAnsiWhite,
437 TerminalAnsiBrightWhite,
438 TerminalAnsiDimWhite,
439 LinkTextHover,
440 VersionControlAdded,
441 VersionControlDeleted,
442 VersionControlModified,
443 VersionControlRenamed,
444 VersionControlConflict,
445 VersionControlIgnored,
446}
447
448impl ThemeColors {
449 pub fn color(&self, field: ThemeColorField) -> Hsla {
450 match field {
451 ThemeColorField::Border => self.border,
452 ThemeColorField::BorderVariant => self.border_variant,
453 ThemeColorField::BorderFocused => self.border_focused,
454 ThemeColorField::BorderSelected => self.border_selected,
455 ThemeColorField::BorderTransparent => self.border_transparent,
456 ThemeColorField::BorderDisabled => self.border_disabled,
457 ThemeColorField::ElevatedSurfaceBackground => self.elevated_surface_background,
458 ThemeColorField::SurfaceBackground => self.surface_background,
459 ThemeColorField::Background => self.background,
460 ThemeColorField::ElementBackground => self.element_background,
461 ThemeColorField::ElementHover => self.element_hover,
462 ThemeColorField::ElementActive => self.element_active,
463 ThemeColorField::ElementSelected => self.element_selected,
464 ThemeColorField::ElementDisabled => self.element_disabled,
465 ThemeColorField::DropTargetBackground => self.drop_target_background,
466 ThemeColorField::DropTargetBorder => self.drop_target_border,
467 ThemeColorField::GhostElementBackground => self.ghost_element_background,
468 ThemeColorField::GhostElementHover => self.ghost_element_hover,
469 ThemeColorField::GhostElementActive => self.ghost_element_active,
470 ThemeColorField::GhostElementSelected => self.ghost_element_selected,
471 ThemeColorField::GhostElementDisabled => self.ghost_element_disabled,
472 ThemeColorField::Text => self.text,
473 ThemeColorField::TextMuted => self.text_muted,
474 ThemeColorField::TextPlaceholder => self.text_placeholder,
475 ThemeColorField::TextDisabled => self.text_disabled,
476 ThemeColorField::TextAccent => self.text_accent,
477 ThemeColorField::Icon => self.icon,
478 ThemeColorField::IconMuted => self.icon_muted,
479 ThemeColorField::IconDisabled => self.icon_disabled,
480 ThemeColorField::IconPlaceholder => self.icon_placeholder,
481 ThemeColorField::IconAccent => self.icon_accent,
482 ThemeColorField::StatusBarBackground => self.status_bar_background,
483 ThemeColorField::TitleBarBackground => self.title_bar_background,
484 ThemeColorField::TitleBarInactiveBackground => self.title_bar_inactive_background,
485 ThemeColorField::ToolbarBackground => self.toolbar_background,
486 ThemeColorField::TabBarBackground => self.tab_bar_background,
487 ThemeColorField::TabInactiveBackground => self.tab_inactive_background,
488 ThemeColorField::TabActiveBackground => self.tab_active_background,
489 ThemeColorField::SearchMatchBackground => self.search_match_background,
490 ThemeColorField::SearchActiveMatchBackground => self.search_active_match_background,
491 ThemeColorField::PanelBackground => self.panel_background,
492 ThemeColorField::PanelFocusedBorder => self.panel_focused_border,
493 ThemeColorField::PanelIndentGuide => self.panel_indent_guide,
494 ThemeColorField::PanelIndentGuideHover => self.panel_indent_guide_hover,
495 ThemeColorField::PanelIndentGuideActive => self.panel_indent_guide_active,
496 ThemeColorField::PanelOverlayBackground => self.panel_overlay_background,
497 ThemeColorField::PanelOverlayHover => self.panel_overlay_hover,
498 ThemeColorField::PaneFocusedBorder => self.pane_focused_border,
499 ThemeColorField::PaneGroupBorder => self.pane_group_border,
500 ThemeColorField::ScrollbarThumbBackground => self.scrollbar_thumb_background,
501 ThemeColorField::ScrollbarThumbHoverBackground => self.scrollbar_thumb_hover_background,
502 ThemeColorField::ScrollbarThumbActiveBackground => {
503 self.scrollbar_thumb_active_background
504 }
505 ThemeColorField::ScrollbarThumbBorder => self.scrollbar_thumb_border,
506 ThemeColorField::ScrollbarTrackBackground => self.scrollbar_track_background,
507 ThemeColorField::ScrollbarTrackBorder => self.scrollbar_track_border,
508 ThemeColorField::MinimapThumbBackground => self.minimap_thumb_background,
509 ThemeColorField::MinimapThumbHoverBackground => self.minimap_thumb_hover_background,
510 ThemeColorField::MinimapThumbActiveBackground => self.minimap_thumb_active_background,
511 ThemeColorField::MinimapThumbBorder => self.minimap_thumb_border,
512 ThemeColorField::EditorForeground => self.editor_foreground,
513 ThemeColorField::EditorBackground => self.editor_background,
514 ThemeColorField::EditorGutterBackground => self.editor_gutter_background,
515 ThemeColorField::EditorSubheaderBackground => self.editor_subheader_background,
516 ThemeColorField::EditorActiveLineBackground => self.editor_active_line_background,
517 ThemeColorField::EditorHighlightedLineBackground => {
518 self.editor_highlighted_line_background
519 }
520 ThemeColorField::EditorLineNumber => self.editor_line_number,
521 ThemeColorField::EditorActiveLineNumber => self.editor_active_line_number,
522 ThemeColorField::EditorInvisible => self.editor_invisible,
523 ThemeColorField::EditorWrapGuide => self.editor_wrap_guide,
524 ThemeColorField::EditorActiveWrapGuide => self.editor_active_wrap_guide,
525 ThemeColorField::EditorIndentGuide => self.editor_indent_guide,
526 ThemeColorField::EditorIndentGuideActive => self.editor_indent_guide_active,
527 ThemeColorField::EditorDocumentHighlightReadBackground => {
528 self.editor_document_highlight_read_background
529 }
530 ThemeColorField::EditorDocumentHighlightWriteBackground => {
531 self.editor_document_highlight_write_background
532 }
533 ThemeColorField::EditorDocumentHighlightBracketBackground => {
534 self.editor_document_highlight_bracket_background
535 }
536 ThemeColorField::TerminalBackground => self.terminal_background,
537 ThemeColorField::TerminalForeground => self.terminal_foreground,
538 ThemeColorField::TerminalBrightForeground => self.terminal_bright_foreground,
539 ThemeColorField::TerminalDimForeground => self.terminal_dim_foreground,
540 ThemeColorField::TerminalAnsiBackground => self.terminal_ansi_background,
541 ThemeColorField::TerminalAnsiBlack => self.terminal_ansi_black,
542 ThemeColorField::TerminalAnsiBrightBlack => self.terminal_ansi_bright_black,
543 ThemeColorField::TerminalAnsiDimBlack => self.terminal_ansi_dim_black,
544 ThemeColorField::TerminalAnsiRed => self.terminal_ansi_red,
545 ThemeColorField::TerminalAnsiBrightRed => self.terminal_ansi_bright_red,
546 ThemeColorField::TerminalAnsiDimRed => self.terminal_ansi_dim_red,
547 ThemeColorField::TerminalAnsiGreen => self.terminal_ansi_green,
548 ThemeColorField::TerminalAnsiBrightGreen => self.terminal_ansi_bright_green,
549 ThemeColorField::TerminalAnsiDimGreen => self.terminal_ansi_dim_green,
550 ThemeColorField::TerminalAnsiYellow => self.terminal_ansi_yellow,
551 ThemeColorField::TerminalAnsiBrightYellow => self.terminal_ansi_bright_yellow,
552 ThemeColorField::TerminalAnsiDimYellow => self.terminal_ansi_dim_yellow,
553 ThemeColorField::TerminalAnsiBlue => self.terminal_ansi_blue,
554 ThemeColorField::TerminalAnsiBrightBlue => self.terminal_ansi_bright_blue,
555 ThemeColorField::TerminalAnsiDimBlue => self.terminal_ansi_dim_blue,
556 ThemeColorField::TerminalAnsiMagenta => self.terminal_ansi_magenta,
557 ThemeColorField::TerminalAnsiBrightMagenta => self.terminal_ansi_bright_magenta,
558 ThemeColorField::TerminalAnsiDimMagenta => self.terminal_ansi_dim_magenta,
559 ThemeColorField::TerminalAnsiCyan => self.terminal_ansi_cyan,
560 ThemeColorField::TerminalAnsiBrightCyan => self.terminal_ansi_bright_cyan,
561 ThemeColorField::TerminalAnsiDimCyan => self.terminal_ansi_dim_cyan,
562 ThemeColorField::TerminalAnsiWhite => self.terminal_ansi_white,
563 ThemeColorField::TerminalAnsiBrightWhite => self.terminal_ansi_bright_white,
564 ThemeColorField::TerminalAnsiDimWhite => self.terminal_ansi_dim_white,
565 ThemeColorField::LinkTextHover => self.link_text_hover,
566 ThemeColorField::VersionControlAdded => self.version_control_added,
567 ThemeColorField::VersionControlDeleted => self.version_control_deleted,
568 ThemeColorField::VersionControlModified => self.version_control_modified,
569 ThemeColorField::VersionControlRenamed => self.version_control_renamed,
570 ThemeColorField::VersionControlConflict => self.version_control_conflict,
571 ThemeColorField::VersionControlIgnored => self.version_control_ignored,
572 }
573 }
574
575 pub fn iter(&self) -> impl Iterator<Item = (ThemeColorField, Hsla)> + '_ {
576 ThemeColorField::iter().map(move |field| (field, self.color(field)))
577 }
578
579 pub fn to_vec(&self) -> Vec<(ThemeColorField, Hsla)> {
580 self.iter().collect()
581 }
582}
583
584pub fn all_theme_colors(cx: &mut App) -> Vec<(Hsla, SharedString)> {
585 let theme = cx.theme();
586 ThemeColorField::iter()
587 .map(|field| {
588 let color = theme.colors().color(field);
589 let name = field.as_ref().to_string();
590 (color, SharedString::from(name))
591 })
592 .collect()
593}
594
595#[derive(Refineable, Clone, Debug, PartialEq)]
596pub struct ThemeStyles {
597 pub window_background_appearance: WindowBackgroundAppearance,
599 pub system: SystemColors,
600 pub accents: AccentColors,
604
605 #[refineable]
606 pub colors: ThemeColors,
607
608 #[refineable]
609 pub status: StatusColors,
610
611 pub player: PlayerColors,
612
613 pub syntax: Arc<SyntaxTheme>,
614}
615
616#[cfg(test)]
617mod tests {
618 use serde_json::json;
619
620 use super::*;
621
622 #[test]
623 fn override_a_single_theme_color() {
624 let mut colors = ThemeColors::light();
625
626 let magenta: Hsla = gpui::rgb(0xff00ff).into();
627
628 assert_ne!(colors.text, magenta);
629
630 let overrides = ThemeColorsRefinement {
631 text: Some(magenta),
632 ..Default::default()
633 };
634
635 colors.refine(&overrides);
636
637 assert_eq!(colors.text, magenta);
638 }
639
640 #[test]
641 fn override_multiple_theme_colors() {
642 let mut colors = ThemeColors::light();
643
644 let magenta: Hsla = gpui::rgb(0xff00ff).into();
645 let green: Hsla = gpui::rgb(0x00ff00).into();
646
647 assert_ne!(colors.text, magenta);
648 assert_ne!(colors.background, green);
649
650 let overrides = ThemeColorsRefinement {
651 text: Some(magenta),
652 background: Some(green),
653 ..Default::default()
654 };
655
656 colors.refine(&overrides);
657
658 assert_eq!(colors.text, magenta);
659 assert_eq!(colors.background, green);
660 }
661
662 #[test]
663 fn deserialize_theme_colors_refinement_from_json() {
664 let colors: ThemeColorsRefinement = serde_json::from_value(json!({
665 "background": "#ff00ff",
666 "text": "#ff0000"
667 }))
668 .unwrap();
669
670 assert_eq!(colors.background, Some(gpui::rgb(0xff00ff).into()));
671 assert_eq!(colors.text, Some(gpui::rgb(0xff0000).into()));
672 }
673}