diff --git a/crates/settings/src/settings_content/terminal.rs b/crates/settings/src/settings_content/terminal.rs index 1a30eecaa12e1e4a2a9799b2ec752bae2998a257..48cb5bfb644f2704c84f80c4936295358333e35d 100644 --- a/crates/settings/src/settings_content/terminal.rs +++ b/crates/settings/src/settings_content/terminal.rs @@ -6,7 +6,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings_macros::{MergeFrom, with_fallible_options}; -use crate::FontFamilyName; +use crate::{FontFamilyName, FontSize}; #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)] pub struct ProjectTerminalSettingsContent { @@ -75,8 +75,7 @@ pub struct TerminalSettingsContent { /// /// If this option is not included, /// the terminal will default to matching the buffer's font size. - #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")] - pub font_size: Option, + pub font_size: Option, /// Sets the terminal's font family. /// /// If this option is not included, diff --git a/crates/settings/src/settings_content/theme.rs b/crates/settings/src/settings_content/theme.rs index 94045b75a1112af64ed56de318d4e27c392a230e..41bd433f28dc6d85955c56d1379aa6fb210db512 100644 --- a/crates/settings/src/settings_content/theme.rs +++ b/crates/settings/src/settings_content/theme.rs @@ -1,5 +1,5 @@ use collections::{HashMap, IndexMap}; -use gpui::{FontFallbacks, FontFeatures, FontStyle, FontWeight, SharedString}; +use gpui::{FontFallbacks, FontFeatures, FontStyle, FontWeight, Pixels, SharedString}; use schemars::{JsonSchema, JsonSchema_repr}; use serde::{Deserialize, Deserializer, Serialize}; use serde_json::Value; @@ -15,8 +15,7 @@ use crate::serialize_f32_with_two_decimal_places; #[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)] pub struct ThemeSettingsContent { /// The default font size for text in the UI. - #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")] - pub ui_font_size: Option, + pub ui_font_size: Option, /// The name of a font to use for rendering in the UI. pub ui_font_family: Option, /// The font fallbacks to use for rendering in the UI. @@ -35,8 +34,7 @@ pub struct ThemeSettingsContent { #[schemars(extend("uniqueItems" = true))] pub buffer_font_fallbacks: Option>, /// The default font size for rendering in text buffers. - #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")] - pub buffer_font_size: Option, + pub buffer_font_size: Option, /// The weight of the editor font in CSS units from 100 to 900. #[schemars(default = "default_buffer_font_weight")] pub buffer_font_weight: Option, @@ -46,11 +44,9 @@ pub struct ThemeSettingsContent { #[schemars(default = "default_font_features")] pub buffer_font_features: Option, /// The font size for agent responses in the agent panel. Falls back to the UI font size if unset. - #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")] - pub agent_ui_font_size: Option, + pub agent_ui_font_size: Option, /// The font size for user messages in the agent panel. - #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")] - pub agent_buffer_font_size: Option, + pub agent_buffer_font_size: Option, /// The name of the Zed theme to use. pub theme: Option, /// The name of the icon theme to use. @@ -79,6 +75,46 @@ pub struct ThemeSettingsContent { pub theme_overrides: HashMap, } +/// A font size value in pixels, wrapping around `f32` for custom settings UI rendering. +#[derive( + Clone, + Copy, + Debug, + Serialize, + Deserialize, + JsonSchema, + MergeFrom, + PartialEq, + PartialOrd, + derive_more::FromStr, +)] +#[serde(transparent)] +pub struct FontSize(#[serde(serialize_with = "serialize_f32_with_two_decimal_places")] pub f32); + +impl Display for FontSize { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:.2}", self.0) + } +} + +impl From for FontSize { + fn from(value: f32) -> Self { + Self(value) + } +} + +impl From for Pixels { + fn from(value: FontSize) -> Self { + value.0.into() + } +} + +impl From for FontSize { + fn from(value: Pixels) -> Self { + Self(value.into()) + } +} + #[derive( Clone, Copy, diff --git a/crates/settings/src/vscode_import.rs b/crates/settings/src/vscode_import.rs index 64343b05fd57c33eb9cfb0d8cb8674971266b464..8f32b7baf119be88717876e3d103b5033b141e86 100644 --- a/crates/settings/src/vscode_import.rs +++ b/crates/settings/src/vscode_import.rs @@ -736,7 +736,9 @@ impl VsCodeSettings { font_fallbacks, font_family, font_features: None, - font_size: self.read_f32("terminal.integrated.fontSize"), + font_size: self + .read_f32("terminal.integrated.fontSize") + .map(FontSize::from), font_weight: None, keep_selection_on_copy: None, line_height: self @@ -795,7 +797,7 @@ impl VsCodeSettings { ui_font_weight: None, buffer_font_family, buffer_font_fallbacks, - buffer_font_size: self.read_f32("editor.fontSize"), + buffer_font_size: self.read_f32("editor.fontSize").map(FontSize::from), buffer_font_weight: self.read_f32("editor.fontWeight").map(|w| w.into()), buffer_line_height: None, buffer_font_features: None, diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index a735553f78d487ad4def08a98886f422b113dba4..1196c45e3280e6c9e0e909f1880017cc1a2eea32 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -31,7 +31,7 @@ use ui::{ Banner, ContextMenu, Divider, DropdownMenu, DropdownStyle, IconButtonShape, KeyBinding, KeybindingHint, PopoverMenu, Switch, Tooltip, TreeViewItem, WithScrollbar, prelude::*, }; -use ui_input::{NumberField, NumberFieldType}; +use ui_input::{NumberField, NumberFieldMode, NumberFieldType}; use util::{ResultExt as _, paths::PathStyle, rel_path::RelPath}; use workspace::{AppState, OpenOptions, OpenVisible, Workspace, client_side_decorations}; use zed_actions::{OpenProjectSettings, OpenSettings, OpenSettingsAt}; @@ -513,6 +513,7 @@ fn init_renderers(cx: &mut App) { .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_editable_number_field) // please semicolon stay on next line ; } @@ -3667,7 +3668,44 @@ fn render_number_field( ) -> AnyElement { let (_, value) = SettingsStore::global(cx).get_value_from_file(file.to_settings(), field.pick); let value = value.copied().unwrap_or_else(T::min_value); - NumberField::new("numeric_stepper", value, window, cx) + + let id = field + .json_path + .map(|p| format!("numeric_stepper_{}", p)) + .unwrap_or_else(|| "numeric_stepper".to_string()); + + NumberField::new(id, value, window, cx) + .tab_index(0_isize) + .on_change({ + move |value, _window, cx| { + let value = *value; + update_settings_file(file.clone(), field.json_path, cx, move |settings, _cx| { + (field.write)(settings, Some(value)); + }) + .log_err(); // todo(settings_ui) don't log err + } + }) + .into_any_element() +} + +fn render_editable_number_field( + field: SettingField, + file: SettingsUiFile, + _metadata: Option<&SettingsFieldMetadata>, + window: &mut Window, + cx: &mut App, +) -> AnyElement { + let (_, value) = SettingsStore::global(cx).get_value_from_file(file.to_settings(), field.pick); + let value = value.copied().unwrap_or_else(T::min_value); + + let id = field + .json_path + .map(|p| format!("numeric_stepper_{}", p)) + .unwrap_or_else(|| "numeric_stepper".to_string()); + + NumberField::new(id, value, window, cx) + .mode(NumberFieldMode::Edit, cx) + .tab_index(0_isize) .on_change({ move |value, _window, cx| { let value = *value; diff --git a/crates/terminal/src/terminal_settings.rs b/crates/terminal/src/terminal_settings.rs index 3d70d85f35239778bee61113ebc51eea7d87adcb..a71800e0935b66ce1d4fad2fb3ff91031258d248 100644 --- a/crates/terminal/src/terminal_settings.rs +++ b/crates/terminal/src/terminal_settings.rs @@ -84,7 +84,7 @@ impl settings::Settings for TerminalSettings { TerminalSettings { shell: settings_shell_to_task_shell(project_content.shell.unwrap()), working_directory: project_content.working_directory.unwrap(), - font_size: user_content.font_size.map(px), + font_size: user_content.font_size.map(Into::into), font_family: user_content.font_family, font_fallbacks: user_content.font_fallbacks.map(|fallbacks| { FontFallbacks::from_fonts( diff --git a/crates/ui_input/src/number_field.rs b/crates/ui_input/src/number_field.rs index b72ce39d4c619600ddc104223087a759081449cf..bb5f6e432474b8353c5555a94f7014b52c518b27 100644 --- a/crates/ui_input/src/number_field.rs +++ b/crates/ui_input/src/number_field.rs @@ -11,7 +11,9 @@ use gpui::{ TextStyleRefinement, WeakEntity, }; -use settings::{CenteredPaddingSettings, CodeFade, DelayMs, InactiveOpacity, MinimumContrast}; +use settings::{ + CenteredPaddingSettings, CodeFade, DelayMs, FontSize, InactiveOpacity, MinimumContrast, +}; use ui::prelude::*; #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] @@ -105,6 +107,7 @@ macro_rules! impl_newtype_numeric_stepper_int { #[rustfmt::skip] impl_newtype_numeric_stepper_float!(FontWeight, 50., 100., 10., FontWeight::THIN, FontWeight::BLACK); impl_newtype_numeric_stepper_float!(CodeFade, 0.1, 0.2, 0.05, 0.0, 0.9); +impl_newtype_numeric_stepper_float!(FontSize, 1.0, 4.0, 0.5, 6.0, 72.0); impl_newtype_numeric_stepper_float!(InactiveOpacity, 0.1, 0.2, 0.05, 0.0, 1.0); impl_newtype_numeric_stepper_float!(MinimumContrast, 1., 10., 0.5, 0.0, 106.0); impl_newtype_numeric_stepper_int!(DelayMs, 100, 500, 10, 0, 2000);