diff --git a/crates/gpui2/src/action.rs b/crates/gpui2/src/action.rs index 6e0bcedf4d..4d89ba1826 100644 --- a/crates/gpui2/src/action.rs +++ b/crates/gpui2/src/action.rs @@ -137,7 +137,8 @@ pub fn all_action_names() -> MappedRwLockReadGuard<'static, [SharedString]> { }) } -// actions defines structs that can be used as actions. +/// Defines unit structs that can be used as actions. +/// To use more complex data types as actions, annotate your type with the #[action] macro. #[macro_export] macro_rules! actions { () => {}; @@ -148,21 +149,10 @@ macro_rules! actions { pub struct $name; }; - ( $name:ident { $($token:tt)* } ) => { - #[gpui::register_action] - #[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)] - pub struct $name { $($token)* } - }; - ( $name:ident, $($rest:tt)* ) => { actions!($name); actions!($($rest)*); }; - - ( $name:ident { $($token:tt)* }, $($rest:tt)* ) => { - actions!($name { $($token)* }); - actions!($($rest)*); - }; } #[derive(Clone, Debug, Default, Eq, PartialEq)] @@ -408,17 +398,17 @@ mod tests { #[test] fn test_actions_definition() { { - actions!(A, B { field: i32 }, C, D, E, F {}, G); + actions!(A, B, C, D, E, F, G); } { actions!( A, - B { field: i32 }, + B, C, D, E, - F {}, + F, G, // Don't wrap, test the trailing comma ); } diff --git a/crates/gpui2_macros/src/action.rs b/crates/gpui2_macros/src/action.rs index 9a8ec0d8b0..e4f54e58d5 100644 --- a/crates/gpui2_macros/src/action.rs +++ b/crates/gpui2_macros/src/action.rs @@ -1,13 +1,17 @@ // Input: // // #[action] -// struct Foo {} +// struct Foo { +// bar: String, +// } // Output: // // #[gpui::register_action] // #[derive(gpui::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone, std::default::Default, std::fmt::Debug)] -// struct Foo {} +// struct Foo { +// bar: String, +// } use proc_macro::TokenStream; use quote::quote; @@ -16,15 +20,35 @@ use syn::{parse_macro_input, DeriveInput}; pub fn action(_attr: TokenStream, item: TokenStream) -> TokenStream { let input = parse_macro_input!(item as DeriveInput); let name = &input.ident; - let data = &input.data; + let attrs = input + .attrs + .into_iter() + .filter(|attr| !attr.path.is_ident("action")) + .collect::>(); - let data_tokens = quote! { #data }.into(); - - let expanded = quote! { + let attributes = quote! { #[gpui::register_action] #[derive(gpui::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone, std::default::Default, std::fmt::Debug)] - struct #name { #data } + #(#attrs)* }; - TokenStream::from(expanded) + let output = match input.data { + syn::Data::Struct(ref struct_data) => { + let fields = &struct_data.fields; + quote! { + #attributes + struct #name { #fields } + } + } + syn::Data::Enum(ref enum_data) => { + let variants = &enum_data.variants; + quote! { + #attributes + enum #name { #variants } + } + } + _ => panic!("Expected a struct or an enum."), + }; + + TokenStream::from(output) } diff --git a/crates/gpui2_macros/src/gpui2_macros.rs b/crates/gpui2_macros/src/gpui2_macros.rs index d1271ad041..80b67e1a12 100644 --- a/crates/gpui2_macros/src/gpui2_macros.rs +++ b/crates/gpui2_macros/src/gpui2_macros.rs @@ -1,15 +1,21 @@ -use proc_macro::TokenStream; - +mod action; mod derive_component; mod register_action; mod style_helpers; mod test; +use proc_macro::TokenStream; + #[proc_macro] pub fn style_helpers(args: TokenStream) -> TokenStream { style_helpers::style_helpers(args) } +#[proc_macro_attribute] +pub fn action(attr: TokenStream, item: TokenStream) -> TokenStream { + action::action(attr, item) +} + #[proc_macro_attribute] pub fn register_action(attr: TokenStream, item: TokenStream) -> TokenStream { register_action::register_action(attr, item)