#![allow(missing_docs)]
use gpui::{App, Hsla, SharedString, WindowBackgroundAppearance};
use refineable::Refineable;
use std::sync::Arc;
use strum::{AsRefStr, EnumIter, IntoEnumIterator};
use crate::{
AccentColors, ActiveTheme, PlayerColors, StatusColors, StatusColorsRefinement, SyntaxTheme,
SystemColors,
};
#[derive(Refineable, Clone, Debug, PartialEq)]
#[refineable(Debug, serde::Deserialize)]
pub struct ThemeColors {
pub border: Hsla,
pub border_variant: Hsla,
pub border_focused: Hsla,
pub border_selected: Hsla,
pub border_transparent: Hsla,
pub border_disabled: Hsla,
pub elevated_surface_background: Hsla,
pub surface_background: Hsla,
pub background: Hsla,
pub element_background: Hsla,
pub element_hover: Hsla,
pub element_active: Hsla,
pub element_selected: Hsla,
pub element_selection_background: Hsla,
pub element_disabled: Hsla,
pub drop_target_background: Hsla,
pub drop_target_border: Hsla,
pub ghost_element_background: Hsla,
pub ghost_element_hover: Hsla,
pub ghost_element_active: Hsla,
pub ghost_element_selected: Hsla,
pub ghost_element_disabled: Hsla,
pub text: Hsla,
pub text_muted: Hsla,
pub text_placeholder: Hsla,
pub text_disabled: Hsla,
pub text_accent: Hsla,
pub icon: Hsla,
pub icon_muted: Hsla,
pub icon_disabled: Hsla,
pub icon_placeholder: Hsla,
pub icon_accent: Hsla,
pub debugger_accent: Hsla,
pub status_bar_background: Hsla,
pub title_bar_background: Hsla,
pub title_bar_inactive_background: Hsla,
pub toolbar_background: Hsla,
pub tab_bar_background: Hsla,
pub tab_inactive_background: Hsla,
pub tab_active_background: Hsla,
pub search_match_background: Hsla,
pub search_active_match_background: Hsla,
pub panel_background: Hsla,
pub panel_focused_border: Hsla,
pub panel_indent_guide: Hsla,
pub panel_indent_guide_hover: Hsla,
pub panel_indent_guide_active: Hsla,
pub panel_overlay_background: Hsla,
pub panel_overlay_hover: Hsla,
pub pane_focused_border: Hsla,
pub pane_group_border: Hsla,
pub scrollbar_thumb_background: Hsla,
pub scrollbar_thumb_hover_background: Hsla,
pub scrollbar_thumb_active_background: Hsla,
pub scrollbar_thumb_border: Hsla,
pub scrollbar_track_background: Hsla,
pub scrollbar_track_border: Hsla,
pub minimap_thumb_background: Hsla,
pub minimap_thumb_hover_background: Hsla,
pub minimap_thumb_active_background: Hsla,
pub minimap_thumb_border: Hsla,
pub vim_normal_background: Hsla,
pub vim_insert_background: Hsla,
pub vim_replace_background: Hsla,
pub vim_visual_background: Hsla,
pub vim_visual_line_background: Hsla,
pub vim_visual_block_background: Hsla,
pub vim_yank_background: Hsla,
pub vim_helix_jump_label_foreground: Hsla,
pub vim_helix_normal_background: Hsla,
pub vim_helix_select_background: Hsla,
pub vim_normal_foreground: Hsla,
pub vim_insert_foreground: Hsla,
pub vim_replace_foreground: Hsla,
pub vim_visual_foreground: Hsla,
pub vim_visual_line_foreground: Hsla,
pub vim_visual_block_foreground: Hsla,
pub vim_helix_normal_foreground: Hsla,
pub vim_helix_select_foreground: Hsla,
pub editor_foreground: Hsla,
pub editor_background: Hsla,
pub editor_gutter_background: Hsla,
pub editor_subheader_background: Hsla,
pub editor_active_line_background: Hsla,
pub editor_highlighted_line_background: Hsla,
pub editor_debugger_active_line_background: Hsla,
pub editor_line_number: Hsla,
pub editor_active_line_number: Hsla,
pub editor_hover_line_number: Hsla,
pub editor_invisible: Hsla,
pub editor_wrap_guide: Hsla,
pub editor_active_wrap_guide: Hsla,
pub editor_indent_guide: Hsla,
pub editor_indent_guide_active: Hsla,
pub editor_document_highlight_read_background: Hsla,
pub editor_document_highlight_write_background: Hsla,
pub editor_document_highlight_bracket_background: Hsla,
pub terminal_background: Hsla,
pub terminal_foreground: Hsla,
pub terminal_bright_foreground: Hsla,
pub terminal_dim_foreground: Hsla,
pub terminal_ansi_background: Hsla,
pub terminal_ansi_black: Hsla,
pub terminal_ansi_bright_black: Hsla,
pub terminal_ansi_dim_black: Hsla,
pub terminal_ansi_red: Hsla,
pub terminal_ansi_bright_red: Hsla,
pub terminal_ansi_dim_red: Hsla,
pub terminal_ansi_green: Hsla,
pub terminal_ansi_bright_green: Hsla,
pub terminal_ansi_dim_green: Hsla,
pub terminal_ansi_yellow: Hsla,
pub terminal_ansi_bright_yellow: Hsla,
pub terminal_ansi_dim_yellow: Hsla,
pub terminal_ansi_blue: Hsla,
pub terminal_ansi_bright_blue: Hsla,
pub terminal_ansi_dim_blue: Hsla,
pub terminal_ansi_magenta: Hsla,
pub terminal_ansi_bright_magenta: Hsla,
pub terminal_ansi_dim_magenta: Hsla,
pub terminal_ansi_cyan: Hsla,
pub terminal_ansi_bright_cyan: Hsla,
pub terminal_ansi_dim_cyan: Hsla,
pub terminal_ansi_white: Hsla,
pub terminal_ansi_bright_white: Hsla,
pub terminal_ansi_dim_white: Hsla,
pub link_text_hover: Hsla,
pub version_control_added: Hsla,
pub version_control_deleted: Hsla,
pub version_control_modified: Hsla,
pub version_control_renamed: Hsla,
pub version_control_conflict: Hsla,
pub version_control_ignored: Hsla,
pub version_control_word_added: Hsla,
pub version_control_word_deleted: Hsla,
pub version_control_conflict_marker_ours: Hsla,
pub version_control_conflict_marker_theirs: Hsla,
}
#[derive(EnumIter, Debug, Clone, Copy, AsRefStr)]
#[strum(serialize_all = "snake_case")]
pub enum ThemeColorField {
Border,
BorderVariant,
BorderFocused,
BorderSelected,
BorderTransparent,
BorderDisabled,
ElevatedSurfaceBackground,
SurfaceBackground,
Background,
ElementBackground,
ElementHover,
ElementActive,
ElementSelected,
ElementDisabled,
DropTargetBackground,
DropTargetBorder,
GhostElementBackground,
GhostElementHover,
GhostElementActive,
GhostElementSelected,
GhostElementDisabled,
Text,
TextMuted,
TextPlaceholder,
TextDisabled,
TextAccent,
Icon,
IconMuted,
IconDisabled,
IconPlaceholder,
IconAccent,
StatusBarBackground,
TitleBarBackground,
TitleBarInactiveBackground,
ToolbarBackground,
TabBarBackground,
TabInactiveBackground,
TabActiveBackground,
SearchMatchBackground,
SearchActiveMatchBackground,
PanelBackground,
PanelFocusedBorder,
PanelIndentGuide,
PanelIndentGuideHover,
PanelIndentGuideActive,
PanelOverlayBackground,
PanelOverlayHover,
PaneFocusedBorder,
PaneGroupBorder,
ScrollbarThumbBackground,
ScrollbarThumbHoverBackground,
ScrollbarThumbActiveBackground,
ScrollbarThumbBorder,
ScrollbarTrackBackground,
ScrollbarTrackBorder,
MinimapThumbBackground,
MinimapThumbHoverBackground,
MinimapThumbActiveBackground,
MinimapThumbBorder,
EditorForeground,
EditorBackground,
EditorGutterBackground,
EditorSubheaderBackground,
EditorActiveLineBackground,
EditorHighlightedLineBackground,
EditorLineNumber,
EditorActiveLineNumber,
EditorInvisible,
EditorWrapGuide,
EditorActiveWrapGuide,
EditorIndentGuide,
EditorIndentGuideActive,
EditorDocumentHighlightReadBackground,
EditorDocumentHighlightWriteBackground,
EditorDocumentHighlightBracketBackground,
TerminalBackground,
TerminalForeground,
TerminalBrightForeground,
TerminalDimForeground,
TerminalAnsiBackground,
TerminalAnsiBlack,
TerminalAnsiBrightBlack,
TerminalAnsiDimBlack,
TerminalAnsiRed,
TerminalAnsiBrightRed,
TerminalAnsiDimRed,
TerminalAnsiGreen,
TerminalAnsiBrightGreen,
TerminalAnsiDimGreen,
TerminalAnsiYellow,
TerminalAnsiBrightYellow,
TerminalAnsiDimYellow,
TerminalAnsiBlue,
TerminalAnsiBrightBlue,
TerminalAnsiDimBlue,
TerminalAnsiMagenta,
TerminalAnsiBrightMagenta,
TerminalAnsiDimMagenta,
TerminalAnsiCyan,
TerminalAnsiBrightCyan,
TerminalAnsiDimCyan,
TerminalAnsiWhite,
TerminalAnsiBrightWhite,
TerminalAnsiDimWhite,
LinkTextHover,
VersionControlAdded,
VersionControlDeleted,
VersionControlModified,
VersionControlRenamed,
VersionControlConflict,
VersionControlIgnored,
}
impl ThemeColors {
pub fn color(&self, field: ThemeColorField) -> Hsla {
match field {
ThemeColorField::Border => self.border,
ThemeColorField::BorderVariant => self.border_variant,
ThemeColorField::BorderFocused => self.border_focused,
ThemeColorField::BorderSelected => self.border_selected,
ThemeColorField::BorderTransparent => self.border_transparent,
ThemeColorField::BorderDisabled => self.border_disabled,
ThemeColorField::ElevatedSurfaceBackground => self.elevated_surface_background,
ThemeColorField::SurfaceBackground => self.surface_background,
ThemeColorField::Background => self.background,
ThemeColorField::ElementBackground => self.element_background,
ThemeColorField::ElementHover => self.element_hover,
ThemeColorField::ElementActive => self.element_active,
ThemeColorField::ElementSelected => self.element_selected,
ThemeColorField::ElementDisabled => self.element_disabled,
ThemeColorField::DropTargetBackground => self.drop_target_background,
ThemeColorField::DropTargetBorder => self.drop_target_border,
ThemeColorField::GhostElementBackground => self.ghost_element_background,
ThemeColorField::GhostElementHover => self.ghost_element_hover,
ThemeColorField::GhostElementActive => self.ghost_element_active,
ThemeColorField::GhostElementSelected => self.ghost_element_selected,
ThemeColorField::GhostElementDisabled => self.ghost_element_disabled,
ThemeColorField::Text => self.text,
ThemeColorField::TextMuted => self.text_muted,
ThemeColorField::TextPlaceholder => self.text_placeholder,
ThemeColorField::TextDisabled => self.text_disabled,
ThemeColorField::TextAccent => self.text_accent,
ThemeColorField::Icon => self.icon,
ThemeColorField::IconMuted => self.icon_muted,
ThemeColorField::IconDisabled => self.icon_disabled,
ThemeColorField::IconPlaceholder => self.icon_placeholder,
ThemeColorField::IconAccent => self.icon_accent,
ThemeColorField::StatusBarBackground => self.status_bar_background,
ThemeColorField::TitleBarBackground => self.title_bar_background,
ThemeColorField::TitleBarInactiveBackground => self.title_bar_inactive_background,
ThemeColorField::ToolbarBackground => self.toolbar_background,
ThemeColorField::TabBarBackground => self.tab_bar_background,
ThemeColorField::TabInactiveBackground => self.tab_inactive_background,
ThemeColorField::TabActiveBackground => self.tab_active_background,
ThemeColorField::SearchMatchBackground => self.search_match_background,
ThemeColorField::SearchActiveMatchBackground => self.search_active_match_background,
ThemeColorField::PanelBackground => self.panel_background,
ThemeColorField::PanelFocusedBorder => self.panel_focused_border,
ThemeColorField::PanelIndentGuide => self.panel_indent_guide,
ThemeColorField::PanelIndentGuideHover => self.panel_indent_guide_hover,
ThemeColorField::PanelIndentGuideActive => self.panel_indent_guide_active,
ThemeColorField::PanelOverlayBackground => self.panel_overlay_background,
ThemeColorField::PanelOverlayHover => self.panel_overlay_hover,
ThemeColorField::PaneFocusedBorder => self.pane_focused_border,
ThemeColorField::PaneGroupBorder => self.pane_group_border,
ThemeColorField::ScrollbarThumbBackground => self.scrollbar_thumb_background,
ThemeColorField::ScrollbarThumbHoverBackground => self.scrollbar_thumb_hover_background,
ThemeColorField::ScrollbarThumbActiveBackground => {
self.scrollbar_thumb_active_background
}
ThemeColorField::ScrollbarThumbBorder => self.scrollbar_thumb_border,
ThemeColorField::ScrollbarTrackBackground => self.scrollbar_track_background,
ThemeColorField::ScrollbarTrackBorder => self.scrollbar_track_border,
ThemeColorField::MinimapThumbBackground => self.minimap_thumb_background,
ThemeColorField::MinimapThumbHoverBackground => self.minimap_thumb_hover_background,
ThemeColorField::MinimapThumbActiveBackground => self.minimap_thumb_active_background,
ThemeColorField::MinimapThumbBorder => self.minimap_thumb_border,
ThemeColorField::EditorForeground => self.editor_foreground,
ThemeColorField::EditorBackground => self.editor_background,
ThemeColorField::EditorGutterBackground => self.editor_gutter_background,
ThemeColorField::EditorSubheaderBackground => self.editor_subheader_background,
ThemeColorField::EditorActiveLineBackground => self.editor_active_line_background,
ThemeColorField::EditorHighlightedLineBackground => {
self.editor_highlighted_line_background
}
ThemeColorField::EditorLineNumber => self.editor_line_number,
ThemeColorField::EditorActiveLineNumber => self.editor_active_line_number,
ThemeColorField::EditorInvisible => self.editor_invisible,
ThemeColorField::EditorWrapGuide => self.editor_wrap_guide,
ThemeColorField::EditorActiveWrapGuide => self.editor_active_wrap_guide,
ThemeColorField::EditorIndentGuide => self.editor_indent_guide,
ThemeColorField::EditorIndentGuideActive => self.editor_indent_guide_active,
ThemeColorField::EditorDocumentHighlightReadBackground => {
self.editor_document_highlight_read_background
}
ThemeColorField::EditorDocumentHighlightWriteBackground => {
self.editor_document_highlight_write_background
}
ThemeColorField::EditorDocumentHighlightBracketBackground => {
self.editor_document_highlight_bracket_background
}
ThemeColorField::TerminalBackground => self.terminal_background,
ThemeColorField::TerminalForeground => self.terminal_foreground,
ThemeColorField::TerminalBrightForeground => self.terminal_bright_foreground,
ThemeColorField::TerminalDimForeground => self.terminal_dim_foreground,
ThemeColorField::TerminalAnsiBackground => self.terminal_ansi_background,
ThemeColorField::TerminalAnsiBlack => self.terminal_ansi_black,
ThemeColorField::TerminalAnsiBrightBlack => self.terminal_ansi_bright_black,
ThemeColorField::TerminalAnsiDimBlack => self.terminal_ansi_dim_black,
ThemeColorField::TerminalAnsiRed => self.terminal_ansi_red,
ThemeColorField::TerminalAnsiBrightRed => self.terminal_ansi_bright_red,
ThemeColorField::TerminalAnsiDimRed => self.terminal_ansi_dim_red,
ThemeColorField::TerminalAnsiGreen => self.terminal_ansi_green,
ThemeColorField::TerminalAnsiBrightGreen => self.terminal_ansi_bright_green,
ThemeColorField::TerminalAnsiDimGreen => self.terminal_ansi_dim_green,
ThemeColorField::TerminalAnsiYellow => self.terminal_ansi_yellow,
ThemeColorField::TerminalAnsiBrightYellow => self.terminal_ansi_bright_yellow,
ThemeColorField::TerminalAnsiDimYellow => self.terminal_ansi_dim_yellow,
ThemeColorField::TerminalAnsiBlue => self.terminal_ansi_blue,
ThemeColorField::TerminalAnsiBrightBlue => self.terminal_ansi_bright_blue,
ThemeColorField::TerminalAnsiDimBlue => self.terminal_ansi_dim_blue,
ThemeColorField::TerminalAnsiMagenta => self.terminal_ansi_magenta,
ThemeColorField::TerminalAnsiBrightMagenta => self.terminal_ansi_bright_magenta,
ThemeColorField::TerminalAnsiDimMagenta => self.terminal_ansi_dim_magenta,
ThemeColorField::TerminalAnsiCyan => self.terminal_ansi_cyan,
ThemeColorField::TerminalAnsiBrightCyan => self.terminal_ansi_bright_cyan,
ThemeColorField::TerminalAnsiDimCyan => self.terminal_ansi_dim_cyan,
ThemeColorField::TerminalAnsiWhite => self.terminal_ansi_white,
ThemeColorField::TerminalAnsiBrightWhite => self.terminal_ansi_bright_white,
ThemeColorField::TerminalAnsiDimWhite => self.terminal_ansi_dim_white,
ThemeColorField::LinkTextHover => self.link_text_hover,
ThemeColorField::VersionControlAdded => self.version_control_added,
ThemeColorField::VersionControlDeleted => self.version_control_deleted,
ThemeColorField::VersionControlModified => self.version_control_modified,
ThemeColorField::VersionControlRenamed => self.version_control_renamed,
ThemeColorField::VersionControlConflict => self.version_control_conflict,
ThemeColorField::VersionControlIgnored => self.version_control_ignored,
}
}
pub fn iter(&self) -> impl Iterator<Item = (ThemeColorField, Hsla)> + '_ {
ThemeColorField::iter().map(move |field| (field, self.color(field)))
}
pub fn to_vec(&self) -> Vec<(ThemeColorField, Hsla)> {
self.iter().collect()
}
}
pub fn all_theme_colors(cx: &mut App) -> Vec<(Hsla, SharedString)> {
let theme = cx.theme();
ThemeColorField::iter()
.map(|field| {
let color = theme.colors().color(field);
let name = field.as_ref().to_string();
(color, SharedString::from(name))
})
.collect()
}
#[derive(Refineable, Clone, Debug, PartialEq)]
pub struct ThemeStyles {
pub window_background_appearance: WindowBackgroundAppearance,
pub system: SystemColors,
pub accents: AccentColors,
#[refineable]
pub colors: ThemeColors,
#[refineable]
pub status: StatusColors,
pub player: PlayerColors,
pub syntax: Arc<SyntaxTheme>,
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::*;
#[test]
fn override_a_single_theme_color() {
let mut colors = ThemeColors::light();
let magenta: Hsla = gpui::rgb(0xff00ff).into();
assert_ne!(colors.text, magenta);
let overrides = ThemeColorsRefinement {
text: Some(magenta),
..Default::default()
};
colors.refine(&overrides);
assert_eq!(colors.text, magenta);
}
#[test]
fn override_multiple_theme_colors() {
let mut colors = ThemeColors::light();
let magenta: Hsla = gpui::rgb(0xff00ff).into();
let green: Hsla = gpui::rgb(0x00ff00).into();
assert_ne!(colors.text, magenta);
assert_ne!(colors.background, green);
let overrides = ThemeColorsRefinement {
text: Some(magenta),
background: Some(green),
..Default::default()
};
colors.refine(&overrides);
assert_eq!(colors.text, magenta);
assert_eq!(colors.background, green);
}
#[test]
fn deserialize_theme_colors_refinement_from_json() {
let colors: ThemeColorsRefinement = serde_json::from_value(json!({
"background": "#ff00ff",
"text": "#ff0000"
}))
.unwrap();
assert_eq!(colors.background, Some(gpui::rgb(0xff00ff).into()));
assert_eq!(colors.text, Some(gpui::rgb(0xff0000).into()));
}
}