feat(ahk): add cmd to generate helper lib

Woke up today and thought this would be a cool way to learn more about
deriving functionality with proc macros.

Hopefully having this wrapper/helper library will make first time
configuration for new users easier.
This commit is contained in:
LGUG2Z
2021-08-22 18:52:06 -07:00
parent c42739591f
commit 2c876701d8
9 changed files with 415 additions and 38 deletions

100
derive-ahk/src/lib.rs Normal file
View File

@@ -0,0 +1,100 @@
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
#![allow(clippy::missing_errors_doc)]
use std::stringify;
use quote::quote;
use syn::parse_macro_input;
use syn::Data;
use syn::DataEnum;
use syn::DeriveInput;
use syn::Fields;
use syn::FieldsNamed;
use syn::FieldsUnnamed;
#[proc_macro_derive(Ahk)]
pub fn ahk(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
match input.data {
Data::Struct(s) => match s.fields {
Fields::Named(FieldsNamed { named, .. }) => {
let idents = named.iter().map(|f| &f.ident);
let arguments = format!("{}", quote! {#(#idents), *});
let idents = named.iter().map(|f| &f.ident);
let called_arguments = format!("{}", quote! {#(%#idents%) *})
.replace(" %", "%")
.replace("% ", "%")
.replace("%%", "% %");
quote! {
impl #name {
fn ahk_function() -> String {
format!(r#"
{}({}) {{
Run, komorebic.exe {} {}, , Hide
}}"#,
stringify!(#name),
#arguments,
stringify!(#name).to_kebab_case(),
#called_arguments
)
}
}
}
}
_ => unreachable!("only to be used on structs with named fields"),
},
Data::Enum(DataEnum { variants, .. }) => {
let enums = variants.iter().filter(|&v| {
matches!(v.fields, Fields::Unit) || matches!(v.fields, Fields::Unnamed(..))
});
let mut stream = proc_macro2::TokenStream::new();
for variant in enums.clone() {
match &variant.fields {
Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
for field in unnamed {
stream.extend(quote! {
v.push(#field::ahk_function());
});
}
}
Fields::Unit => {
let name = &variant.ident;
stream.extend(quote! {
v.push(format!(r#"
{}() {{
Run, komorebic.exe {}, , Hide
}}"#,
stringify!(#name),
stringify!(#name).to_kebab_case()
));
});
}
Fields::Named(_) => {
unreachable!("only to be used with unnamed and unit fields");
}
}
}
quote! {
impl #name {
fn ahk_functions() -> Vec<String> {
let mut v: Vec<String> = vec![];
v.push(String::from("; Generated by komorebic.exe ahk-lib"));
#stream
v
}
}
}
}
Data::Union(_) => unreachable!("only to be used on enums and structs"),
}
.into()
}