1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput, GenericParam};
4
5pub fn derive_element(input: TokenStream) -> TokenStream {
6 let ast = parse_macro_input!(input as DeriveInput);
7 let type_name = ast.ident;
8
9 let mut state_type = quote! { () };
10
11 for param in &ast.generics.params {
12 if let GenericParam::Type(type_param) = param {
13 let type_ident = &type_param.ident;
14 state_type = quote! {#type_ident};
15 break;
16 }
17 }
18
19 let attrs = &ast.attrs;
20 for attr in attrs {
21 if attr.path.is_ident("element") {
22 match attr.parse_meta() {
23 Ok(syn::Meta::List(i)) => {
24 for nested_meta in i.nested {
25 if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = nested_meta {
26 if nv.path.is_ident("view_state") {
27 if let syn::Lit::Str(lit_str) = nv.lit {
28 state_type = lit_str.value().parse().unwrap();
29 }
30 }
31 }
32 }
33 }
34 _ => (),
35 }
36 }
37 }
38
39 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
40
41 let gen = quote! {
42 impl #impl_generics gpui2::IntoAnyElement<#state_type> for #type_name #ty_generics
43 #where_clause
44 {
45 fn into_any(self) -> gpui2::AnyElement<#state_type> {
46 gpui2::AnyElement::new(self)
47 }
48 }
49
50 impl #impl_generics gpui2::Element for #type_name #ty_generics
51 #where_clause
52 {
53 type ViewState = #state_type;
54 type ElementState = gpui2::AnyElement<#state_type>;
55
56 fn id(&self) -> Option<gpui2::ElementId> {
57 None
58 }
59
60 fn initialize(
61 &mut self,
62 view_state: &mut Self::ViewState,
63 _: Option<Self::ElementState>,
64 cx: &mut gpui2::ViewContext<Self::ViewState>
65 ) -> Self::ElementState {
66 use gpui2::IntoAnyElement;
67
68 let mut element = self.render(view_state, cx).into_any();
69 element.initialize(view_state, cx);
70 element
71 }
72
73 fn layout(
74 &mut self,
75 view_state: &mut Self::ViewState,
76 rendered_element: &mut Self::ElementState,
77 cx: &mut gpui2::ViewContext<Self::ViewState>,
78 ) -> gpui2::LayoutId {
79 rendered_element.layout(view_state, cx)
80 }
81
82 fn paint(
83 &mut self,
84 bounds: gpui2::Bounds<gpui2::Pixels>,
85 view_state: &mut Self::ViewState,
86 rendered_element: &mut Self::ElementState,
87 cx: &mut gpui2::ViewContext<Self::ViewState>,
88 ) {
89 rendered_element.paint(view_state, cx)
90 }
91 }
92 };
93
94 gen.into()
95}