oxi_module/
lib.rs

1use proc_macro::TokenStream;
2use proc_macro2::{Ident, Span};
3use quote::quote;
4use syn::{parse_macro_input, Error};
5
6// *Heavily* inspired by mlua's `lua_module` proc macro.
7//
8/// Marks the plugin entrypoint.
9///
10/// # Examples
11///
12/// ```ignore
13/// use nvim_oxi as nvim;
14///
15/// #[nvim::module]
16/// fn foo() -> nvim::Result<()> {
17///     Ok(())
18/// }
19/// ```
20#[proc_macro_attribute]
21pub fn oxi_module(attr: TokenStream, item: TokenStream) -> TokenStream {
22    let args = parse_macro_input!(attr as syn::AttributeArgs);
23
24    if !args.is_empty() {
25        return Error::new(Span::call_site(), "no attributes are supported")
26            .to_compile_error()
27            .into();
28    }
29
30    let item = parse_macro_input!(item as syn::ItemFn);
31
32    let module_name = item.sig.ident.clone();
33
34    let lua_module =
35        Ident::new(&format!("luaopen_{module_name}"), Span::call_site());
36
37    let module_body = quote! {
38        #item
39
40        #[no_mangle]
41        unsafe extern "C" fn #lua_module(
42            state: *mut ::nvim_oxi::lua::ffi::lua_State,
43        ) -> ::std::ffi::c_int {
44            ::nvim_oxi::entrypoint(state, #module_name)
45        }
46    };
47
48    module_body.into()
49}