Compiling

Nathan Sobo created

Change summary

crates/gpui/playground/src/element.rs                        | 29 ++-
crates/gpui/playground/src/frame.rs                          |  2 
crates/gpui/playground/src/hoverable.rs                      | 19 +-
crates/gpui/playground/src/paint_context.rs                  |  6 
crates/gpui/playground/src/text.rs                           |  2 
crates/gpui/src/app.rs                                       | 17 +
crates/refineable/derive_refineable/src/derive_refineable.rs | 48 ++++-
crates/refineable/src/refineable.rs                          |  9 
8 files changed, 95 insertions(+), 37 deletions(-)

Detailed changes

crates/gpui/playground/src/element.rs 🔗

@@ -12,6 +12,7 @@ use gpui::{
     EngineLayout, EventContext, RenderContext, ViewContext,
 };
 use playground_macros::tailwind_lengths;
+use refineable::Refineable;
 use std::{
     any::{Any, TypeId},
     cell::Cell,
@@ -61,7 +62,7 @@ pub trait Element<V: 'static>: 'static {
 
     fn declared_style(&mut self) -> &mut StyleRefinement;
 
-    fn computed_style(&mut self) -> &StyleRefinement {
+    fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
         self.declared_style()
     }
 
@@ -444,7 +445,8 @@ pub trait Element<V: 'static>: 'static {
 
 // Object-safe counterpart of Element used by AnyElement to store elements as trait objects.
 trait ElementObject<V> {
-    fn style(&mut self) -> &mut StyleRefinement;
+    fn declared_style(&mut self) -> &mut StyleRefinement;
+    fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement;
     fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
     fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
         -> Result<(NodeId, Box<dyn Any>)>;
@@ -457,10 +459,14 @@ trait ElementObject<V> {
 }
 
 impl<V: 'static, E: Element<V>> ElementObject<V> for E {
-    fn style(&mut self) -> &mut StyleRefinement {
+    fn declared_style(&mut self) -> &mut StyleRefinement {
         Element::declared_style(self)
     }
 
+    fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
+        Element::computed_style(self, cx)
+    }
+
     fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
         Element::handlers_mut(self)
     }
@@ -510,10 +516,13 @@ impl<V: 'static> AnyElement<V> {
         Ok(node_id)
     }
 
-    pub fn push_text_style(&mut self, cx: &mut impl RenderContext) -> bool {
-        let text_style = self.element.style().text_style();
+    pub fn push_text_style<'a: 'b, 'b>(&mut self, cx: &mut impl RenderContext<'a, 'b, V>) -> bool {
+        let text_style = self
+            .element
+            .computed_style(cx.as_view_context())
+            .text_style();
         if let Some(text_style) = text_style {
-            cx.push_text_style(cx.text_style().refine(text_style));
+            cx.push_text_style(cx.text_style().refined(&text_style));
             true
         } else {
             false
@@ -535,7 +544,7 @@ impl<V: 'static> AnyElement<V> {
             from_element: element_layout.as_mut(),
         };
 
-        let style = self.element.style();
+        let style = self.element.computed_style(cx.as_view_context());
 
         let fill_color = style.fill.as_ref().and_then(|fill| fill.color());
         if let Some(fill_color) = fill_color {
@@ -583,7 +592,11 @@ impl<V: 'static> Element<V> for AnyElement<V> {
     type Layout = ();
 
     fn declared_style(&mut self) -> &mut StyleRefinement {
-        self.element.style()
+        self.element.declared_style()
+    }
+
+    fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
+        self.element.computed_style(cx)
     }
 
     fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {

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

@@ -48,7 +48,7 @@ impl<V: 'static> Element<V> for Frame<V> {
             .collect::<Result<Vec<LayoutNodeId>>>()?;
 
         let rem_size = cx.rem_pixels();
-        let style = Style::default().refine(&self.style);
+        let style = Style::default().refined(&self.style);
         let node_id = cx
             .layout_engine()
             .ok_or_else(|| anyhow!("no layout engine"))?

crates/gpui/playground/src/hoverable.rs 🔗

@@ -3,17 +3,15 @@ use std::{cell::Cell, marker::PhantomData, rc::Rc};
 use gpui::{
     geometry::{rect::RectF, vector::Vector2F},
     scene::MouseMove,
-    EngineLayout,
+    EngineLayout, ViewContext,
 };
+use refineable::Refineable;
 
-use crate::{
-    element::Element,
-    style::{Style, StyleRefinement},
-};
+use crate::{element::Element, style::StyleRefinement};
 
 pub struct Hoverable<V, E> {
     hover_style: StyleRefinement,
-    computed_style: Option<Style>,
+    computed_style: Option<StyleRefinement>,
     view_type: PhantomData<V>,
     child: E,
 }
@@ -36,8 +34,13 @@ impl<V: 'static, E: Element<V>> Element<V> for Hoverable<V, E> {
         &mut self.hover_style
     }
 
-    fn computed_style(&mut self) -> &StyleRefinement {
-        todo!()
+    fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
+        self.computed_style.get_or_insert_with(|| {
+            let mut style = self.child.computed_style(cx).clone();
+            // if hovered
+            style.refine(&self.hover_style);
+            style
+        })
     }
 
     fn handlers_mut(&mut self) -> &mut Vec<crate::element::EventHandler<V>> {

crates/gpui/playground/src/paint_context.rs 🔗

@@ -13,7 +13,7 @@ pub struct PaintContext<'a, 'b, 'c, 'd, V> {
     pub(crate) scene: &'d mut gpui::SceneBuilder,
 }
 
-impl<V> RenderContext for PaintContext<'_, '_, '_, '_, V> {
+impl<'a, 'b, V> RenderContext<'a, 'b, V> for PaintContext<'a, 'b, '_, '_, V> {
     fn text_style(&self) -> gpui::fonts::TextStyle {
         self.legacy_cx.text_style()
     }
@@ -25,6 +25,10 @@ impl<V> RenderContext for PaintContext<'_, '_, '_, '_, V> {
     fn pop_text_style(&mut self) {
         self.legacy_cx.pop_text_style()
     }
+
+    fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V> {
+        &mut self.view_context
+    }
 }
 
 impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {

crates/gpui/playground/src/text.rs 🔗

@@ -43,7 +43,7 @@ impl<V: 'static> Element<V> for Text<V> {
         let text = self.text.clone();
         let layout = Arc::new(Mutex::new(None));
 
-        let style: Style = Style::default().refine(&self.metadata.style);
+        let style: Style = Style::default().refined(&self.metadata.style);
         let node_id = layout_engine.add_measured_node(style.to_taffy(rem_size), {
             let layout = layout.clone();
             move |params| {

crates/gpui/src/app.rs 🔗

@@ -3383,10 +3383,11 @@ impl<V> BorrowWindowContext for ViewContext<'_, '_, V> {
 ///
 /// It's that PaintContext should be implemented in terms of layout context and
 /// deref to it, in which case we wouldn't need this.
-pub trait RenderContext {
+pub trait RenderContext<'a, 'b, V> {
     fn text_style(&self) -> TextStyle;
     fn push_text_style(&mut self, style: TextStyle);
     fn pop_text_style(&mut self);
+    fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V>;
 }
 
 pub struct LayoutContext<'a, 'b, 'c, V> {
@@ -3472,7 +3473,7 @@ impl<'a, 'b, 'c, V> LayoutContext<'a, 'b, 'c, V> {
     }
 }
 
-impl<'a, 'b, 'c, V> RenderContext for LayoutContext<'a, 'b, 'c, V> {
+impl<'a, 'b, 'c, V> RenderContext<'a, 'b, V> for LayoutContext<'a, 'b, 'c, V> {
     fn text_style(&self) -> TextStyle {
         self.text_style_stack
             .last()
@@ -3487,6 +3488,10 @@ impl<'a, 'b, 'c, V> RenderContext for LayoutContext<'a, 'b, 'c, V> {
     fn pop_text_style(&mut self) {
         self.text_style_stack.pop();
     }
+
+    fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V> {
+        &mut self.view_context
+    }
 }
 
 impl<'a, 'b, 'c, V> Deref for LayoutContext<'a, 'b, 'c, V> {
@@ -3544,7 +3549,7 @@ impl<V> BorrowWindowContext for LayoutContext<'_, '_, '_, V> {
 }
 
 pub struct PaintContext<'a, 'b, 'c, V> {
-    view_context: &'c mut ViewContext<'a, 'b, V>,
+    pub view_context: &'c mut ViewContext<'a, 'b, V>,
     text_style_stack: Vec<TextStyle>,
 }
 
@@ -3557,7 +3562,7 @@ impl<'a, 'b, 'c, V> PaintContext<'a, 'b, 'c, V> {
     }
 }
 
-impl<'a, 'b, 'c, V> RenderContext for PaintContext<'a, 'b, 'c, V> {
+impl<'a, 'b, 'c, V> RenderContext<'a, 'b, V> for PaintContext<'a, 'b, 'c, V> {
     fn text_style(&self) -> TextStyle {
         self.text_style_stack
             .last()
@@ -3572,6 +3577,10 @@ impl<'a, 'b, 'c, V> RenderContext for PaintContext<'a, 'b, 'c, V> {
     fn pop_text_style(&mut self) {
         self.text_style_stack.pop();
     }
+
+    fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V> {
+        &mut self.view_context
+    }
 }
 
 impl<'a, 'b, 'c, V> Deref for PaintContext<'a, 'b, 'c, V> {

crates/refineable/derive_refineable/src/derive_refineable.rs 🔗

@@ -44,14 +44,14 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
                         paren_token: None,
                         modifier: syn::TraitBoundModifier::None,
                         lifetimes: None,
-                        path: parse_quote!(std::clone::Clone),
+                        path: parse_quote!(Clone),
                     }));
                     punctuated.push_punct(syn::token::Add::default());
                     punctuated.push_value(TypeParamBound::Trait(TraitBound {
                         paren_token: None,
                         modifier: syn::TraitBoundModifier::None,
                         lifetimes: None,
-                        path: parse_quote!(std::default::Default),
+                        path: parse_quote!(Default),
                     }));
                     punctuated
                 },
@@ -73,7 +73,7 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
         },
     };
 
-    let field_initializations: Vec<TokenStream2> = fields
+    let field_assignments: Vec<TokenStream2> = fields
         .iter()
         .map(|field| {
             let name = &field.ident;
@@ -82,18 +82,38 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
 
             if is_refineable {
                 quote! {
-                    clone.#name = self.#name.refine(&refinement.#name);
+                    self.#name.refine(&refinement.#name);
                 }
             } else if is_optional {
                 quote! {
                     if let Some(ref value) = &refinement.#name {
-                        clone.#name = Some(value.clone());
+                        self.#name = Some(value.clone());
                     }
                 }
             } else {
                 quote! {
                     if let Some(ref value) = &refinement.#name {
-                        clone.#name = value.clone();
+                        self.#name = value.clone();
+                    }
+                }
+            }
+        })
+        .collect();
+
+    let refinement_field_assignments: Vec<TokenStream2> = fields
+        .iter()
+        .map(|field| {
+            let name = &field.ident;
+            let is_refineable = is_refineable_field(field);
+
+            if is_refineable {
+                quote! {
+                    self.#name.refine(&refinement.#name);
+                }
+            } else {
+                quote! {
+                    if let Some(ref value) = &refinement.#name {
+                        self.#name = Some(value.clone());
                     }
                 }
             }
@@ -111,10 +131,18 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
         {
             type Refinement = #refinement_ident #ty_generics;
 
-            fn refine(&self, refinement: &Self::Refinement) -> Self {
-                let mut clone = self.clone();
-                #( #field_initializations )*
-                clone
+            fn refine(&mut self, refinement: &Self::Refinement) {
+                #( #field_assignments )*
+            }
+        }
+
+        impl #impl_generics Refineable for #refinement_ident #ty_generics
+            #where_clause
+        {
+            type Refinement = #refinement_ident #ty_generics;
+
+            fn refine(&mut self, refinement: &Self::Refinement) {
+                #( #refinement_field_assignments )*
             }
         }
     };

crates/refineable/src/refineable.rs 🔗

@@ -3,11 +3,12 @@ pub use derive_refineable::Refineable;
 pub trait Refineable {
     type Refinement;
 
-    fn refine(&self, refinement: &Self::Refinement) -> Self;
-    fn from_refinement(refinement: &Self::Refinement) -> Self
+    fn refine(&mut self, refinement: &Self::Refinement);
+    fn refined(mut self, refinement: &Self::Refinement) -> Self
     where
-        Self: Sized + Default,
+        Self: Sized,
     {
-        Self::default().refine(refinement)
+        self.refine(refinement);
+        self
     }
 }