bevy_console_derive/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput};
4
5#[proc_macro_derive(ConsoleCommand, attributes(command))]
6pub fn derive_clap_command(input: TokenStream) -> TokenStream {
7 let derive_input = parse_macro_input!(input as DeriveInput);
8
9 let name_string = get_command_name(&derive_input);
10 let name = &derive_input.ident;
11 let generics = derive_input.generics;
12 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
13
14 TokenStream::from(quote! {
15 impl #impl_generics bevy_console::NamedCommand for #name #ty_generics #where_clause {
16 fn name() -> &'static str {
17 #name_string
18 }
19 }
20
21 impl #impl_generics bevy::prelude::Resource for #name #ty_generics #where_clause {};
22 })
23}
24
25fn get_command_name(input: &DeriveInput) -> syn::LitStr {
26 input
27 .attrs
28 .iter()
29 .find_map(|attr| {
30 if attr.path.is_ident("command") {
31 if let Ok(syn::Meta::List(list)) = attr.parse_meta() {
32 return list.nested.iter().find_map(|meta| {
33 if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = meta {
34 Some(nv.lit.clone())
35 } else {
36 None
37 }
38 });
39 }
40 }
41 None
42 })
43 .map(|lit| {
44 if let syn::Lit::Str(str) = lit {
45 str
46 } else {
47 panic!("Expected string literal as command name");
48 }
49 })
50 .unwrap_or_else(|| syn::LitStr::new(&input.ident.to_string(), input.ident.span()))
51}