WIP: Lots of errors, starting on resurrecting derive Element

Nathan Sobo created

Change summary

crates/gpui2/src/element.rs               |  2 
crates/gpui2_macros/src/derive_element.rs | 75 +++++++++++++++++++++++++
crates/gpui2_macros/src/gpui2_macros.rs   | 18 +++---
crates/ui2/src/components/avatar.rs       |  5 -
crates/ui2/src/components/toast.rs        | 60 ++++++++++---------
5 files changed, 118 insertions(+), 42 deletions(-)

Detailed changes

crates/gpui2/src/element.rs 🔗

@@ -364,7 +364,7 @@ impl<V: 'static> Element<V> for AnyElement<V> {
 
     fn paint(
         self,
-        bounds: Bounds<Pixels>,
+        _bounds: Bounds<Pixels>,
         view_state: &mut V,
         _: &mut Self::State,
         cx: &mut ViewContext<V>,

crates/gpui2_macros/src/derive_element.rs 🔗

@@ -0,0 +1,75 @@
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::{parse_macro_input, DeriveInput, GenericParam};
+
+pub fn derive_element(input: TokenStream) -> TokenStream {
+    let ast = parse_macro_input!(input as DeriveInput);
+    let type_name = ast.ident;
+
+    let mut view_state_ty = quote! { V };
+
+    for param in &ast.generics.params {
+        if let GenericParam::Type(type_param) = param {
+            let type_ident = &type_param.ident;
+            view_state_ty = quote! {#type_ident};
+            break;
+        }
+    }
+
+    let attrs = &ast.attrs;
+    for attr in attrs {
+        if attr.path.is_ident("element") {
+            match attr.parse_meta() {
+                Ok(syn::Meta::List(i)) => {
+                    for nested_meta in i.nested {
+                        if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = nested_meta {
+                            if nv.path.is_ident("view_state") {
+                                if let syn::Lit::Str(lit_str) = nv.lit {
+                                    view_state_ty = lit_str.value().parse().unwrap();
+                                }
+                            }
+                        }
+                    }
+                }
+                _ => (),
+            }
+        }
+    }
+
+    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
+
+    let gen = quote! {
+        impl #impl_generics gpui::Element<#view_state_ty> for #type_name #ty_generics
+        #where_clause
+        {
+            type State = Option<gpui::AnyElement<#view_state_ty>>;
+
+            fn element_id(&self) -> Option<gpui::ElementId> {
+                None
+            }
+
+            fn layout(
+                &mut self,
+                view_state: &mut #view_state_ty,
+                _element_state: Option<Self::State>,
+                cx: &mut gpui::ViewContext<#view_state_ty>,
+            ) -> (gpui::LayoutId, Self::State) {
+                let mut element = self.render(view_state, cx).into_any();
+                let layout_id = element.layout(view_state, cx);
+                (layout_id, Some(element))
+            }
+
+            fn paint(
+                self,
+                _bounds: gpui::Bounds<gpui::Pixels>,
+                view_state: &mut #view_state_ty,
+                rendered_element: &mut Self::State,
+                cx: &mut gpui::ViewContext<#view_state_ty>,
+            ) {
+                rendered_element.take().unwrap().paint(view_state, cx)
+            }
+        }
+    };
+
+    gen.into()
+}

crates/gpui2_macros/src/gpui2_macros.rs 🔗

@@ -7,11 +7,6 @@ mod test;
 
 use proc_macro::TokenStream;
 
-#[proc_macro]
-pub fn style_helpers(args: TokenStream) -> TokenStream {
-    style_helpers::style_helpers(args)
-}
-
 #[proc_macro_derive(Action)]
 pub fn action(input: TokenStream) -> TokenStream {
     action::action(input)
@@ -27,10 +22,15 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
     derive_component::derive_component(input)
 }
 
-// #[proc_macro_derive(Element)]
-// pub fn derive_element(input: TokenStream) -> TokenStream {
-//     derive_element::derive_element(input)
-// }
+#[proc_macro_derive(Element, attributes(element))]
+pub fn derive_element(input: TokenStream) -> TokenStream {
+    derive_element::derive_element(input)
+}
+
+#[proc_macro]
+pub fn style_helpers(input: TokenStream) -> TokenStream {
+    style_helpers::style_helpers(input)
+}
 
 #[proc_macro_attribute]
 pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {

crates/ui2/src/components/avatar.rs 🔗

@@ -1,8 +1,7 @@
-use gpui::img;
-
 use crate::prelude::*;
+use gpui::img;
 
-#[derive(Component)]
+#[derive(Element)]
 pub struct Avatar {
     src: SharedString,
     shape: Shape,

crates/ui2/src/components/toast.rs 🔗

@@ -1,4 +1,5 @@
 use crate::prelude::*;
+use gpui::Element;
 use gpui::{prelude::*, AnyElement};
 use smallvec::SmallVec;
 
@@ -21,40 +22,41 @@ pub enum ToastOrigin {
 /// they are actively showing the a process in progress.
 ///
 /// Only one toast may be visible at a time.
+#[derive(Element)]
 pub struct Toast<V: 'static> {
     origin: ToastOrigin,
     children: SmallVec<[AnyElement<V>; 2]>,
 }
 
-impl<V: 'static> Element<V> for Toast<V> {
-    type State = Option<AnyElement<V>>;
-
-    fn element_id(&self) -> Option<ElementId> {
-        None
-    }
-
-    fn layout(
-        &mut self,
-        view_state: &mut V,
-        _element_state: Option<Self::State>,
-        cx: &mut ViewContext<V>,
-    ) -> (gpui::LayoutId, Self::State) {
-        let mut element = self.render(view_state, cx).into_any();
-        let layout_id = element.layout(view_state, cx);
-        (layout_id, Some(element))
-    }
-
-    fn paint(
-        self,
-        bounds: gpui::Bounds<gpui::Pixels>,
-        view_state: &mut V,
-        element: &mut Self::State,
-        cx: &mut ViewContext<V>,
-    ) {
-        let element = element.take().unwrap();
-        element.paint(view_state, cx);
-    }
-}
+// impl<V: 'static> Element<V> for Toast<V> {
+//     type State = Option<AnyElement<V>>;
+
+//     fn element_id(&self) -> Option<ElementId> {
+//         None
+//     }
+
+//     fn layout(
+//         &mut self,
+//         view_state: &mut V,
+//         _element_state: Option<Self::State>,
+//         cx: &mut ViewContext<V>,
+//     ) -> (gpui::LayoutId, Self::State) {
+//         let mut element = self.render(view_state, cx).into_any();
+//         let layout_id = element.layout(view_state, cx);
+//         (layout_id, Some(element))
+//     }
+
+//     fn paint(
+//         self,
+//         bounds: gpui::Bounds<gpui::Pixels>,
+//         view_state: &mut V,
+//         element: &mut Self::State,
+//         cx: &mut ViewContext<V>,
+//     ) {
+//         let element = element.take().unwrap();
+//         element.paint(view_state, cx);
+//     }
+// }
 
 impl<V: 'static> Toast<V> {
     pub fn new(origin: ToastOrigin) -> Self {