From 242af863f56220ea6b8fd28d17353ee01bd53a14 Mon Sep 17 00:00:00 2001
From: Max Mynter <32773644+maxmynter@users.noreply.github.com>
Date: Thu, 12 Jun 2025 07:28:04 +0200
Subject: [PATCH] Use ch-width (`0`) instead of em-width (`m`) for gutter width
calculation (#32548)
Closes #21860
Release Notes:
- Added `ch_width` and `ch_advance` function alongside their `em_*`
counterparts
- Use `ch_*` version to calculate gutter layouts
- Update a stale comment from changes in #31959
The ch units refer to the width of the number `0` whereas em is the
width of `m` and the actual font size (e.g. 16px means 16 px width of
`m`).
This change has no effect for monospaced fonts but can be drastic for
proportional ones as seen below for "Zed Plex Sans" with a
`"min_line_number_width" = 4`.
---
crates/editor/src/editor.rs | 25 +++++++++++++------------
crates/gpui/src/text_system.rs | 14 ++++++++++++++
2 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs
index 8f03d660c4..60e7ce7ab8 100644
--- a/crates/editor/src/editor.rs
+++ b/crates/editor/src/editor.rs
@@ -21565,8 +21565,8 @@ impl EditorSnapshot {
return None;
}
- let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
- let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
+ let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
+ let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
matches!(
@@ -21579,9 +21579,10 @@ impl EditorSnapshot {
.show_line_numbers
.unwrap_or(gutter_settings.line_numbers);
let line_gutter_width = if show_line_numbers {
- // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
+ // Avoid flicker-like gutter resizes when the line number gains another digit by
+ // only resizing the gutter on files with > 10**min_line_number_digits lines.
let min_width_for_number_on_gutter =
- em_advance * gutter_settings.min_line_number_digits as f32;
+ ch_advance * gutter_settings.min_line_number_digits as f32;
max_line_number_width.max(min_width_for_number_on_gutter)
} else {
0.0.into()
@@ -21604,20 +21605,20 @@ impl EditorSnapshot {
+ MAX_RELATIVE_TIMESTAMP.len()
+ SPACING_WIDTH;
- em_advance * max_char_count
+ ch_advance * max_char_count
});
let is_singleton = self.buffer_snapshot.is_singleton();
let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
left_padding += if !is_singleton {
- em_width * 4.0
+ ch_width * 4.0
} else if show_runnables || show_breakpoints {
- em_width * 3.0
+ ch_width * 3.0
} else if show_git_gutter && show_line_numbers {
- em_width * 2.0
+ ch_width * 2.0
} else if show_git_gutter || show_line_numbers {
- em_width
+ ch_width
} else {
px(0.)
};
@@ -21625,11 +21626,11 @@ impl EditorSnapshot {
let shows_folds = is_singleton && gutter_settings.folds;
let right_padding = if shows_folds && show_line_numbers {
- em_width * 4.0
+ ch_width * 4.0
} else if shows_folds || (!is_singleton && show_line_numbers) {
- em_width * 3.0
+ ch_width * 3.0
} else if show_line_numbers {
- em_width
+ ch_width
} else {
px(0.)
};
diff --git a/crates/gpui/src/text_system.rs b/crates/gpui/src/text_system.rs
index 3576c2e04a..b2af9140c6 100644
--- a/crates/gpui/src/text_system.rs
+++ b/crates/gpui/src/text_system.rs
@@ -209,6 +209,20 @@ impl TextSystem {
Ok(self.advance(font_id, font_size, 'm')?.width)
}
+ /// Returns the width of an `ch`.
+ ///
+ /// Uses the width of the `0` character in the given font and size.
+ pub fn ch_width(&self, font_id: FontId, font_size: Pixels) -> Result {
+ Ok(self.typographic_bounds(font_id, font_size, '0')?.size.width)
+ }
+
+ /// Returns the advance width of an `ch`.
+ ///
+ /// Uses the advance width of the `0` character in the given font and size.
+ pub fn ch_advance(&self, font_id: FontId, font_size: Pixels) -> Result {
+ Ok(self.advance(font_id, font_size, '0')?.width)
+ }
+
/// Get the number of font size units per 'em square',
/// Per MDN: "an abstract square whose height is the intended distance between
/// lines of type in the same type size"