Scale diagnostic headers icons with editor font and right align w/ line numbers

Nathan Sobo and Max Brunsfeld created

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>

Change summary

crates/diagnostics/src/diagnostics.rs      | 15 +++++++++------
crates/editor/src/display_map/block_map.rs |  8 ++++++--
crates/editor/src/editor.rs                |  3 ++-
crates/editor/src/element.rs               | 14 ++++++++++----
crates/theme/src/theme.rs                  | 13 ++++---------
crates/zed/assets/themes/_base.toml        |  3 ++-
6 files changed, 33 insertions(+), 23 deletions(-)

Detailed changes

crates/diagnostics/src/diagnostics.rs 🔗

@@ -688,7 +688,7 @@ fn path_header_renderer(buffer: ModelHandle<Buffer>, build_settings: BuildSettin
             .left()
             .contained()
             .with_style(style.container)
-            .with_padding_left(cx.line_number_x)
+            .with_padding_left(cx.gutter_padding)
             .expanded()
             .named("path header block")
     })
@@ -702,6 +702,7 @@ fn diagnostic_header_renderer(
     Arc::new(move |cx| {
         let settings = build_settings(cx);
         let style = &settings.style.diagnostic_header;
+        let icon_width = cx.em_width * style.icon_width_factor;
         let icon = if diagnostic.severity == DiagnosticSeverity::ERROR {
             Svg::new("icons/diagnostic-error-10.svg")
                 .with_color(settings.style.error_diagnostic.message.text.color)
@@ -713,10 +714,9 @@ fn diagnostic_header_renderer(
         Flex::row()
             .with_child(
                 icon.constrained()
-                    .with_height(style.icon.width)
+                    .with_width(icon_width)
                     .aligned()
                     .contained()
-                    .with_style(style.icon.container)
                     .boxed(),
             )
             .with_child(
@@ -724,6 +724,7 @@ fn diagnostic_header_renderer(
                     .with_highlights(highlights.clone())
                     .contained()
                     .with_style(style.message.container)
+                    .with_margin_left(cx.gutter_padding)
                     .aligned()
                     .boxed(),
             )
@@ -736,7 +737,7 @@ fn diagnostic_header_renderer(
             }))
             .contained()
             .with_style(style.container)
-            .with_padding_left(cx.line_number_x)
+            .with_padding_left(cx.gutter_width - cx.gutter_padding - icon_width)
             .expanded()
             .named("diagnostic header")
     })
@@ -748,7 +749,7 @@ fn context_header_renderer(build_settings: BuildSettings) -> RenderBlock {
         let text_style = settings.style.text.clone();
         Label::new("…".to_string(), text_style)
             .contained()
-            .with_padding_left(cx.line_number_x)
+            .with_padding_left(cx.gutter_padding)
             .named("collapsed context")
     })
 }
@@ -1194,7 +1195,9 @@ mod tests {
                     .render(&BlockContext {
                         cx,
                         anchor_x: 0.,
-                        line_number_x: 0.,
+                        gutter_padding: 0.,
+                        gutter_width: 0.,
+                        em_width: 0.,
                     })
                     .name()
                     .map(|s| (row, s.to_string()))

crates/editor/src/display_map/block_map.rs 🔗

@@ -69,7 +69,9 @@ where
 pub struct BlockContext<'a> {
     pub cx: &'a AppContext,
     pub anchor_x: f32,
-    pub line_number_x: f32,
+    pub gutter_width: f32,
+    pub gutter_padding: f32,
+    pub em_width: f32,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -947,7 +949,9 @@ mod tests {
                         .render(&BlockContext {
                             cx,
                             anchor_x: 0.,
-                            line_number_x: 0.,
+                            gutter_padding: 0.,
+                            gutter_width: 0.,
+                            em_width: 0.,
                         })
                         .name()
                         .unwrap()

crates/editor/src/editor.rs 🔗

@@ -3834,6 +3834,7 @@ impl EditorSettings {
                     placeholder_text: None,
                     background: Default::default(),
                     gutter_background: Default::default(),
+                    gutter_padding_factor: 2.,
                     active_line_background: Default::default(),
                     highlighted_line_background: Default::default(),
                     line_number: Default::default(),
@@ -3862,7 +3863,7 @@ impl EditorSettings {
                             container: Default::default(),
                             text: text.clone(),
                         },
-                        icon: Default::default(),
+                        icon_width_factor: Default::default(),
                     },
                     error_diagnostic: default_diagnostic_style.clone(),
                     invalid_error_diagnostic: default_diagnostic_style.clone(),

crates/editor/src/element.rs 🔗

@@ -586,7 +586,9 @@ impl EditorElement {
         rows: Range<u32>,
         snapshot: &EditorSnapshot,
         width: f32,
-        line_number_x: f32,
+        gutter_padding: f32,
+        gutter_width: f32,
+        em_width: f32,
         text_x: f32,
         line_height: f32,
         style: &EditorStyle,
@@ -614,7 +616,9 @@ impl EditorElement {
                 let mut element = block.render(&BlockContext {
                     cx,
                     anchor_x,
-                    line_number_x,
+                    gutter_padding,
+                    gutter_width,
+                    em_width,
                 });
                 element.layout(
                     SizeConstraint {
@@ -645,12 +649,12 @@ impl Element for EditorElement {
 
         let snapshot = self.snapshot(cx.app);
         let style = self.settings.style.clone();
-        let line_height = style.text.line_height(cx.font_cache);
+        let line_height = dbg!(style.text.line_height(cx.font_cache));
 
         let gutter_padding;
         let gutter_width;
         if snapshot.mode == EditorMode::Full {
-            gutter_padding = style.text.em_width(cx.font_cache);
+            gutter_padding = style.text.em_width(cx.font_cache) * style.gutter_padding_factor;
             gutter_width = self.max_line_number_width(&snapshot, cx) + gutter_padding * 2.0;
         } else {
             gutter_padding = 0.0;
@@ -781,6 +785,8 @@ impl Element for EditorElement {
             &snapshot,
             size.x(),
             gutter_padding,
+            gutter_width,
+            em_width,
             gutter_width + text_offset.x(),
             line_height,
             &style,

crates/theme/src/theme.rs 🔗

@@ -245,6 +245,7 @@ pub struct EditorStyle {
     pub background: Color,
     pub selection: SelectionStyle,
     pub gutter_background: Color,
+    pub gutter_padding_factor: f32,
     pub active_line_background: Color,
     pub highlighted_line_background: Color,
     pub line_number: Color,
@@ -277,14 +278,7 @@ pub struct DiagnosticHeader {
     pub container: ContainerStyle,
     pub message: ContainedLabel,
     pub code: ContainedText,
-    pub icon: DiagnosticHeaderIcon,
-}
-
-#[derive(Clone, Deserialize, Default)]
-pub struct DiagnosticHeaderIcon {
-    #[serde(flatten)]
-    pub container: ContainerStyle,
-    pub width: f32,
+    pub icon_width_factor: f32,
 }
 
 #[derive(Clone, Deserialize, Default)]
@@ -340,6 +334,7 @@ impl InputEditorStyle {
                 .unwrap_or(Color::transparent_black()),
             selection: self.selection,
             gutter_background: Default::default(),
+            gutter_padding_factor: Default::default(),
             active_line_background: Default::default(),
             highlighted_line_background: Default::default(),
             line_number: Default::default(),
@@ -367,7 +362,7 @@ impl InputEditorStyle {
                     container: Default::default(),
                     text: self.text.clone(),
                 },
-                icon: Default::default(),
+                icon_width_factor: Default::default(),
             },
             error_diagnostic: default_diagnostic_style.clone(),
             invalid_error_diagnostic: default_diagnostic_style.clone(),

crates/zed/assets/themes/_base.toml 🔗

@@ -244,6 +244,7 @@ text = "$text.0"
 text = "$text.1"
 background = "$surface.1"
 gutter_background = "$surface.1"
+gutter_padding_factor = 2.5
 active_line_background = "$state.active_line"
 highlighted_line_background = "$state.highlighted_line"
 line_number = "$text.2.color"
@@ -260,7 +261,7 @@ path = { extends = "$text.2", size = 14, margin.left = 12 }
 background = "$state.active_line"
 border = { width = 1, top = true, bottom = true, color = "$border.0" }
 code = { extends = "$text.2", size = 14, margin.left = 10 }
-icon = { width = 10, margin.right = 8 }
+icon_width_factor = 1.5
 
 [editor.diagnostic_header.message]
 text = { extends = "$text.1", size = 14 }