diff --git a/Cargo.lock b/Cargo.lock index 1e95f34..37a6bb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -913,6 +913,41 @@ dependencies = [ "zbus", ] +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.77", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.77", +] + [[package]] name = "data-url" version = "0.3.1" @@ -1196,6 +1231,12 @@ dependencies = [ "spin", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "font-types" version = "0.6.0" @@ -1787,6 +1828,9 @@ dependencies = [ name = "iced_layershell_macros" version = "0.7.2" dependencies = [ + "darling", + "iced_layershell", + "manyhow", "proc-macro2", "quote", "syn 2.0.77", @@ -1921,6 +1965,12 @@ dependencies = [ "winit", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "image" version = "0.24.9" @@ -2238,6 +2288,30 @@ dependencies = [ "libc", ] +[[package]] +name = "manyhow" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" +dependencies = [ + "darling_core", + "manyhow-macros", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "manyhow-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + [[package]] name = "memchr" version = "2.7.4" @@ -3009,6 +3083,17 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-utils" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -3659,6 +3744,12 @@ dependencies = [ "float-cmp", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "svg_fmt" version = "0.4.3" diff --git a/iced_examples/counter/src/main.rs b/iced_examples/counter/src/main.rs index 1b8985c..99156b5 100644 --- a/iced_examples/counter/src/main.rs +++ b/iced_examples/counter/src/main.rs @@ -38,7 +38,8 @@ enum WindowDirection { Bottom, } -#[to_layer_message(derives = "Debug Clone")] +#[to_layer_message] +#[derive(Debug, Clone)] enum Message { IncrementPressed, DecrementPressed, diff --git a/iced_examples/counter_muti/src/main.rs b/iced_examples/counter_muti/src/main.rs index 7ce2482..969abd5 100644 --- a/iced_examples/counter_muti/src/main.rs +++ b/iced_examples/counter_muti/src/main.rs @@ -44,7 +44,8 @@ enum WindowDirection { Bottom(Id), } -#[to_layer_message(multi, info_name = "WindowInfo", derives = "Debug Clone")] +#[to_layer_message(multi, info_name = "WindowInfo")] +#[derive(Debug, Clone)] enum Message { IncrementPressed, DecrementPressed, diff --git a/iced_layershell/README.md b/iced_layershell/README.md index 577cf41..bbb30fe 100644 --- a/iced_layershell/README.md +++ b/iced_layershell/README.md @@ -58,7 +58,9 @@ enum WindowDirection { // Because new iced delete the custom command, so now we make a macro crate to generate // the Command -#[to_layer_message(derives = "Debug Clone")] +#[to_layer_message] +#[derive(Debug, Clone)] +#[doc = "Some docs"] enum Message { IncrementPressed, DecrementPressed, diff --git a/iced_layershell_macros/Cargo.toml b/iced_layershell_macros/Cargo.toml index 6999e67..15eb68d 100644 --- a/iced_layershell_macros/Cargo.toml +++ b/iced_layershell_macros/Cargo.toml @@ -12,7 +12,17 @@ readme.workspace = true [lib] proc-macro = true +[features] +default = [] +# Only nightly +diagnostics = ["darling/diagnostics"] + [dependencies] +darling = { version = "0.20.10", features = ["suggestions"] } +manyhow = { version = "0.11.4", features = ["darling"] } proc-macro2 = "1.0.86" quote = "1.0.37" -syn = { version = "2.0.77", features = ["full"]} +syn = { version = "2.0.77", features = ["full"] } + +[dev-dependencies] +iced_layershell.workspace = true diff --git a/iced_layershell_macros/src/lib.rs b/iced_layershell_macros/src/lib.rs index c6f1e9f..73f88c5 100644 --- a/iced_layershell_macros/src/lib.rs +++ b/iced_layershell_macros/src/lib.rs @@ -1,53 +1,40 @@ -use proc_macro::TokenStream; -use proc_macro2::{Ident, Span}; -use syn::{parse_macro_input, ItemEnum, LitStr}; +use darling::{ + ast::{Data, NestedMeta}, + util::{Flag, Ignored}, + FromDeriveInput, FromMeta, +}; +use proc_macro2::{Span, TokenStream as TokenStream2}; +use syn::{DeriveInput, Generics, Ident, LitStr, Variant, Visibility}; use quote::quote; +#[manyhow::manyhow] #[proc_macro_attribute] -pub fn to_layer_message(attr: TokenStream, input: TokenStream) -> TokenStream { - let mut is_multi = false; - let mut info_name: Option = None; - let mut derives: Option = None; - let tea_parser = syn::meta::parser(|meta| { - if meta.path.is_ident("multi") { - is_multi = true; - Ok(()) - } else if meta.path.is_ident("info_name") { - info_name = Some(meta.value()?.parse()?); - Ok(()) - } else if meta.path.is_ident("derives") { - derives = Some(meta.value()?.parse()?); - Ok(()) - } else { - Err(meta.error("unsupported tea property")) - } - }); - let input_enum = parse_macro_input!(input as ItemEnum); - parse_macro_input!(attr with tea_parser); - let mut derive_part = vec![]; - if let Some(derives) = derives { - let tmpval = derives.value(); - let val: Vec<&str> = tmpval.split(' ').collect(); - for der in val.iter() { - let iden_tmp = Ident::new(der, Span::call_site()); - derive_part.push(quote! { - #[derive(#iden_tmp)] - }); - } - } - // Extract the enum name - let enum_vis = &input_enum.vis; - let enum_name = &input_enum.ident; - let variants = &input_enum.variants; - let new_varents = if is_multi { - let info_name = info_name.expect("Should set the infoName").value(); - let info = Ident::new(&info_name, Span::call_site()); - - quote! { - #(#derive_part)* - #enum_vis enum #enum_name { - #variants +pub fn to_layer_message(attr: TokenStream2, input: TokenStream2) -> manyhow::Result { + let meta = NestedMeta::parse_meta_list(attr)?; + + let ToLayerMessageAttr { multi, info_name } = ToLayerMessageAttr::from_list(&meta)?; + + let is_multi = multi.is_present(); + + let derive_input = syn::parse2::(input)?; + let attrs = &derive_input.attrs; + let MessageEnum { + vis, + ident, + generics, + data, + } = MessageEnum::from_derive_input(&derive_input)?; + + let (impl_gen, ty_gen, where_gen) = generics.split_for_impl(); + let variants = data.take_enum().unwrap(); + + let (additional_variants, try_into_impl) = match is_multi { + true => { + let info_name = info_name.expect("Should set the info_name").value(); + let info = Ident::new(&info_name, Span::call_site()); + + let additional_variants = quote! { AnchorChange{id: iced::window::Id, anchor: iced_layershell::reexport::Anchor}, LayerChange{id: iced::window::Id, layer:iced_layershell::reexport::Layer}, MarginChange{id: iced::window::Id, margin: (i32, i32, i32, i32)}, @@ -61,52 +48,40 @@ pub fn to_layer_message(attr: TokenStream, input: TokenStream) -> TokenStream { NewMenu { settings: iced_layershell::actions::IcedNewMenuSettings, info: #info }, RemoveWindow(iced::window::Id), ForgetLastOutput, - } - impl TryInto> for #enum_name { - type Error = Self; - - fn try_into(self) -> Result, Self::Error> { - type InnerLayerActionId = iced_layershell::actions::LayershellCustomActionsWithIdAndInfo<#info>; - type InnerLayerAction = iced_layershell::actions::LayershellCustomActionsWithInfo<#info>; - match self { - Self::AnchorChange{id, anchor} => { - Ok(InnerLayerActionId::new(Some(id), InnerLayerAction::AnchorChange(anchor))) - } - Self::LayerChange{id, layer} => { - Ok(InnerLayerActionId::new(Some(id), InnerLayerAction::LayerChange(layer))) - } - Self::MarginChange{id, margin} => { - Ok(InnerLayerActionId::new(Some(id), InnerLayerAction::MarginChange(margin))) - } - Self::SizeChange {id,size} => { - Ok(InnerLayerActionId::new(Some(id), InnerLayerAction::SizeChange(size))) - } - Self::VirtualKeyboardPressed { - time, - key, - } => { - Ok(InnerLayerActionId::new(None, InnerLayerAction::VirtualKeyboardPressed { - time, - key - })) - } - Self::NewLayerShell {settings, info } => { - Ok(InnerLayerActionId::new(None, InnerLayerAction::NewLayerShell((settings, info)))) + }; + + let try_into_impl = quote! { + impl #impl_gen TryInto> for #ident #ty_gen #where_gen { + type Error = Self; + + fn try_into(self) -> Result, Self::Error> { + type InnerLayerActionId = iced_layershell::actions::LayershellCustomActionsWithIdAndInfo<#info>; + type InnerLayerAction = iced_layershell::actions::LayershellCustomActionsWithInfo<#info>; + + match self { + Self::AnchorChange { id, anchor } => Ok(InnerLayerActionId::new(Some(id), InnerLayerAction::AnchorChange(anchor))), + Self::LayerChange { id, layer } => Ok(InnerLayerActionId::new(Some(id), InnerLayerAction::LayerChange(layer))), + Self::MarginChange { id, margin } => Ok(InnerLayerActionId::new(Some(id), InnerLayerAction::MarginChange(margin))), + Self::SizeChange { id, size } => Ok(InnerLayerActionId::new(Some(id), InnerLayerAction::SizeChange(size))), + Self::VirtualKeyboardPressed { time, key } => Ok(InnerLayerActionId::new( + None, + InnerLayerAction::VirtualKeyboardPressed { time, key }) + ), + Self::NewLayerShell {settings, info } => Ok(InnerLayerActionId::new(None, InnerLayerAction::NewLayerShell((settings, info)))), + Self::NewPopUp { settings, info } => Ok(InnerLayerActionId::new(None, InnerLayerAction::NewPopUp((settings, info)))), + Self::NewMenu { settings, info } => Ok(InnerLayerActionId::new(None, InnerLayerAction::NewMenu((settings, info)))), + Self::RemoveWindow(id) => Ok(InnerLayerActionId::new(None, InnerLayerAction::RemoveWindow(id))), + Self::ForgetLastOutput => Ok(InnerLayerActionId::new(None, InnerLayerAction::ForgetLastOutput)), + _ => Err(self) } - Self::NewPopUp { settings, info } => Ok(InnerLayerActionId::new(None, InnerLayerAction::NewPopUp((settings, info)))), - Self::NewMenu { settings, info } => Ok(InnerLayerActionId::new(None, InnerLayerAction::NewMenu((settings, info)))), - Self::RemoveWindow(id) => Ok(InnerLayerActionId::new(None, InnerLayerAction::RemoveWindow(id))), - Self::ForgetLastOutput => Ok(InnerLayerActionId::new(None, InnerLayerAction::ForgetLastOutput)), - _ => Err(self) } } - } + }; + + (additional_variants, try_into_impl) } - } else { - quote! { - #(#derive_part)* - #enum_vis enum #enum_name { - #variants + false => { + let additional_variants = quote! { AnchorChange(iced_layershell::reexport::Anchor), LayerChange(iced_layershell::reexport::Layer), MarginChange((i32, i32, i32, i32)), @@ -115,43 +90,55 @@ pub fn to_layer_message(attr: TokenStream, input: TokenStream) -> TokenStream { time: u32, key: u32, }, - } - - impl TryInto for #enum_name { - type Error = Self; - fn try_into(self) -> Result { - use iced_layershell::actions::LayershellCustomActions; - match self { - Self::AnchorChange(anchor) => { - Ok(LayershellCustomActions::AnchorChange(anchor)) - }, - Self::LayerChange(layer) => { - Ok(LayershellCustomActions::LayerChange(layer)) - } - Self::MarginChange(margin) => { - Ok(LayershellCustomActions::MarginChange(margin)) - } - Self::SizeChange(size) => { + }; + let try_into_impl = quote! { + impl #impl_gen TryInto for #ident #ty_gen #where_gen { + type Error = Self; - Ok(LayershellCustomActions::SizeChange(size)) - } - Self::VirtualKeyboardPressed { - time, - key, - } => { + fn try_into(self) -> Result { + use iced_layershell::actions::LayershellCustomActions; - Ok(LayershellCustomActions::VirtualKeyboardPressed { + match self { + Self::AnchorChange(anchor) => Ok(LayershellCustomActions::AnchorChange(anchor)), + Self::LayerChange(layer) => Ok(LayershellCustomActions::LayerChange(layer)), + Self::MarginChange(margin) => Ok(LayershellCustomActions::MarginChange(margin)), + Self::SizeChange(size) => Ok(LayershellCustomActions::SizeChange(size)), + Self::VirtualKeyboardPressed { time, key } => Ok(LayershellCustomActions::VirtualKeyboardPressed { time, key - }) + }), + _ => Err(self) } - _ => Err(self) } } - // add code here - } + }; + + (additional_variants, try_into_impl) } }; - TokenStream::from(new_varents) + Ok(quote! { + #(#attrs)* + #vis enum #ident #ty_gen #where_gen { + #(#variants,)* + #additional_variants + } + + #try_into_impl + }) +} + +#[derive(FromMeta)] +struct ToLayerMessageAttr { + multi: Flag, + info_name: Option, +} + +#[derive(FromDeriveInput)] +#[darling(supports(enum_any))] +struct MessageEnum { + vis: Visibility, + ident: Ident, + generics: Generics, + data: Data, } diff --git a/iced_layershell_macros/tests/macro_test.rs b/iced_layershell_macros/tests/macro_test.rs new file mode 100644 index 0000000..037be1e --- /dev/null +++ b/iced_layershell_macros/tests/macro_test.rs @@ -0,0 +1,12 @@ +use iced_layershell_macros::to_layer_message; + +#[test] +fn test_macro() { + #[to_layer_message] + #[derive(Debug, Clone)] + enum TestEnum { + TestA, + } + let e = TestEnum::SizeChange((10, 10)); + let _ = e.clone(); +}