diff --git a/crates/theme/src/registry.rs b/crates/theme/src/registry.rs index 9f95d19937..73e8fe8c66 100644 --- a/crates/theme/src/registry.rs +++ b/crates/theme/src/registry.rs @@ -6,16 +6,11 @@ use collections::HashMap; use derive_more::{Deref, DerefMut}; use fs::Fs; use futures::StreamExt; -use gpui::{AppContext, AssetSource, Global, HighlightStyle, SharedString}; +use gpui::{AppContext, AssetSource, Global, SharedString}; use parking_lot::RwLock; -use refineable::Refineable; use util::ResultExt; -use crate::{ - try_parse_color, AccentColors, Appearance, AppearanceContent, PlayerColors, StatusColors, - SyntaxTheme, SystemColors, Theme, ThemeColors, ThemeContent, ThemeFamily, ThemeFamilyContent, - ThemeStyles, -}; +use crate::{refine_theme_family, Appearance, Theme, ThemeFamily, ThemeFamilyContent}; /// The metadata for a theme. #[derive(Debug, Clone)] @@ -97,89 +92,12 @@ impl ThemeRegistry { #[allow(unused)] fn insert_user_theme_families(&self, families: impl IntoIterator) { for family in families.into_iter() { - self.insert_user_themes(family.themes); + let refined_family = refine_theme_family(family); + + self.insert_themes(refined_family.themes); } } - /// Inserts user themes into the registry. - pub fn insert_user_themes(&self, themes: impl IntoIterator) { - self.insert_themes(themes.into_iter().map(|user_theme| { - let mut theme_colors = match user_theme.appearance { - AppearanceContent::Light => ThemeColors::light(), - AppearanceContent::Dark => ThemeColors::dark(), - }; - theme_colors.refine(&user_theme.style.theme_colors_refinement()); - - let mut status_colors = match user_theme.appearance { - AppearanceContent::Light => StatusColors::light(), - AppearanceContent::Dark => StatusColors::dark(), - }; - status_colors.refine(&user_theme.style.status_colors_refinement()); - - let mut player_colors = match user_theme.appearance { - AppearanceContent::Light => PlayerColors::light(), - AppearanceContent::Dark => PlayerColors::dark(), - }; - player_colors.merge(&user_theme.style.players); - - let mut accent_colors = match user_theme.appearance { - AppearanceContent::Light => AccentColors::light(), - AppearanceContent::Dark => AccentColors::dark(), - }; - accent_colors.merge(&user_theme.style.accents); - - let syntax_highlights = user_theme - .style - .syntax - .iter() - .map(|(syntax_token, highlight)| { - ( - syntax_token.clone(), - HighlightStyle { - color: highlight - .color - .as_ref() - .and_then(|color| try_parse_color(color).ok()), - background_color: highlight - .background_color - .as_ref() - .and_then(|color| try_parse_color(color).ok()), - font_style: highlight.font_style.map(Into::into), - font_weight: highlight.font_weight.map(Into::into), - ..Default::default() - }, - ) - }) - .collect::>(); - let syntax_theme = - SyntaxTheme::merge(Arc::new(SyntaxTheme::default()), syntax_highlights); - - let window_background_appearance = user_theme - .style - .window_background_appearance - .map(Into::into) - .unwrap_or_default(); - - Theme { - id: uuid::Uuid::new_v4().to_string(), - name: user_theme.name.into(), - appearance: match user_theme.appearance { - AppearanceContent::Light => Appearance::Light, - AppearanceContent::Dark => Appearance::Dark, - }, - styles: ThemeStyles { - system: SystemColors::default(), - window_background_appearance, - accents: accent_colors, - colors: theme_colors, - status: status_colors, - player: player_colors, - syntax: syntax_theme, - }, - } - })); - } - /// Removes the themes with the given names from the registry. pub fn remove_user_themes(&self, themes_to_remove: &[SharedString]) { self.state diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index c62359242d..307ea6b287 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -29,10 +29,11 @@ pub use settings::*; pub use styles::*; use gpui::{ - px, AppContext, AssetSource, Hsla, Pixels, SharedString, WindowAppearance, - WindowBackgroundAppearance, + px, AppContext, AssetSource, HighlightStyle, Hsla, Pixels, Refineable, SharedString, + WindowAppearance, WindowBackgroundAppearance, }; use serde::Deserialize; +use uuid::Uuid; /// Defines window border radius for platforms that use client side decorations. pub const CLIENT_SIDE_DECORATION_ROUNDING: Pixels = px(10.0); @@ -137,7 +138,112 @@ pub struct ThemeFamily { pub scales: ColorScales, } -impl ThemeFamily {} +impl ThemeFamily { + // This is on ThemeFamily because we will have variables here we will need + // in the future to resolve @references. + /// Refines ThemeContent into a theme, merging it's contents with the base theme. + pub fn refine_theme(&self, theme: &ThemeContent) -> Theme { + let appearance = match theme.appearance { + AppearanceContent::Light => Appearance::Light, + AppearanceContent::Dark => Appearance::Dark, + }; + + let mut refined_theme_colors = match theme.appearance { + AppearanceContent::Light => ThemeColors::light(), + AppearanceContent::Dark => ThemeColors::dark(), + }; + refined_theme_colors.refine(&theme.style.theme_colors_refinement()); + + let mut refined_status_colors = match theme.appearance { + AppearanceContent::Light => StatusColors::light(), + AppearanceContent::Dark => StatusColors::dark(), + }; + refined_status_colors.refine(&theme.style.status_colors_refinement()); + + let mut refined_player_colors = match theme.appearance { + AppearanceContent::Light => PlayerColors::light(), + AppearanceContent::Dark => PlayerColors::dark(), + }; + refined_player_colors.merge(&theme.style.players); + + let mut refined_accent_colors = match theme.appearance { + AppearanceContent::Light => AccentColors::light(), + AppearanceContent::Dark => AccentColors::dark(), + }; + refined_accent_colors.merge(&theme.style.accents); + + let syntax_highlights = theme + .style + .syntax + .iter() + .map(|(syntax_token, highlight)| { + ( + syntax_token.clone(), + HighlightStyle { + color: highlight + .color + .as_ref() + .and_then(|color| try_parse_color(color).ok()), + background_color: highlight + .background_color + .as_ref() + .and_then(|color| try_parse_color(color).ok()), + font_style: highlight.font_style.map(Into::into), + font_weight: highlight.font_weight.map(Into::into), + ..Default::default() + }, + ) + }) + .collect::>(); + let syntax_theme = SyntaxTheme::merge(Arc::new(SyntaxTheme::default()), syntax_highlights); + + let window_background_appearance = theme + .style + .window_background_appearance + .map(Into::into) + .unwrap_or_default(); + + Theme { + id: uuid::Uuid::new_v4().to_string(), + name: theme.name.clone().into(), + appearance, + styles: ThemeStyles { + system: SystemColors::default(), + window_background_appearance, + accents: refined_accent_colors, + colors: refined_theme_colors, + status: refined_status_colors, + player: refined_player_colors, + syntax: syntax_theme, + }, + } + } +} + +/// Refines a [ThemeFamilyContent] and it's [ThemeContent]s into a [ThemeFamily]. +pub fn refine_theme_family(theme_family_content: ThemeFamilyContent) -> ThemeFamily { + let id = Uuid::new_v4().to_string(); + let name = theme_family_content.name.clone(); + let author = theme_family_content.author.clone(); + + let mut theme_family = ThemeFamily { + id: id.clone(), + name: name.clone().into(), + author: author.clone().into(), + themes: vec![], + scales: default_color_scales(), + }; + + let refined_themes = theme_family_content + .themes + .iter() + .map(|theme_content| theme_family.refine_theme(theme_content)) + .collect(); + + theme_family.themes = refined_themes; + + theme_family +} /// A theme is the primary mechanism for defining the appearance of the UI. #[derive(Clone, PartialEq)]