theme_settings.rs

  1use crate::{Theme, ThemeRegistry};
  2use anyhow::Result;
  3use gpui::{font_cache::FamilyId, fonts, AppContext};
  4use schemars::{
  5    gen::SchemaGenerator,
  6    schema::{InstanceType, Schema, SchemaObject},
  7    JsonSchema,
  8};
  9use serde::{Deserialize, Serialize};
 10use serde_json::Value;
 11use settings::SettingsJsonSchemaParams;
 12use std::sync::Arc;
 13use util::ResultExt as _;
 14
 15#[derive(Clone)]
 16pub struct ThemeSettings {
 17    pub buffer_font_family_name: String,
 18    pub buffer_font_features: fonts::Features,
 19    pub buffer_font_family: FamilyId,
 20    pub buffer_font_size: f32,
 21    pub theme: Arc<Theme>,
 22}
 23
 24#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
 25pub struct ThemeSettingsContent {
 26    #[serde(default)]
 27    pub buffer_font_family: Option<String>,
 28    #[serde(default)]
 29    pub buffer_font_size: Option<f32>,
 30    #[serde(default)]
 31    pub buffer_font_features: Option<fonts::Features>,
 32    #[serde(default)]
 33    pub theme: Option<String>,
 34}
 35
 36impl settings::Setting for ThemeSettings {
 37    const KEY: Option<&'static str> = None;
 38
 39    type FileContent = ThemeSettingsContent;
 40
 41    fn load(
 42        defaults: &Self::FileContent,
 43        user_values: &[&Self::FileContent],
 44        cx: &AppContext,
 45    ) -> Result<Self> {
 46        let buffer_font_features = defaults.buffer_font_features.clone().unwrap();
 47        let themes = cx.global::<Arc<ThemeRegistry>>();
 48
 49        let mut this = Self {
 50            buffer_font_family: cx
 51                .font_cache()
 52                .load_family(
 53                    &[defaults.buffer_font_family.as_ref().unwrap()],
 54                    &buffer_font_features,
 55                )
 56                .unwrap(),
 57            buffer_font_family_name: defaults.buffer_font_family.clone().unwrap(),
 58            buffer_font_features,
 59            buffer_font_size: defaults.buffer_font_size.unwrap(),
 60            theme: themes.get(defaults.theme.as_ref().unwrap()).unwrap(),
 61        };
 62
 63        for value in user_values.into_iter().copied().cloned() {
 64            let font_cache = cx.font_cache();
 65            let mut family_changed = false;
 66            if let Some(value) = value.buffer_font_family {
 67                this.buffer_font_family_name = value;
 68                family_changed = true;
 69            }
 70            if let Some(value) = value.buffer_font_features {
 71                this.buffer_font_features = value;
 72                family_changed = true;
 73            }
 74            if family_changed {
 75                if let Some(id) = font_cache
 76                    .load_family(&[&this.buffer_font_family_name], &this.buffer_font_features)
 77                    .log_err()
 78                {
 79                    this.buffer_font_family = id;
 80                }
 81            }
 82
 83            if let Some(value) = &value.theme {
 84                if let Some(theme) = themes.get(value).log_err() {
 85                    this.theme = theme;
 86                }
 87            }
 88
 89            merge(&mut this.buffer_font_size, value.buffer_font_size);
 90        }
 91
 92        Ok(this)
 93    }
 94
 95    fn json_schema(
 96        generator: &mut SchemaGenerator,
 97        params: &SettingsJsonSchemaParams,
 98        cx: &AppContext,
 99    ) -> schemars::schema::RootSchema {
100        let mut root_schema = generator.root_schema_for::<ThemeSettingsContent>();
101        let theme_names = cx
102            .global::<Arc<ThemeRegistry>>()
103            .list(params.staff_mode)
104            .map(|theme| Value::String(theme.name.clone()))
105            .collect();
106
107        let theme_name_schema = SchemaObject {
108            instance_type: Some(InstanceType::String.into()),
109            enum_values: Some(theme_names),
110            ..Default::default()
111        };
112
113        root_schema
114            .definitions
115            .extend([("ThemeName".into(), theme_name_schema.into())]);
116
117        root_schema
118            .schema
119            .object
120            .as_mut()
121            .unwrap()
122            .properties
123            .extend([(
124                "theme".to_owned(),
125                Schema::new_ref("#/definitions/ThemeName".into()),
126            )]);
127
128        root_schema
129    }
130}
131
132fn merge<T: Copy>(target: &mut T, value: Option<T>) {
133    if let Some(value) = value {
134        *target = value;
135    }
136}