What if we base themes on Rose Pine

Nathan Sobo created

Change summary

Cargo.lock                                        |   3 
crates/gpui/playground/ui/Cargo.toml              |   5 
crates/gpui/playground/ui/src/color.rs            |  60 ++++
crates/gpui/playground/ui/src/frame.rs            |  81 +++---
crates/gpui/playground/ui/src/playground_ui.rs    |  50 ++++
crates/gpui/playground/ui/src/themes.rs           |  91 ++++++++
crates/gpui/playground/ui/src/themes/rose_pine.rs | 187 ++++++++++------
crates/gpui/src/app.rs                            |  16 -
crates/gpui/src/app/window.rs                     |   2 
crates/zed/Cargo.toml                             |   2 
10 files changed, 367 insertions(+), 130 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -5301,11 +5301,14 @@ dependencies = [
 name = "playground_ui"
 version = "0.1.0"
 dependencies = [
+ "collections",
  "derive_more",
  "gpui",
  "log",
  "optional_struct",
+ "serde",
  "smallvec",
+ "util",
 ]
 
 [[package]]

crates/gpui/playground/ui/Cargo.toml 🔗

@@ -9,11 +9,14 @@ path = "src/playground_ui.rs"
 crate-type = ["dylib"]
 
 [dependencies]
-derive_more = "0.99.17"
+collections = { path = "../../../collections" }
+util = { path = "../../../util" }
 gpui = { path = "../.." }
+derive_more = "0.99.17"
 log.workspace = true
 optional_struct = "0.3.1"
 smallvec.workspace = true
+serde.workspace = true
 
 [dev-dependencies]
 gpui = { path = "../..", features = ["test-support"] }

crates/gpui/playground/ui/src/color.rs 🔗

@@ -1,12 +1,14 @@
 #![allow(dead_code)]
 
+use std::{num::ParseIntError, ops::Range};
+
 use smallvec::SmallVec;
 
-pub fn rgb(hex: u32) -> Rgba {
+pub fn rgb<C: From<Rgba>>(hex: u32) -> C {
     let r = ((hex >> 16) & 0xFF) as f32 / 255.0;
     let g = ((hex >> 8) & 0xFF) as f32 / 255.0;
     let b = (hex & 0xFF) as f32 / 255.0;
-    Rgba { r, g, b, a: 1.0 }
+    Rgba { r, g, b, a: 1.0 }.into()
 }
 
 #[derive(Clone, Copy, Default, Debug)]
@@ -17,6 +19,22 @@ pub struct Rgba {
     pub a: f32,
 }
 
+pub trait Lerp {
+    fn lerp(&self, level: f32) -> Hsla;
+}
+
+impl Lerp for Range<Hsla> {
+    fn lerp(&self, level: f32) -> Hsla {
+        let level = level.clamp(0., 1.);
+        Hsla {
+            h: self.start.h + (level * (self.end.h - self.start.h)),
+            s: self.start.s + (level * (self.end.s - self.start.s)),
+            l: self.start.l + (level * (self.end.l - self.start.l)),
+            a: self.start.a + (level * (self.end.a - self.start.a)),
+        }
+    }
+}
+
 impl From<Hsla> for Rgba {
     fn from(color: Hsla) -> Self {
         let h = color.h;
@@ -47,18 +65,39 @@ impl From<Hsla> for Rgba {
     }
 }
 
+impl TryFrom<&'_ str> for Rgba {
+    type Error = ParseIntError;
+
+    fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
+        let r = u8::from_str_radix(&value[1..3], 16)? as f32 / 255.0;
+        let g = u8::from_str_radix(&value[3..5], 16)? as f32 / 255.0;
+        let b = u8::from_str_radix(&value[5..7], 16)? as f32 / 255.0;
+        let a = if value.len() > 7 {
+            u8::from_str_radix(&value[7..9], 16)? as f32 / 255.0
+        } else {
+            1.0
+        };
+
+        Ok(Rgba { r, g, b, a })
+    }
+}
+
 impl Into<gpui::color::Color> for Rgba {
     fn into(self) -> gpui::color::Color {
         gpui::color::rgba(self.r, self.g, self.b, self.a)
     }
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub struct Hsla {
-    h: f32,
-    s: f32,
-    l: f32,
-    a: f32,
+    pub h: f32,
+    pub s: f32,
+    pub l: f32,
+    pub a: f32,
+}
+
+pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
+    Hsla { h, s, l, a }
 }
 
 impl From<Rgba> for Hsla {
@@ -100,6 +139,13 @@ impl From<Rgba> for Hsla {
 }
 
 impl Hsla {
+    /// Scales the saturation and lightness by the given values, clamping at 1.0.
+    pub fn scale_sl(mut self, s: f32, l: f32) -> Self {
+        self.s = (self.s * s).clamp(0., 1.);
+        self.l = (self.l * l).clamp(0., 1.);
+        self
+    }
+
     /// Increases the saturation of the color by a certain amount, with a max
     /// value of 1.0.
     pub fn saturate(mut self, amount: f32) -> Self {

crates/gpui/playground/ui/src/frame.rs 🔗

@@ -28,6 +28,7 @@ pub struct Frame<V: View> {
     style: FrameStyle,
     children: Vec<AnyElement<V>>,
     id: Option<Cow<'static, str>>,
+    before_paint: Option<Box<dyn FnMut(RectF, &mut FrameLayout, &mut PaintContext<V>)>>,
 }
 
 pub fn column<V: View>() -> Frame<V> {
@@ -60,6 +61,7 @@ impl<V: View> Default for Frame<V> {
             style: Default::default(),
             children: Default::default(),
             id: None,
+            before_paint: None,
         }
     }
 }
@@ -79,7 +81,6 @@ impl<V: View> Element<V> for Frame<V> {
         } else {
             todo!()
         };
-
         (layout.size.max(constraint.min), layout)
     }
 
@@ -92,22 +93,21 @@ impl<V: View> Element<V> for Frame<V> {
         view: &mut V,
         cx: &mut PaintContext<V>,
     ) -> Self::PaintState {
-        dbg!(self.id_string());
-        dbg!(bounds.origin(), bounds.size());
+        if let Some(before_paint) = &mut self.before_paint {
+            before_paint(bounds, layout, cx);
+        }
 
-        let bounds_center = dbg!(bounds.size()) / 2.;
+        let bounds_center = bounds.size() / 2.;
         let bounds_target = bounds_center + (bounds_center * self.style.align.0);
-        let layout_center = dbg!(layout.size) / 2.;
+        let layout_center = layout.size / 2.;
         let layout_target = layout_center + layout_center * self.style.align.0;
         let delta = bounds_target - layout_target;
 
         let aligned_bounds = RectF::new(bounds.origin() + delta, layout.size);
-        dbg!(aligned_bounds.origin(), aligned_bounds.size());
         let margined_bounds = RectF::from_points(
             aligned_bounds.origin() + vec2f(layout.margins.left, layout.margins.top),
             aligned_bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom),
         );
-        dbg!(margined_bounds.origin(), margined_bounds.size());
 
         // Paint drop shadow
         for shadow in &self.style.shadows {
@@ -238,6 +238,11 @@ impl<V: View> Frame<V> {
         self
     }
 
+    pub fn size(self, size: impl Into<Size<Length>>) -> Self {
+        let size = size.into();
+        self.width(size.width).height(size.height)
+    }
+
     pub fn width(mut self, width: impl Into<Length>) -> Self {
         self.style.size.width = width.into();
         self
@@ -508,8 +513,15 @@ impl<V: View> Frame<V> {
             }
         }
 
-        dbg!(self.id_string());
-        dbg!(layout)
+        layout
+    }
+
+    fn before_paint<H>(mut self, handler: H) -> Self
+    where
+        H: 'static + FnMut(RectF, &mut FrameLayout, &mut PaintContext<V>),
+    {
+        self.before_paint = Some(Box::new(handler));
+        self
     }
 }
 
@@ -599,7 +611,7 @@ struct TextStyle {
 }
 
 #[derive(Add, Default, Clone)]
-struct Size<T> {
+pub struct Size<T> {
     width: T,
     height: T,
 }
@@ -1478,12 +1490,12 @@ where
     }
 }
 
-pub fn view<F, E>(mut function: F) -> ViewFn
+pub fn view<F, E>(mut render: F) -> ViewFn
 where
     F: 'static + FnMut(&mut ViewContext<ViewFn>) -> E,
     E: Element<ViewFn>,
 {
-    ViewFn(Box::new(move |cx| (function)(cx).into_any()))
+    ViewFn(Box::new(move |cx| (render)(cx).into_any()))
 }
 
 pub struct ViewFn(Box<dyn FnMut(&mut ViewContext<ViewFn>) -> AnyElement<ViewFn>>);
@@ -1508,8 +1520,8 @@ mod tests {
     use gpui::TestAppContext;
 
     #[gpui::test]
-    fn test_layout(cx: &mut TestAppContext) {
-        let window = cx.add_window(|_| {
+    fn test_frame_layout(cx: &mut TestAppContext) {
+        cx.add_window(|_| {
             view(|_| {
                 let theme = rose_pine::dawn();
                 column()
@@ -1520,32 +1532,25 @@ mod tests {
                         row()
                             .width(auto())
                             .height(rems(10.))
-                            .fill(theme.foam)
                             .justify(1.)
-                            .child(row().width(rems(10.)).height(auto()).fill(theme.gold)),
+                            .child(
+                                row()
+                                    .width(rems(10.))
+                                    .height(auto())
+                                    .fill(theme.surface(1.)),
+                            )
+                            .before_paint(|bounds, layout, cx| {
+                                assert_eq!(bounds.origin(), vec2f(0., 0.));
+                                assert_eq!(layout.size.x(), cx.window_size().x());
+                                assert_eq!(layout.size.y(), rems(10.).to_pixels(cx.rem_pixels()));
+                            }),
                     )
                     .child(row())
-            });
-        });
-
-        window.update(cx, |cx| {
-            let root = cx.root_element();
-            dbg!(root.debug(cx).unwrap());
-        });
-
-        // tree.layout(
-        //     SizeConstraint::strict(vec2f(100., 100.)),
-        //     &mut (),
-        //     LayoutContext::test(),
-        // );
-
-        // LayoutContext::new(
-        //     cx,
-        //     new_parents,
-        //     views_to_notify_if_ancestors_change,
-        //     refreshing,
-        // )
-
-        // tree.layout(SizeConstraint::strict(vec2f(100., 100.)), &mut (), cx)
+                    .before_paint(|bounds, layout, cx| {
+                        assert_eq!(layout.size, cx.window_size());
+                    })
+            })
+        })
+        .remove(cx);
     }
 }

crates/gpui/playground/ui/src/playground_ui.rs 🔗

@@ -3,6 +3,7 @@
 use frame::{length::auto, *};
 use gpui::{AnyElement, Element, LayoutContext, View, ViewContext};
 use std::{borrow::Cow, cell::RefCell, marker::PhantomData, rc::Rc};
+use themes::ThemeColors;
 use tokens::{margin::m4, text::lg};
 
 mod color;
@@ -21,6 +22,25 @@ impl<V: View> Playground<V> {
     }
 }
 
+fn workspace<V: View>(theme: &ThemeColors) -> impl Element<V> {
+    column()
+        .child(title_bar(theme))
+        .child(stage(theme))
+        .child(status_bar(theme))
+}
+
+fn title_bar<V: View>(theme: &ThemeColors) -> impl Element<V> {
+    row().fill(theme.surface(1.0))
+}
+
+fn stage<V: View>(theme: &ThemeColors) -> impl Element<V> {
+    row().fill(theme.surface(0.9))
+}
+
+fn status_bar<V: View>(theme: &ThemeColors) -> impl Element<V> {
+    row().fill(theme.surface(0.1))
+}
+
 pub trait DialogDelegate<V: View>: 'static {}
 
 impl<V: View> DialogDelegate<V> for () {}
@@ -113,6 +133,36 @@ where
     }
 }
 
+// impl<V, D, F> Button<V, D, F>
+// where
+//     V: View,
+//     F: ClickHandler<V, D>,
+// {
+//     fn render(&mut self, _: &mut V, _: &mut LayoutContext<V>) -> impl Element<V> {
+//         // TODO! Handle click etc
+//         row()
+//             .fill(theme.colors.primary(5))
+//             .child(text(self.label.clone()).text_color(theme.colors.on_primary()))
+//     }
+// }
+
+// struct Tab<V> {
+//     active: bool,
+// }
+
+// impl<V> Tab<V>
+// where
+//     V: View,
+// {
+//     fn tab(&mut self, _: &mut V, _: &mut LayoutContext<V>) -> impl Element<V> {
+//         let theme = todo!();
+//         // TODO! Handle click etc
+//         row()
+//             .fill(theme.colors.neutral(6))
+//             .child(text(self.label.clone()).text_color(theme.colors.on_neutral()))
+//     }
+// }
+
 impl<V: View> Button<V, (), ()> {
     fn data<D>(self, data: D) -> Button<V, D, ()>
     where

crates/gpui/playground/ui/src/themes.rs 🔗

@@ -1 +1,92 @@
+use crate::color::{Hsla, Lerp};
+use serde::{Deserialize, Serialize};
+use std::{ops::Range, sync::Arc};
+
 pub mod rose_pine;
+
+pub struct ThemeColors {
+    pub base: Range<Hsla>,
+    pub surface: Range<Hsla>,
+    pub overlay: Range<Hsla>,
+    pub muted: Range<Hsla>,
+    pub subtle: Range<Hsla>,
+    pub text: Range<Hsla>,
+    pub highlight_low: Range<Hsla>,
+    pub highlight_med: Range<Hsla>,
+    pub highlight_high: Range<Hsla>,
+    pub success: Range<Hsla>,
+    pub warning: Range<Hsla>,
+    pub error: Range<Hsla>,
+    pub inserted: Range<Hsla>,
+    pub deleted: Range<Hsla>,
+    pub modified: Range<Hsla>,
+}
+
+impl ThemeColors {
+    pub fn base(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn surface(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn overlay(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn muted(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn subtle(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn text(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn highlight_low(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn highlight_med(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn highlight_high(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn success(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn warning(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn error(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn inserted(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn deleted(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+    pub fn modified(&self, level: f32) -> Hsla {
+        self.deleted.lerp(level)
+    }
+}
+
+#[derive(Serialize, Deserialize)]
+struct Entity {
+    class: String,
+    #[serde(rename = "type")]
+    kind: String,
+    id: Arc<str>,
+    name: String,
+    value: String,
+    description: String,
+    category_id: String,
+    last_updated_by: String,
+    last_updated: String,
+    tags: Vec<String>,
+}
+
+#[derive(Serialize, Deserialize)]
+struct Category {
+    id: String,
+    label: String,
+}

crates/gpui/playground/ui/src/themes/rose_pine.rs 🔗

@@ -1,86 +1,133 @@
-use crate::color::{rgb, Rgba};
+use std::ops::Range;
+
+use crate::{
+    color::{hsla, rgb, Hsla},
+    ThemeColors,
+};
+
+pub struct RosePineThemes {
+    pub default: RosePinePalette,
+    pub dawn: RosePinePalette,
+    pub moon: RosePinePalette,
+}
 
 #[derive(Clone, Copy, Debug)]
-pub struct ThemeColors {
-    pub base: Rgba,
-    pub surface: Rgba,
-    pub overlay: Rgba,
-    pub muted: Rgba,
-    pub subtle: Rgba,
-    pub text: Rgba,
-    pub love: Rgba,
-    pub gold: Rgba,
-    pub rose: Rgba,
-    pub pine: Rgba,
-    pub foam: Rgba,
-    pub iris: Rgba,
-    pub highlight_low: Rgba,
-    pub highlight_med: Rgba,
-    pub highlight_high: Rgba,
+pub struct RosePinePalette {
+    pub base: Hsla,
+    pub surface: Hsla,
+    pub overlay: Hsla,
+    pub muted: Hsla,
+    pub subtle: Hsla,
+    pub text: Hsla,
+    pub love: Hsla,
+    pub gold: Hsla,
+    pub rose: Hsla,
+    pub pine: Hsla,
+    pub foam: Hsla,
+    pub iris: Hsla,
+    pub highlight_low: Hsla,
+    pub highlight_med: Hsla,
+    pub highlight_high: Hsla,
 }
 
-pub struct RosePineThemes {
-    pub default: ThemeColors,
-    pub dawn: ThemeColors,
-    pub moon: ThemeColors,
+impl RosePinePalette {
+    pub fn default() -> RosePinePalette {
+        RosePinePalette {
+            base: rgb(0x191724),
+            surface: rgb(0x1f1d2e),
+            overlay: rgb(0x26233a),
+            muted: rgb(0x6e6a86),
+            subtle: rgb(0x908caa),
+            text: rgb(0xe0def4),
+            love: rgb(0xeb6f92),
+            gold: rgb(0xf6c177),
+            rose: rgb(0xebbcba),
+            pine: rgb(0x31748f),
+            foam: rgb(0x9ccfd8),
+            iris: rgb(0xc4a7e7),
+            highlight_low: rgb(0x21202e),
+            highlight_med: rgb(0x403d52),
+            highlight_high: rgb(0x524f67),
+        }
+    }
+
+    pub fn moon() -> RosePinePalette {
+        RosePinePalette {
+            base: rgb(0x232136),
+            surface: rgb(0x2a273f),
+            overlay: rgb(0x393552),
+            muted: rgb(0x6e6a86),
+            subtle: rgb(0x908caa),
+            text: rgb(0xe0def4),
+            love: rgb(0xeb6f92),
+            gold: rgb(0xf6c177),
+            rose: rgb(0xea9a97),
+            pine: rgb(0x3e8fb0),
+            foam: rgb(0x9ccfd8),
+            iris: rgb(0xc4a7e7),
+            highlight_low: rgb(0x2a283e),
+            highlight_med: rgb(0x44415a),
+            highlight_high: rgb(0x56526e),
+        }
+    }
+
+    pub fn dawn() -> RosePinePalette {
+        RosePinePalette {
+            base: rgb(0xfaf4ed),
+            surface: rgb(0xfffaf3),
+            overlay: rgb(0xf2e9e1),
+            muted: rgb(0x9893a5),
+            subtle: rgb(0x797593),
+            text: rgb(0x575279),
+            love: rgb(0xb4637a),
+            gold: rgb(0xea9d34),
+            rose: rgb(0xd7827e),
+            pine: rgb(0x286983),
+            foam: rgb(0x56949f),
+            iris: rgb(0x907aa9),
+            highlight_low: rgb(0xf4ede8),
+            highlight_med: rgb(0xdfdad9),
+            highlight_high: rgb(0xcecacd),
+        }
+    }
 }
 
 pub fn default() -> ThemeColors {
-    ThemeColors {
-        base: rgb(0x191724),
-        surface: rgb(0x1f1d2e),
-        overlay: rgb(0x26233a),
-        muted: rgb(0x6e6a86),
-        subtle: rgb(0x908caa),
-        text: rgb(0xe0def4),
-        love: rgb(0xeb6f92),
-        gold: rgb(0xf6c177),
-        rose: rgb(0xebbcba),
-        pine: rgb(0x31748f),
-        foam: rgb(0x9ccfd8),
-        iris: rgb(0xc4a7e7),
-        highlight_low: rgb(0x21202e),
-        highlight_med: rgb(0x403d52),
-        highlight_high: rgb(0x524f67),
-    }
+    theme_colors(&RosePinePalette::default())
 }
 
 pub fn moon() -> ThemeColors {
-    ThemeColors {
-        base: rgb(0x232136),
-        surface: rgb(0x2a273f),
-        overlay: rgb(0x393552),
-        muted: rgb(0x6e6a86),
-        subtle: rgb(0x908caa),
-        text: rgb(0xe0def4),
-        love: rgb(0xeb6f92),
-        gold: rgb(0xf6c177),
-        rose: rgb(0xea9a97),
-        pine: rgb(0x3e8fb0),
-        foam: rgb(0x9ccfd8),
-        iris: rgb(0xc4a7e7),
-        highlight_low: rgb(0x2a283e),
-        highlight_med: rgb(0x44415a),
-        highlight_high: rgb(0x56526e),
-    }
+    theme_colors(&RosePinePalette::moon())
 }
 
 pub fn dawn() -> ThemeColors {
+    theme_colors(&RosePinePalette::dawn())
+}
+
+fn theme_colors(p: &RosePinePalette) -> ThemeColors {
     ThemeColors {
-        base: rgb(0xfaf4ed),
-        surface: rgb(0xfffaf3),
-        overlay: rgb(0xf2e9e1),
-        muted: rgb(0x9893a5),
-        subtle: rgb(0x797593),
-        text: rgb(0x575279),
-        love: rgb(0xb4637a),
-        gold: rgb(0xea9d34),
-        rose: rgb(0xd7827e),
-        pine: rgb(0x286983),
-        foam: rgb(0x56949f),
-        iris: rgb(0x907aa9),
-        highlight_low: rgb(0xf4ede8),
-        highlight_med: rgb(0xdfdad9),
-        highlight_high: rgb(0xcecacd),
+        base: scale_sl(p.base, (0.8, 0.8), (1.2, 1.2)),
+        surface: scale_sl(p.surface, (0.8, 0.8), (1.2, 1.2)),
+        overlay: scale_sl(p.overlay, (0.8, 0.8), (1.2, 1.2)),
+        muted: scale_sl(p.muted, (0.8, 0.8), (1.2, 1.2)),
+        subtle: scale_sl(p.subtle, (0.8, 0.8), (1.2, 1.2)),
+        text: scale_sl(p.text, (0.8, 0.8), (1.2, 1.2)),
+        highlight_low: scale_sl(p.highlight_low, (0.8, 0.8), (1.2, 1.2)),
+        highlight_med: scale_sl(p.highlight_med, (0.8, 0.8), (1.2, 1.2)),
+        highlight_high: scale_sl(p.highlight_high, (0.8, 0.8), (1.2, 1.2)),
+        success: scale_sl(p.foam, (0.8, 0.8), (1.2, 1.2)),
+        warning: scale_sl(p.gold, (0.8, 0.8), (1.2, 1.2)),
+        error: scale_sl(p.love, (0.8, 0.8), (1.2, 1.2)),
+        inserted: scale_sl(p.foam, (0.8, 0.8), (1.2, 1.2)),
+        deleted: scale_sl(p.love, (0.8, 0.8), (1.2, 1.2)),
+        modified: scale_sl(p.rose, (0.8, 0.8), (1.2, 1.2)),
     }
 }
+
+/// Produces a range by multiplying the saturation and lightness of the base color by the given
+/// start and end factors.
+fn scale_sl(base: Hsla, (start_s, start_l): (f32, f32), (end_s, end_l): (f32, f32)) -> Range<Hsla> {
+    let start = hsla(base.h, base.s * start_s, base.l * start_l, base.a);
+    let end = hsla(base.h, base.s * end_s, base.l * end_l, base.a);
+    Range { start, end }
+}

crates/gpui/src/app.rs 🔗

@@ -44,7 +44,7 @@ pub use test_app_context::{ContextHandle, TestAppContext};
 use window_input_handler::WindowInputHandler;
 
 use crate::{
-    elements::{AnyElement, AnyRootElement, Empty, RootElement},
+    elements::{AnyElement, AnyRootElement, RootElement},
     executor::{self, Task},
     fonts::TextStyle,
     json,
@@ -55,7 +55,7 @@ use crate::{
     },
     util::post_inc,
     window::{Window, WindowContext},
-    AssetCache, AssetSource, ClipboardItem, Element, FontCache, MouseRegionId,
+    AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId,
 };
 
 use self::ref_counts::RefCounts;
@@ -129,16 +129,6 @@ pub trait View: Entity + Sized {
     }
 }
 
-impl Entity for () {
-    type Event = ();
-}
-
-impl View for () {
-    fn render(&mut self, _: &mut ViewContext<'_, '_, Self>) -> AnyElement<Self> {
-        Empty::new().into_any()
-    }
-}
-
 pub trait BorrowAppContext {
     fn read_with<T, F: FnOnce(&AppContext) -> T>(&self, f: F) -> T;
     fn update<T, F: FnOnce(&mut AppContext) -> T>(&mut self, f: F) -> T;
@@ -2155,7 +2145,7 @@ struct ViewMetadata {
     keymap_context: KeymapContext,
 }
 
-#[derive(Default, Clone)]
+#[derive(Default, Clone, Debug)]
 pub struct WindowInvalidation {
     pub updated: HashSet<usize>,
     pub removed: Vec<usize>,

crates/gpui/src/app/window.rs 🔗

@@ -940,7 +940,9 @@ impl<'a> WindowContext<'a> {
     pub fn layout(&mut self, refreshing: bool) -> Result<HashMap<usize, usize>> {
         let window_size = self.window.platform_window.content_size();
         let root_view_id = self.window.root_view().id();
+
         let mut rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap();
+
         let mut new_parents = HashMap::default();
         let mut views_to_notify_if_ancestors_change = HashMap::default();
         rendered_root.layout(

crates/zed/Cargo.toml 🔗

@@ -92,7 +92,7 @@ postage.workspace = true
 rand.workspace = true
 regex.workspace = true
 rsa = "0.4"
-rust-embed = { version = "6.3", features = ["include-exclude"] }
+rust-embed = { version = "6.8.1" }
 serde.workspace = true
 serde_derive.workspace = true
 serde_json.workspace = true