yazi_codegen/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{FnArg, ItemFn};
4
5#[proc_macro_attribute]
6pub fn command(_: TokenStream, item: TokenStream) -> TokenStream {
7	let mut f: ItemFn = syn::parse(item).unwrap();
8	let mut ins = f.sig.inputs.clone();
9
10	// Turn `opt: Opt` into `opt: impl Into<Opt>`
11	ins[1] = {
12		let FnArg::Typed(opt) = &f.sig.inputs[1] else {
13			panic!("Cannot find the `opt` argument in the function signature.");
14		};
15
16		let opt_ty = &opt.ty;
17		syn::parse2(quote! { opt: impl Into<#opt_ty> }).unwrap()
18	};
19
20	// Make the original function private and add a public wrapper
21	assert!(matches!(f.vis, syn::Visibility::Public(_)));
22	f.vis = syn::Visibility::Inherited;
23
24	// Add `__` prefix to the original function name
25	let name_ori = f.sig.ident;
26	f.sig.ident = format_ident!("__{}", name_ori);
27	let name_new = &f.sig.ident;
28
29	// Collect the rest of the arguments
30	let rest_args = ins.iter().skip(2).map(|arg| match arg {
31		FnArg::Receiver(_) => unreachable!(),
32		FnArg::Typed(t) => &t.pat,
33	});
34
35	quote! {
36		#[inline]
37		pub fn #name_ori(#ins) { self.#name_new(opt.into(), #(#rest_args),*); }
38		#f
39	}
40	.into()
41}