settings ui: Add numeric steppers to settings UI (#39491)

This PR adds the numeric stepper component to the settings ui and
implements some settings that rely on this component as well.

I also switched {buffer/ui}_font_weight to the `gpui::FontWeight` type
and added a manual implementation of the Schemars trait. This allows Zed
to send min, max, and default information to the JSON LSP when a user is
manually editing the settings file.

The numeric stepper elements added to the settings ui are below:
- ui font size
- ui font weight
- Buffer font size
- Buffer font weight 
- Scroll sensitivity
- Fast scroll sensitivity
- Vertical scroll margin
- Horizontal scroll margin
- Inline blame padding 
- Inline blame delay
- Inline blame min column
- Unnecessary code fade
- Tab Size
- Hover popover delay

Release Notes:

- N/A
This commit is contained in:
Anthony Eid
2025-10-06 10:06:33 +00:00
committed by GitHub
parent c26937a848
commit d2b91eb2bc
11 changed files with 501 additions and 137 deletions
+2 -1
View File
@@ -57,7 +57,8 @@ merge_from_overwrites!(
gpui::SharedString,
std::path::PathBuf,
gpui::Modifiers,
gpui::FontFeatures
gpui::FontFeatures,
gpui::FontWeight
);
impl<T: Clone + MergeFrom> MergeFrom for Option<T> {
+74 -4
View File
@@ -5,7 +5,7 @@ use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;
use serde_repr::{Deserialize_repr, Serialize_repr};
use settings_macros::MergeFrom;
use std::sync::Arc;
use std::{fmt::Display, sync::Arc};
use serde_with::skip_serializing_none;
@@ -31,7 +31,8 @@ pub struct ThemeSettingsContent {
pub ui_font_features: Option<FontFeatures>,
/// The weight of the UI font in CSS units from 100 to 900.
#[serde(default)]
pub ui_font_weight: Option<f32>,
#[schemars(default = "default_buffer_font_weight")]
pub ui_font_weight: Option<FontWeight>,
/// The name of a font to use for rendering in text buffers.
#[serde(default)]
pub buffer_font_family: Option<FontFamilyName>,
@@ -44,7 +45,8 @@ pub struct ThemeSettingsContent {
pub buffer_font_size: Option<f32>,
/// The weight of the editor font in CSS units from 100 to 900.
#[serde(default)]
pub buffer_font_weight: Option<f32>,
#[schemars(default = "default_buffer_font_weight")]
pub buffer_font_weight: Option<FontWeight>,
/// The buffer's line height.
#[serde(default)]
pub buffer_line_height: Option<BufferLineHeight>,
@@ -73,7 +75,8 @@ pub struct ThemeSettingsContent {
/// How much to fade out unused code.
#[serde(default)]
pub unnecessary_code_fade: Option<f32>,
#[schemars(range(min = 0.0, max = 0.9))]
pub unnecessary_code_fade: Option<CodeFade>,
/// EXPERIMENTAL: Overrides for the current theme.
///
@@ -88,6 +91,27 @@ pub struct ThemeSettingsContent {
pub theme_overrides: HashMap<String, ThemeStyleContent>,
}
#[derive(
Clone,
Copy,
Debug,
Serialize,
Deserialize,
JsonSchema,
MergeFrom,
PartialEq,
PartialOrd,
derive_more::FromStr,
)]
#[serde(transparent)]
pub struct CodeFade(pub f32);
impl Display for CodeFade {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:.2}", self.0)
}
}
fn default_font_features() -> Option<FontFeatures> {
Some(FontFeatures::default())
}
@@ -96,6 +120,10 @@ fn default_font_fallbacks() -> Option<FontFallbacks> {
Some(FontFallbacks::default())
}
fn default_buffer_font_weight() -> Option<FontWeight> {
Some(FontWeight::default())
}
/// Represents the selection of a theme, which can be either static or dynamic.
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq)]
#[serde(untagged)]
@@ -1113,4 +1141,46 @@ mod tests {
.contains("buffer_line_height.custom must be at least 1.0")
);
}
#[test]
fn test_buffer_font_weight_schema_has_default() {
use schemars::schema_for;
let schema = schema_for!(ThemeSettingsContent);
let schema_value = serde_json::to_value(&schema).unwrap();
let properties = &schema_value["properties"];
let buffer_font_weight = &properties["buffer_font_weight"];
assert!(
buffer_font_weight.get("default").is_some(),
"buffer_font_weight should have a default value in the schema"
);
let default_value = &buffer_font_weight["default"];
assert_eq!(
default_value.as_f64(),
Some(FontWeight::NORMAL.0 as f64),
"buffer_font_weight default should be 400.0 (FontWeight::NORMAL)"
);
let defs = &schema_value["$defs"];
let font_weight_def = &defs["FontWeight"];
assert_eq!(
font_weight_def["minimum"].as_f64(),
Some(FontWeight::THIN.0 as f64),
"FontWeight should have minimum of 100.0"
);
assert_eq!(
font_weight_def["maximum"].as_f64(),
Some(FontWeight::BLACK.0 as f64),
"FontWeight should have maximum of 900.0"
);
assert_eq!(
font_weight_def["default"].as_f64(),
Some(FontWeight::NORMAL.0 as f64),
"FontWeight should have default of 400.0"
);
}
}
+6
View File
@@ -125,6 +125,12 @@ impl VsCodeSettings {
}
}
pub fn from_f32_setting<T: From<f32>>(&self, key: &str, setting: &mut Option<T>) {
if let Some(s) = self.content.get(key).and_then(Value::as_f64) {
*setting = Some(T::from(s as f32))
}
}
pub fn enum_setting<T>(
&self,
key: &str,