Add line height settings for the editor

Mikayla Maki created

Change summary

assets/settings/default.json       | 12 +++++++++++-
crates/editor/src/editor.rs        |  5 ++++-
crates/editor/src/element.rs       |  2 +-
crates/terminal/src/terminal.rs    |  2 +-
crates/theme/src/theme_settings.rs | 29 +++++++++++++++++++++++++++++
5 files changed, 46 insertions(+), 4 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -24,6 +24,17 @@
   },
   // The default font size for text in the editor
   "buffer_font_size": 15,
+  // Set the buffer's line height.
+  // May take 3 values:
+  //  1. Use a line height that's comfortable for reading (1.618)
+  //         "line_height": "comfortable"
+  //  2. Use a standard line height, (1.3)
+  //         "line_height": "standard",
+  //  3. Use a custom line height
+  //         "line_height": {
+  //           "custom": 2
+  //         },
+  "buffer_line_height": "comfortable",
   // The factor to grow the active pane by. Defaults to 1.0
   // which gives the same size as all other panes.
   "active_pane_magnification": 1.0,
@@ -282,7 +293,6 @@
     //         "line_height": {
     //           "custom": 2
     //         },
-    //
     "line_height": "comfortable"
     // Set the terminal's font size. If this option is not included,
     // the terminal will default to matching the buffer's font size.

crates/editor/src/editor.rs 🔗

@@ -494,6 +494,7 @@ pub enum SoftWrap {
 #[derive(Clone)]
 pub struct EditorStyle {
     pub text: TextStyle,
+    pub line_height_scalar: f32,
     pub placeholder_text: Option<TextStyle>,
     pub theme: theme::Editor,
     pub theme_id: usize,
@@ -8101,7 +8102,7 @@ fn build_style(
     cx: &AppContext,
 ) -> EditorStyle {
     let font_cache = cx.font_cache();
-
+    let line_height_scalar = settings.line_height();
     let theme_id = settings.theme.meta.id;
     let mut theme = settings.theme.editor.clone();
     let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
@@ -8115,6 +8116,7 @@ fn build_style(
         EditorStyle {
             text: field_editor_theme.text,
             placeholder_text: field_editor_theme.placeholder_text,
+            line_height_scalar,
             theme,
             theme_id,
         }
@@ -8137,6 +8139,7 @@ fn build_style(
                 underline: Default::default(),
             },
             placeholder_text: None,
+            line_height_scalar,
             theme,
             theme_id,
         }

crates/editor/src/element.rs 🔗

@@ -1975,7 +1975,7 @@ impl Element<Editor> for EditorElement {
 
         let snapshot = editor.snapshot(cx);
         let style = self.style.clone();
-        let line_height = style.text.line_height(cx.font_cache());
+        let line_height = (style.text.font_size * style.line_height_scalar).round();
 
         let gutter_padding;
         let gutter_width;

crates/terminal/src/terminal.rs 🔗

@@ -198,7 +198,7 @@ impl TerminalLineHeight {
         match self {
             TerminalLineHeight::Comfortable => 1.618,
             TerminalLineHeight::Standard => 1.3,
-            TerminalLineHeight::Custom(line_height) => *line_height,
+            TerminalLineHeight::Custom(line_height) => f32::max(*line_height, 1.),
         }
     }
 }

crates/theme/src/theme_settings.rs 🔗

@@ -13,6 +13,7 @@ use std::sync::Arc;
 use util::ResultExt as _;
 
 const MIN_FONT_SIZE: f32 = 6.0;
+const MIN_LINE_HEIGHT: f32 = 1.0;
 
 #[derive(Clone, JsonSchema)]
 pub struct ThemeSettings {
@@ -20,6 +21,7 @@ pub struct ThemeSettings {
     pub buffer_font_features: fonts::Features,
     pub buffer_font_family: FamilyId,
     pub(crate) buffer_font_size: f32,
+    pub(crate) buffer_line_height: BufferLineHeight,
     #[serde(skip)]
     pub theme: Arc<Theme>,
 }
@@ -33,11 +35,32 @@ pub struct ThemeSettingsContent {
     #[serde(default)]
     pub buffer_font_size: Option<f32>,
     #[serde(default)]
+    pub buffer_line_height: Option<BufferLineHeight>,
+    #[serde(default)]
     pub buffer_font_features: Option<fonts::Features>,
     #[serde(default)]
     pub theme: Option<String>,
 }
 
+#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, JsonSchema, Default)]
+#[serde(rename_all = "snake_case")]
+pub enum BufferLineHeight {
+    #[default]
+    Comfortable,
+    Standard,
+    Custom(f32),
+}
+
+impl BufferLineHeight {
+    pub fn value(&self) -> f32 {
+        match self {
+            BufferLineHeight::Comfortable => 1.618,
+            BufferLineHeight::Standard => 1.3,
+            BufferLineHeight::Custom(line_height) => *line_height,
+        }
+    }
+}
+
 impl ThemeSettings {
     pub fn buffer_font_size(&self, cx: &AppContext) -> f32 {
         if cx.has_global::<AdjustedBufferFontSize>() {
@@ -47,6 +70,10 @@ impl ThemeSettings {
         }
         .max(MIN_FONT_SIZE)
     }
+
+    pub fn line_height(&self) -> f32 {
+        f32::max(self.buffer_line_height.value(), MIN_LINE_HEIGHT)
+    }
 }
 
 pub fn adjusted_font_size(size: f32, cx: &AppContext) -> f32 {
@@ -106,6 +133,7 @@ impl settings::Setting for ThemeSettings {
             buffer_font_family_name: defaults.buffer_font_family.clone().unwrap(),
             buffer_font_features,
             buffer_font_size: defaults.buffer_font_size.unwrap(),
+            buffer_line_height: defaults.buffer_line_height.unwrap(),
             theme: themes.get(defaults.theme.as_ref().unwrap()).unwrap(),
         };
 
@@ -136,6 +164,7 @@ impl settings::Setting for ThemeSettings {
             }
 
             merge(&mut this.buffer_font_size, value.buffer_font_size);
+            merge(&mut this.buffer_line_height, value.buffer_line_height);
         }
 
         Ok(this)