Define theme/ui text style settings in theme crate

This commit is contained in:
Max Brunsfeld
2023-05-17 14:44:59 -07:00
parent 5c729c0e56
commit 67a25126d4
86 changed files with 530 additions and 637 deletions
+6 -203
View File
@@ -3,23 +3,10 @@ mod keymap_file;
mod settings_file;
mod settings_store;
use anyhow::Result;
use gpui::{
font_cache::{FamilyId, FontCache},
fonts, AppContext, AssetSource,
};
use schemars::{
gen::SchemaGenerator,
schema::{InstanceType, Schema, SchemaObject},
JsonSchema,
};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::{borrow::Cow, str, sync::Arc};
use theme::{Theme, ThemeRegistry};
use util::ResultExt as _;
use std::{borrow::Cow, str};
pub use font_size::{adjust_font_size_delta, font_size_for_setting};
use gpui::AssetSource;
pub use keymap_file::{keymap_file_json_schema, KeymapFileContent};
pub use settings_file::*;
pub use settings_store::{Setting, SettingsJsonSchemaParams, SettingsStore};
@@ -27,193 +14,9 @@ pub use settings_store::{Setting, SettingsJsonSchemaParams, SettingsStore};
pub const DEFAULT_SETTINGS_ASSET_PATH: &str = "settings/default.json";
pub const INITIAL_USER_SETTINGS_ASSET_PATH: &str = "settings/initial_user_settings.json";
#[derive(Clone)]
pub struct Settings {
pub buffer_font_family_name: String,
pub buffer_font_features: fonts::Features,
pub buffer_font_family: FamilyId,
pub buffer_font_size: f32,
pub theme: Arc<Theme>,
}
impl Setting for Settings {
const KEY: Option<&'static str> = None;
type FileContent = SettingsFileContent;
fn load(
defaults: &Self::FileContent,
user_values: &[&Self::FileContent],
cx: &AppContext,
) -> Result<Self> {
let buffer_font_features = defaults.buffer_font_features.clone().unwrap();
let themes = cx.global::<Arc<ThemeRegistry>>();
let mut this = Self {
buffer_font_family: cx
.font_cache()
.load_family(
&[defaults.buffer_font_family.as_ref().unwrap()],
&buffer_font_features,
)
.unwrap(),
buffer_font_family_name: defaults.buffer_font_family.clone().unwrap(),
buffer_font_features,
buffer_font_size: defaults.buffer_font_size.unwrap(),
theme: themes.get(defaults.theme.as_ref().unwrap()).unwrap(),
};
for value in user_values.into_iter().copied().cloned() {
this.set_user_settings(value, themes.as_ref(), cx.font_cache());
}
Ok(this)
}
fn json_schema(
generator: &mut SchemaGenerator,
params: &SettingsJsonSchemaParams,
) -> schemars::schema::RootSchema {
let mut root_schema = generator.root_schema_for::<SettingsFileContent>();
// Create a schema for a theme name.
let theme_name_schema = SchemaObject {
instance_type: Some(InstanceType::String.into()),
enum_values: Some(
params
.theme_names
.iter()
.cloned()
.map(Value::String)
.collect(),
),
..Default::default()
};
root_schema
.definitions
.extend([("ThemeName".into(), theme_name_schema.into())]);
root_schema
.schema
.object
.as_mut()
.unwrap()
.properties
.extend([(
"theme".to_owned(),
Schema::new_ref("#/definitions/ThemeName".into()),
)]);
root_schema
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct SettingsFileContent {
#[serde(default)]
pub buffer_font_family: Option<String>,
#[serde(default)]
pub buffer_font_size: Option<f32>,
#[serde(default)]
pub buffer_font_features: Option<fonts::Features>,
#[serde(default)]
pub theme: Option<String>,
}
impl Settings {
pub fn initial_user_settings_content(assets: &'static impl AssetSource) -> Cow<'static, str> {
match assets.load(INITIAL_USER_SETTINGS_ASSET_PATH).unwrap() {
Cow::Borrowed(s) => Cow::Borrowed(str::from_utf8(s).unwrap()),
Cow::Owned(s) => Cow::Owned(String::from_utf8(s).unwrap()),
}
}
/// Fill out the settings corresponding to the default.json file, overrides will be set later
pub fn defaults(
assets: impl AssetSource,
font_cache: &FontCache,
themes: &ThemeRegistry,
) -> Self {
let defaults: SettingsFileContent = settings_store::parse_json_with_comments(
str::from_utf8(assets.load(DEFAULT_SETTINGS_ASSET_PATH).unwrap().as_ref()).unwrap(),
)
.unwrap();
let buffer_font_features = defaults.buffer_font_features.unwrap();
Self {
buffer_font_family: font_cache
.load_family(
&[defaults.buffer_font_family.as_ref().unwrap()],
&buffer_font_features,
)
.unwrap(),
buffer_font_family_name: defaults.buffer_font_family.unwrap(),
buffer_font_features,
buffer_font_size: defaults.buffer_font_size.unwrap(),
theme: themes.get(&defaults.theme.unwrap()).unwrap(),
}
}
// Fill out the overrride and etc. settings from the user's settings.json
fn set_user_settings(
&mut self,
data: SettingsFileContent,
theme_registry: &ThemeRegistry,
font_cache: &FontCache,
) {
let mut family_changed = false;
if let Some(value) = data.buffer_font_family {
self.buffer_font_family_name = value;
family_changed = true;
}
if let Some(value) = data.buffer_font_features {
self.buffer_font_features = value;
family_changed = true;
}
if family_changed {
if let Some(id) = font_cache
.load_family(&[&self.buffer_font_family_name], &self.buffer_font_features)
.log_err()
{
self.buffer_font_family = id;
}
}
if let Some(value) = &data.theme {
if let Some(theme) = theme_registry.get(value).log_err() {
self.theme = theme;
}
}
merge(&mut self.buffer_font_size, data.buffer_font_size);
}
#[cfg(any(test, feature = "test-support"))]
pub fn test(cx: &gpui::AppContext) -> Settings {
Settings {
buffer_font_family_name: "Monaco".to_string(),
buffer_font_features: Default::default(),
buffer_font_family: cx
.font_cache()
.load_family(&["Monaco"], &Default::default())
.unwrap(),
buffer_font_size: 14.,
theme: gpui::fonts::with_font_cache(cx.font_cache().clone(), Default::default),
}
}
#[cfg(any(test, feature = "test-support"))]
pub fn test_async(cx: &mut gpui::TestAppContext) {
cx.update(|cx| {
let settings = Self::test(cx);
cx.set_global(settings);
});
}
}
fn merge<T: Copy>(target: &mut T, value: Option<T>) {
if let Some(value) = value {
*target = value;
pub fn initial_user_settings_content(assets: &'static impl AssetSource) -> Cow<'static, str> {
match assets.load(INITIAL_USER_SETTINGS_ASSET_PATH).unwrap() {
Cow::Borrowed(s) => Cow::Borrowed(str::from_utf8(s).unwrap()),
Cow::Owned(s) => Cow::Owned(String::from_utf8(s).unwrap()),
}
}
+10 -15
View File
@@ -1,7 +1,4 @@
use crate::{
settings_store::parse_json_with_comments, settings_store::SettingsStore, Setting, Settings,
DEFAULT_SETTINGS_ASSET_PATH,
};
use crate::{settings_store::SettingsStore, Setting, DEFAULT_SETTINGS_ASSET_PATH};
use anyhow::Result;
use assets::Assets;
use fs::Fs;
@@ -34,16 +31,21 @@ pub fn default_settings() -> Cow<'static, str> {
}
}
#[cfg(any(test, feature = "test-support"))]
pub const EMPTY_THEME_NAME: &'static str = "empty-theme";
#[cfg(any(test, feature = "test-support"))]
pub fn test_settings() -> String {
let mut value =
parse_json_with_comments::<serde_json::Value>(default_settings().as_ref()).unwrap();
let mut value = crate::settings_store::parse_json_with_comments::<serde_json::Value>(
default_settings().as_ref(),
)
.unwrap();
util::merge_non_null_json_value_into(
serde_json::json!({
"buffer_font_family": "Courier",
"buffer_font_features": {},
"buffer_font_size": 14,
"theme": theme::EMPTY_THEME_NAME,
"theme": EMPTY_THEME_NAME,
}),
&mut value,
);
@@ -85,10 +87,6 @@ pub fn handle_settings_file_changes(
store
.set_user_settings(&user_settings_content, cx)
.log_err();
// TODO - remove the Settings global, use the SettingsStore instead.
store.register_setting::<Settings>(cx);
cx.set_global(store.get::<Settings>(None).clone());
});
cx.spawn(move |mut cx| async move {
while let Some(user_settings_content) = user_settings_file_rx.next().await {
@@ -97,9 +95,6 @@ pub fn handle_settings_file_changes(
store
.set_user_settings(&user_settings_content, cx)
.log_err();
// TODO - remove the Settings global, use the SettingsStore instead.
cx.set_global(store.get::<Settings>(None).clone());
});
});
}
@@ -113,7 +108,7 @@ async fn load_settings(fs: &Arc<dyn Fs>) -> Result<String> {
Err(err) => {
if let Some(e) = err.downcast_ref::<std::io::Error>() {
if e.kind() == ErrorKind::NotFound {
return Ok(Settings::initial_user_settings_content(&Assets).to_string());
return Ok(crate::initial_user_settings_content(&Assets).to_string());
}
}
return Err(err);
+25 -5
View File
@@ -40,7 +40,11 @@ pub trait Setting: 'static {
where
Self: Sized;
fn json_schema(generator: &mut SchemaGenerator, _: &SettingsJsonSchemaParams) -> RootSchema {
fn json_schema(
generator: &mut SchemaGenerator,
_: &SettingsJsonSchemaParams,
_: &AppContext,
) -> RootSchema {
generator.root_schema_for::<Self::FileContent>()
}
@@ -75,7 +79,7 @@ pub trait Setting: 'static {
}
pub struct SettingsJsonSchemaParams<'a> {
pub theme_names: &'a [String],
pub staff_mode: bool,
pub language_names: &'a [String],
}
@@ -112,6 +116,7 @@ trait AnySettingValue {
&self,
generator: &mut SchemaGenerator,
_: &SettingsJsonSchemaParams,
cx: &AppContext,
) -> RootSchema;
}
@@ -169,6 +174,16 @@ impl SettingsStore {
.expect("no default value for setting type")
}
/// Override the global value for a setting.
///
/// The given value will be overwritten if the user settings file changes.
pub fn override_global<T: Setting>(&mut self, value: T) {
self.setting_values
.get_mut(&TypeId::of::<T>())
.unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()))
.set_global_value(Box::new(value))
}
/// Get the user's settings as a raw JSON value.
///
/// This is only for debugging and reporting. For user-facing functionality,
@@ -342,7 +357,11 @@ impl SettingsStore {
Ok(())
}
pub fn json_schema(&self, schema_params: &SettingsJsonSchemaParams) -> serde_json::Value {
pub fn json_schema(
&self,
schema_params: &SettingsJsonSchemaParams,
cx: &AppContext,
) -> serde_json::Value {
use schemars::{
gen::SchemaSettings,
schema::{Schema, SchemaObject},
@@ -355,7 +374,7 @@ impl SettingsStore {
let mut combined_schema = RootSchema::default();
for setting_value in self.setting_values.values() {
let setting_schema = setting_value.json_schema(&mut generator, schema_params);
let setting_schema = setting_value.json_schema(&mut generator, schema_params, cx);
combined_schema
.definitions
.extend(setting_schema.definitions);
@@ -552,8 +571,9 @@ impl<T: Setting> AnySettingValue for SettingValue<T> {
&self,
generator: &mut SchemaGenerator,
params: &SettingsJsonSchemaParams,
cx: &AppContext,
) -> RootSchema {
T::json_schema(generator, params)
T::json_schema(generator, params, cx)
}
}