settings: Use a derive macro for refine (#38451)

When we refactored settings to not pass JSON blobs around, we ended up
needing
to write *a lot* of code that just merged things (like json merge used
to do).

Use a derive macro to prevent typos in this logic.

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin
2025-09-18 21:13:49 +00:00
committed by GitHub
parent 5f4f0a873e
commit b09764c54a
74 changed files with 1089 additions and 2818 deletions
+16 -156
View File
@@ -7,17 +7,16 @@ use crate::{
use collections::HashMap;
use derive_more::{Deref, DerefMut};
use gpui::{
App, Context, Font, FontFallbacks, FontStyle, FontWeight, Global, Pixels, SharedString,
Subscription, Window, px,
App, Context, Font, FontFallbacks, FontStyle, FontWeight, Global, Pixels, Subscription, Window,
px,
};
use refineable::Refineable;
use schemars::{JsonSchema, json_schema};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub use settings::{FontFamilyName, IconThemeName, ThemeMode, ThemeName};
use settings::{ParameterizedJsonSchema, Settings, SettingsContent};
use settings::{Settings, SettingsContent};
use std::sync::Arc;
use util::schemars::replace_subschema;
use util::{MergeFrom, ResultExt as _};
use util::ResultExt as _;
const MIN_FONT_SIZE: Pixels = px(6.0);
const MAX_FONT_SIZE: Pixels = px(100.0);
@@ -270,45 +269,6 @@ pub struct AgentFontSize(Pixels);
impl Global for AgentFontSize {}
inventory::submit! {
ParameterizedJsonSchema {
add_and_get_ref: |generator, _params, cx| {
replace_subschema::<settings::ThemeName>(generator, || json_schema!({
"type": "string",
"enum": ThemeRegistry::global(cx).list_names(),
}))
}
}
}
inventory::submit! {
ParameterizedJsonSchema {
add_and_get_ref: |generator, _params, cx| {
replace_subschema::<settings::IconThemeName>(generator, || json_schema!({
"type": "string",
"enum": ThemeRegistry::global(cx)
.list_icon_themes()
.into_iter()
.map(|icon_theme| icon_theme.name)
.collect::<Vec<SharedString>>(),
}))
}
}
}
inventory::submit! {
ParameterizedJsonSchema {
add_and_get_ref: |generator, params, _cx| {
replace_subschema::<settings::FontFamilyName>(generator, || {
json_schema!({
"type": "string",
"enum": params.font_names,
})
})
}
}
}
/// Represents the selection of a theme, which can be either static or dynamic.
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(untagged)]
@@ -807,20 +767,20 @@ pub fn font_fallbacks_from_settings(
}
impl settings::Settings for ThemeSettings {
fn from_defaults(content: &settings::SettingsContent, cx: &mut App) -> Self {
fn from_settings(content: &settings::SettingsContent, cx: &mut App) -> Self {
let content = &content.theme;
// todo(settings_refactor). This should *not* require cx...
let themes = ThemeRegistry::default_global(cx);
let system_appearance = SystemAppearance::default_global(cx);
let theme_selection: ThemeSelection = content.theme.clone().unwrap().into();
let icon_theme_selection: IconThemeSelection = content.icon_theme.clone().unwrap().into();
Self {
ui_font_size: content.ui_font_size.unwrap().into(),
let mut this = Self {
ui_font_size: clamp_font_size(content.ui_font_size.unwrap().into()),
ui_font: Font {
family: content.ui_font_family.as_ref().unwrap().0.clone().into(),
features: content.ui_font_features.clone().unwrap(),
fallbacks: font_fallbacks_from_settings(content.ui_font_fallbacks.clone()),
weight: content.ui_font_weight.map(FontWeight).unwrap(),
weight: clamp_font_weight(content.ui_font_weight.unwrap()),
style: Default::default(),
},
buffer_font: Font {
@@ -833,12 +793,12 @@ impl settings::Settings for ThemeSettings {
.into(),
features: content.buffer_font_features.clone().unwrap(),
fallbacks: font_fallbacks_from_settings(content.buffer_font_fallbacks.clone()),
weight: content.buffer_font_weight.map(FontWeight).unwrap(),
weight: clamp_font_weight(content.buffer_font_weight.unwrap()),
style: FontStyle::default(),
},
buffer_font_size: content.buffer_font_size.unwrap().into(),
buffer_font_size: clamp_font_size(content.buffer_font_size.unwrap().into()),
buffer_line_height: content.buffer_line_height.unwrap().into(),
agent_font_size: content.agent_font_size.flatten().map(Into::into),
agent_font_size: content.agent_font_size.map(Into::into),
active_theme: themes
.get(theme_selection.theme(*system_appearance))
.or(themes.get(&zed_default_dark().name))
@@ -852,110 +812,10 @@ impl settings::Settings for ThemeSettings {
.unwrap(),
icon_theme_selection: Some(icon_theme_selection),
ui_density: content.ui_density.unwrap_or_default().into(),
unnecessary_code_fade: content.unnecessary_code_fade.unwrap(),
}
}
fn refine(&mut self, content: &SettingsContent, cx: &mut App) {
let value = &content.theme;
let themes = ThemeRegistry::default_global(cx);
let system_appearance = SystemAppearance::default_global(cx);
self.ui_density
.merge_from(&value.ui_density.map(Into::into));
if let Some(value) = value.buffer_font_family.clone() {
self.buffer_font.family = value.0.into();
}
if let Some(value) = value.buffer_font_features.clone() {
self.buffer_font.features = value;
}
if let Some(value) = value.buffer_font_fallbacks.clone() {
self.buffer_font.fallbacks = font_fallbacks_from_settings(Some(value));
}
if let Some(value) = value.buffer_font_weight {
self.buffer_font.weight = clamp_font_weight(value);
}
if let Some(value) = value.ui_font_family.clone() {
self.ui_font.family = value.0.into();
}
if let Some(value) = value.ui_font_features.clone() {
self.ui_font.features = value;
}
if let Some(value) = value.ui_font_fallbacks.clone() {
self.ui_font.fallbacks = font_fallbacks_from_settings(Some(value));
}
if let Some(value) = value.ui_font_weight {
self.ui_font.weight = clamp_font_weight(value);
}
if let Some(value) = &value.theme {
self.theme_selection = Some(value.clone().into());
let theme_name = self
.theme_selection
.as_ref()
.unwrap()
.theme(*system_appearance);
match themes.get(theme_name) {
Ok(theme) => {
self.active_theme = theme;
}
Err(err @ ThemeNotFoundError(_)) => {
if themes.extensions_loaded() {
log::error!("{err}");
}
}
}
}
self.experimental_theme_overrides
.clone_from(&value.experimental_theme_overrides);
self.theme_overrides.clone_from(&value.theme_overrides);
self.apply_theme_overrides();
if let Some(value) = &value.icon_theme {
self.icon_theme_selection = Some(value.clone().into());
let icon_theme_name = self
.icon_theme_selection
.as_ref()
.unwrap()
.icon_theme(*system_appearance);
match themes.get_icon_theme(icon_theme_name) {
Ok(icon_theme) => {
self.active_icon_theme = icon_theme;
}
Err(err @ IconThemeNotFoundError(_)) => {
if themes.extensions_loaded() {
log::error!("{err}");
}
}
}
}
self.ui_font_size
.merge_from(&value.ui_font_size.map(Into::into).map(clamp_font_size));
self.buffer_font_size
.merge_from(&value.buffer_font_size.map(Into::into).map(clamp_font_size));
self.agent_font_size.merge_from(
&value
.agent_font_size
.map(|value| value.map(Into::into).map(clamp_font_size)),
);
self.buffer_line_height
.merge_from(&value.buffer_line_height.map(Into::into));
// Clamp the `unnecessary_code_fade` to ensure text can't disappear entirely.
self.unnecessary_code_fade
.merge_from(&value.unnecessary_code_fade);
self.unnecessary_code_fade = self.unnecessary_code_fade.clamp(0.0, 0.9);
unnecessary_code_fade: content.unnecessary_code_fade.unwrap().clamp(0.0, 0.9),
};
this.apply_theme_overrides();
this
}
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {