Improve border parsing in themes

Max Brunsfeld and Nathan Sobo created

The `top`, `left`, `bottom` and `right` fields are optional.
If none are specified, then they are all set to true.

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

gpui/src/platform/mac/renderer.rs |  6 ---
gpui/src/scene.rs                 | 52 +++++++++++++++++++++++++-------
zed/assets/themes/_base.toml      |  2 
zed/assets/themes/dark.toml       |  2 
4 files changed, 43 insertions(+), 19 deletions(-)

Detailed changes

gpui/src/platform/mac/renderer.rs 🔗

@@ -444,11 +444,7 @@ impl Renderer {
                 border_right: border_width * (quad.border.right as usize as f32),
                 border_bottom: border_width * (quad.border.bottom as usize as f32),
                 border_left: border_width * (quad.border.left as usize as f32),
-                border_color: quad
-                    .border
-                    .color
-                    .unwrap_or(Color::transparent_black())
-                    .to_uchar4(),
+                border_color: quad.border.color.to_uchar4(),
                 corner_radius: quad.corner_radius * scene.scale_factor(),
             };
             unsafe {

gpui/src/scene.rs 🔗

@@ -57,24 +57,52 @@ pub struct Icon {
     pub color: Color,
 }
 
-#[derive(Clone, Copy, Default, Debug, Deserialize)]
+#[derive(Clone, Copy, Default, Debug)]
 pub struct Border {
-    #[serde(default = "default_border_width")]
     pub width: f32,
-    #[serde(default)]
-    pub color: Option<Color>,
-    #[serde(default)]
+    pub color: Color,
     pub top: bool,
-    #[serde(default)]
     pub right: bool,
-    #[serde(default)]
     pub bottom: bool,
-    #[serde(default)]
     pub left: bool,
 }
 
-fn default_border_width() -> f32 {
-    1.0
+impl<'de> Deserialize<'de> for Border {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        #[derive(Deserialize)]
+        struct BorderData {
+            pub width: f32,
+            pub color: Color,
+            #[serde(default)]
+            pub top: bool,
+            #[serde(default)]
+            pub right: bool,
+            #[serde(default)]
+            pub bottom: bool,
+            #[serde(default)]
+            pub left: bool,
+        }
+
+        let data = BorderData::deserialize(deserializer)?;
+        let mut border = Border {
+            width: data.width,
+            color: data.color,
+            top: data.top,
+            bottom: data.bottom,
+            left: data.left,
+            right: data.right,
+        };
+        if !border.top && !border.bottom && !border.left && !border.right {
+            border.top = true;
+            border.bottom = true;
+            border.left = true;
+            border.right = true;
+        }
+        Ok(border)
+    }
 }
 
 #[derive(Debug)]
@@ -206,7 +234,7 @@ impl Border {
     pub fn new(width: f32, color: Color) -> Self {
         Self {
             width,
-            color: Some(color),
+            color,
             top: false,
             left: false,
             bottom: false,
@@ -217,7 +245,7 @@ impl Border {
     pub fn all(width: f32, color: Color) -> Self {
         Self {
             width,
-            color: Some(color),
+            color,
             top: true,
             left: true,
             bottom: true,

zed/assets/themes/_base.toml 🔗

@@ -4,7 +4,7 @@ background = "$elevation_1"
 [ui.tab]
 background = "$elevation_2"
 text = "$text_dull"
-border.color = "#000000"
+border = { color = "#000000", width = 1.0 }
 padding = { left = 10, right = 10 }
 icon_close = "#383839"
 icon_dirty = "#556de8"

zed/assets/themes/dark.toml 🔗

@@ -10,7 +10,7 @@ text_bright = "#ffffff"
 text_normal = "#d4d4d4"
 
 [syntax]
-keyword = { color = "#c586c0", weight = "bold" }
+keyword = { color = "#0086c0", weight = "bold" }
 function = "#dcdcaa"
 string = "#cb8f77"
 type = "#4ec9b0"