use proc_macro::TokenStream; use proc_macro2::Ident; use quote::quote; use syn::{parse_macro_input, parse_quote, DeriveInput, GenericParam, Generics}; use crate::derive_into_element::impl_into_element; pub fn derive_element(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let type_name = ast.ident; let placeholder_view_generics: Generics = parse_quote! { }; let (impl_generics, type_generics, where_clause, view_type_name, lifetimes) = if let Some(first_type_param) = ast.generics.params.iter().find_map(|param| { if let GenericParam::Type(type_param) = param { Some(type_param.ident.clone()) } else { None } }) { let mut lifetimes = vec![]; for param in ast.generics.params.iter() { if let GenericParam::Lifetime(lifetime_def) = param { lifetimes.push(lifetime_def.lifetime.clone()); } } let generics = ast.generics.split_for_impl(); ( generics.0, Some(generics.1), generics.2, first_type_param, lifetimes, ) } else { let generics = placeholder_view_generics.split_for_impl(); let placeholder_view_type_name: Ident = parse_quote! { V }; ( generics.0, None, generics.2, placeholder_view_type_name, vec![], ) }; let lifetimes = if !lifetimes.is_empty() { quote! { <#(#lifetimes),*> } } else { quote! {} }; let impl_into_element = impl_into_element( &impl_generics, &view_type_name, &type_name, &type_generics, &where_clause, ); let gen = quote! { impl #impl_generics gpui2::element::Element<#view_type_name> for #type_name #type_generics #where_clause { type PaintState = gpui2::element::AnyElement<#view_type_name #lifetimes>; fn layout( &mut self, view: &mut V, cx: &mut gpui2::ViewContext, ) -> anyhow::Result<(gpui2::element::LayoutId, Self::PaintState)> { let mut rendered_element = self.render(view, cx).into_element().into_any(); let layout_id = rendered_element.layout(view, cx)?; Ok((layout_id, rendered_element)) } fn paint( &mut self, view: &mut V, parent_origin: gpui2::Vector2F, _: &gpui2::element::Layout, rendered_element: &mut Self::PaintState, cx: &mut gpui2::ViewContext, ) { rendered_element.paint(view, parent_origin, cx); } } #impl_into_element }; gen.into() }