registry.rs

  1use std::collections::HashMap;
  2use std::sync::Arc;
  3
  4use anyhow::{anyhow, Result};
  5use gpui::{HighlightStyle, SharedString};
  6use refineable::Refineable;
  7
  8use crate::{
  9    one_themes::one_family, zed_pro_family, Appearance, PlayerColors, StatusColors, SyntaxTheme,
 10    SystemColors, Theme, ThemeColors, ThemeFamily, ThemeStyles, UserTheme, UserThemeFamily,
 11};
 12
 13#[derive(Debug, Clone)]
 14pub struct ThemeMeta {
 15    pub name: SharedString,
 16    pub appearance: Appearance,
 17}
 18
 19pub struct ThemeRegistry {
 20    themes: HashMap<SharedString, Arc<Theme>>,
 21}
 22
 23impl ThemeRegistry {
 24    fn insert_theme_families(&mut self, families: impl IntoIterator<Item = ThemeFamily>) {
 25        for family in families.into_iter() {
 26            self.insert_themes(family.themes);
 27        }
 28    }
 29
 30    fn insert_themes(&mut self, themes: impl IntoIterator<Item = Theme>) {
 31        for theme in themes.into_iter() {
 32            self.themes.insert(theme.name.clone(), Arc::new(theme));
 33        }
 34    }
 35
 36    #[allow(unused)]
 37    fn insert_user_theme_familes(&mut self, families: impl IntoIterator<Item = UserThemeFamily>) {
 38        for family in families.into_iter() {
 39            self.insert_user_themes(family.themes);
 40        }
 41    }
 42
 43    #[allow(unused)]
 44    fn insert_user_themes(&mut self, themes: impl IntoIterator<Item = UserTheme>) {
 45        self.insert_themes(themes.into_iter().map(|user_theme| {
 46            let mut theme_colors = match user_theme.appearance {
 47                Appearance::Light => ThemeColors::light(),
 48                Appearance::Dark => ThemeColors::dark(),
 49            };
 50            theme_colors.refine(&user_theme.styles.colors);
 51
 52            let mut status_colors = StatusColors::dark();
 53            status_colors.refine(&user_theme.styles.status);
 54
 55            let mut syntax_colors = match user_theme.appearance {
 56                Appearance::Light => SyntaxTheme::light(),
 57                Appearance::Dark => SyntaxTheme::dark(),
 58            };
 59            if let Some(user_syntax) = user_theme.styles.syntax {
 60                syntax_colors.highlights = user_syntax
 61                    .highlights
 62                    .iter()
 63                    .map(|(syntax_token, highlight)| {
 64                        (
 65                            syntax_token.clone(),
 66                            HighlightStyle {
 67                                color: highlight.color,
 68                                font_style: highlight.font_style.map(Into::into),
 69                                font_weight: highlight.font_weight.map(Into::into),
 70                                ..Default::default()
 71                            },
 72                        )
 73                    })
 74                    .collect::<Vec<_>>();
 75            }
 76
 77            Theme {
 78                id: uuid::Uuid::new_v4().to_string(),
 79                name: user_theme.name.into(),
 80                appearance: user_theme.appearance,
 81                styles: ThemeStyles {
 82                    system: SystemColors::default(),
 83                    colors: theme_colors,
 84                    status: status_colors,
 85                    player: match user_theme.appearance {
 86                        Appearance::Light => PlayerColors::light(),
 87                        Appearance::Dark => PlayerColors::dark(),
 88                    },
 89                    syntax: Arc::new(syntax_colors),
 90                    accents: Vec::new(),
 91                },
 92            }
 93        }));
 94    }
 95
 96    pub fn clear(&mut self) {
 97        self.themes.clear();
 98    }
 99
100    pub fn list_names(&self, _staff: bool) -> impl Iterator<Item = SharedString> + '_ {
101        self.themes.keys().cloned()
102    }
103
104    pub fn list(&self, _staff: bool) -> impl Iterator<Item = ThemeMeta> + '_ {
105        self.themes.values().map(|theme| ThemeMeta {
106            name: theme.name.clone(),
107            appearance: theme.appearance(),
108        })
109    }
110
111    pub fn get(&self, name: &str) -> Result<Arc<Theme>> {
112        self.themes
113            .get(name)
114            .ok_or_else(|| anyhow!("theme not found: {}", name))
115            .cloned()
116    }
117
118    pub fn load_user_themes(&mut self) {
119        #[cfg(not(feature = "importing-themes"))]
120        self.insert_user_theme_familes(crate::all_user_themes());
121    }
122}
123
124impl Default for ThemeRegistry {
125    fn default() -> Self {
126        let mut this = Self {
127            themes: HashMap::default(),
128        };
129
130        this.insert_theme_families([zed_pro_family(), one_family()]);
131
132        this
133    }
134}