Add derive macro now new elements

Nathan Sobo created

Change summary

crates/gpui/playground/src/components.rs               |  67 ++--
crates/gpui/playground/src/playground.rs               |   1 
crates/gpui/playground_macros/src/derive_element.rs    | 150 ++++++++---
crates/gpui/playground_macros/src/playground_macros.rs |   5 
4 files changed, 142 insertions(+), 81 deletions(-)

Detailed changes

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

@@ -1,9 +1,10 @@
 use crate::{
-    element::{AnyElement, Element, ElementMetadata},
+    element::{Element, ElementMetadata},
     frame,
     themes::rose_pine,
 };
 use gpui::ViewContext;
+use playground_macros::Element;
 use std::{borrow::Cow, marker::PhantomData, rc::Rc};
 
 struct ButtonHandlers<V, D> {
@@ -16,6 +17,8 @@ impl<V, D> Default for ButtonHandlers<V, D> {
     }
 }
 
+#[derive(Element)]
+#[element_crate = "crate"]
 pub struct Button<V: 'static, D: 'static> {
     metadata: ElementMetadata<V>,
     handlers: ButtonHandlers<V, D>,
@@ -89,34 +92,34 @@ impl<V: 'static, D: 'static> Button<V, D> {
     }
 }
 
-impl<V: 'static, D> Element<V> for Button<V, D> {
-    type Layout = AnyElement<V>;
-
-    fn style_mut(&mut self) -> &mut crate::style::ElementStyle {
-        &mut self.metadata.style
-    }
-
-    fn handlers_mut(&mut self) -> &mut crate::element::ElementHandlers<V> {
-        &mut self.metadata.handlers
-    }
-
-    fn layout(
-        &mut self,
-        view: &mut V,
-        cx: &mut crate::element::LayoutContext<V>,
-    ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
-        let mut element = self.render(view, cx).into_any();
-        let node_id = element.layout(view, cx)?;
-        Ok((node_id, element))
-    }
-
-    fn paint<'a>(
-        &mut self,
-        layout: crate::element::Layout<'a, Self::Layout>,
-        view: &mut V,
-        cx: &mut crate::element::PaintContext<V>,
-    ) -> anyhow::Result<()> {
-        layout.from_element.paint(view, cx)?;
-        Ok(())
-    }
-}
+// impl<V: 'static, D> Element<V> for Button<V, D> {
+//     type Layout = AnyElement<V>;
+
+//     fn style_mut(&mut self) -> &mut crate::style::ElementStyle {
+//         &mut self.metadata.style
+//     }
+
+//     fn handlers_mut(&mut self) -> &mut crate::element::ElementHandlers<V> {
+//         &mut self.metadata.handlers
+//     }
+
+//     fn layout(
+//         &mut self,
+//         view: &mut V,
+//         cx: &mut crate::element::LayoutContext<V>,
+//     ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
+//         let mut element = self.render(view, cx).into_any();
+//         let node_id = element.layout(view, cx)?;
+//         Ok((node_id, element))
+//     }
+
+//     fn paint<'a>(
+//         &mut self,
+//         layout: crate::element::Layout<'a, Self::Layout>,
+//         view: &mut V,
+//         cx: &mut crate::element::PaintContext<V>,
+//     ) -> anyhow::Result<()> {
+//         layout.from_element.paint(view, cx)?;
+//         Ok(())
+//     }
+// }

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

@@ -42,7 +42,6 @@ fn main() {
 }
 
 fn workspace<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
-    // frame().w_full().h_half().fill(theme.success(0.5))
     frame()
         .h_full()
         .w(percent(50.))

crates/gpui/playground_macros/src/derive_element.rs 🔗

@@ -1,48 +1,102 @@
-// type Result = ();
-// type LayoutContext<> = ();
-
-// trait Element<V: 'static>: 'static + Clone {
-//     type Layout: 'static;
-
-//     fn style_mut(&mut self) -> &mut Style;
-//     fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
-//         -> Result<(NodeId, Self::Layout)>;
-//     fn paint<'a>(
-//         &mut self,
-//         layout: Layout<'a, Self::Layout>,
-//         view: &mut V,
-//         cx: &mut PaintContext<V>,
-//     ) -> Result<()>;
-// }
-
-// struct Button {
-//     style: Style,
-// }
-
-// type Style = ();
-
-// impl Button {
-//     fn render<V>() -> impl Element<V> {
-//         todo!()
-//     }
-// }
-
-// impl<V: 'static> Element<V> for Foo {
-//     type Layout = ();
-
-//     fn style_mut(&mut self) -> &mut Style {
-//         unimplemented!()
-//     }
-
-//     fn layout(
-//         &mut self,
-//         view: &mut V,
-//         cx: &mut LayoutContext<V>,
-//     ) -> Result<(NodeId, Self::Layout)> {
-//         unimplemented!()
-//     }
-
-//     fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
-//         unimplemented!()
-//     }
-// }
+use proc_macro::TokenStream;
+use quote::{format_ident, quote};
+use syn::{
+    parse_macro_input, parse_quote, DeriveInput, GenericParam, Generics, Ident, Lit, Meta,
+    WhereClause,
+};
+
+pub fn derive_element(input: TokenStream) -> TokenStream {
+    let ast = parse_macro_input!(input as DeriveInput);
+    let type_name = ast.ident;
+
+    let crate_name: String = ast
+        .attrs
+        .iter()
+        .find_map(|attr| {
+            if attr.path.is_ident("element_crate") {
+                match attr.parse_meta() {
+                    Ok(Meta::NameValue(nv)) => {
+                        if let Lit::Str(s) = nv.lit {
+                            Some(s.value())
+                        } else {
+                            None
+                        }
+                    }
+                    _ => None,
+                }
+            } else {
+                None
+            }
+        })
+        .unwrap_or_else(|| String::from("playground"));
+
+    let crate_name = format_ident!("{}", crate_name);
+
+    let placeholder_view_generics: Generics = parse_quote! { <V: 'static> };
+    let placeholder_view_type_name: Ident = parse_quote! { V };
+    let view_type_name: Ident;
+    let impl_generics: syn::ImplGenerics<'_>;
+    let type_generics: Option<syn::TypeGenerics<'_>>;
+    let where_clause: Option<&'_ WhereClause>;
+
+    match ast.generics.params.iter().find_map(|param| {
+        if let GenericParam::Type(type_param) = param {
+            Some(type_param.ident.clone())
+        } else {
+            None
+        }
+    }) {
+        Some(type_name) => {
+            view_type_name = type_name;
+            let generics = ast.generics.split_for_impl();
+            impl_generics = generics.0;
+            type_generics = Some(generics.1);
+            where_clause = generics.2;
+        }
+        _ => {
+            view_type_name = placeholder_view_type_name;
+            let generics = placeholder_view_generics.split_for_impl();
+            impl_generics = generics.0;
+            type_generics = None;
+            where_clause = generics.2;
+        }
+    }
+
+    let gen = quote! {
+        impl #impl_generics #crate_name::element::Element<#view_type_name> for #type_name #type_generics
+        #where_clause
+        {
+            type Layout = #crate_name::element::AnyElement<V>;
+
+            fn style_mut(&mut self) -> &mut #crate_name::style::ElementStyle {
+                &mut self.metadata.style
+            }
+
+            fn handlers_mut(&mut self) -> &mut #crate_name::element::ElementHandlers<V> {
+                &mut self.metadata.handlers
+            }
+
+            fn layout(
+                &mut self,
+                view: &mut V,
+                cx: &mut #crate_name::element::LayoutContext<V>,
+            ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
+                let mut element = self.render(view, cx).into_any();
+                let node_id = element.layout(view, cx)?;
+                Ok((node_id, element))
+            }
+
+            fn paint<'a>(
+                &mut self,
+                layout: #crate_name::element::Layout<'a, Self::Layout>,
+                view: &mut V,
+                cx: &mut #crate_name::element::PaintContext<V>,
+            ) -> anyhow::Result<()> {
+                layout.from_element.paint(view, cx)?;
+                Ok(())
+            }
+        }
+    };
+
+    gen.into()
+}

crates/gpui/playground_macros/src/playground_macros.rs 🔗

@@ -7,3 +7,8 @@ mod tailwind_lengths;
 pub fn tailwind_lengths(attr: TokenStream, item: TokenStream) -> TokenStream {
     tailwind_lengths::tailwind_lengths(attr, item)
 }
+
+#[proc_macro_derive(Element, attributes(element_crate))]
+pub fn derive_element(input: TokenStream) -> TokenStream {
+    derive_element::derive_element(input)
+}