diff --git a/Cargo.lock b/Cargo.lock index 641899f..286c929 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,6 +101,15 @@ version = "0.1.0" dependencies = [ "abi_stable", "anyrun-interface", + "anyrun-plugin-macros", +] + +[[package]] +name = "anyrun-plugin-macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn 2.0.15", ] [[package]] @@ -135,7 +144,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -978,7 +987,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2de65550b4ec230167654f367b6ec02795acf2cfd9692f05bedb10ff09e46a6e" dependencies = [ "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -1740,7 +1749,7 @@ checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -1762,7 +1771,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -1900,9 +1909,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 67b2293..ea9d9eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "anyrun", "anyrun-plugin", + "anyrun-plugin-macros", "anyrun-interface", "plugins/applications", "plugins/symbols", diff --git a/anyrun-plugin-macros/Cargo.toml b/anyrun-plugin-macros/Cargo.toml new file mode 100644 index 0000000..e5706b1 --- /dev/null +++ b/anyrun-plugin-macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "anyrun-plugin-macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +quote = "1.0.26" +syn = { version = "2.0.15", features = ["full"] } diff --git a/anyrun-plugin-macros/src/lib.rs b/anyrun-plugin-macros/src/lib.rs new file mode 100644 index 0000000..49e8793 --- /dev/null +++ b/anyrun-plugin-macros/src/lib.rs @@ -0,0 +1,209 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, ReturnType, Type}; + +/// The function to handle the selection of an item. Takes a `Match` as its first argument, and the second argument can be one of: +/// - &T +/// - &mut T +/// - +/// where T is the type returned by `init`. +/// +/// Should return a `HandleResult` with the appropriate action. +#[proc_macro_attribute] +pub fn handler(_attr: TokenStream, item: TokenStream) -> TokenStream { + let function = parse_macro_input!(item as syn::ItemFn); + let fn_name = &function.sig.ident; + + let data = if function.sig.inputs.len() == 2 { + if match function.sig.inputs.last() { + Some(syn::FnArg::Typed(pat)) => match &*pat.ty { + Type::Reference(reference) => { + reference.mutability.is_some() + } + _ => return quote! { compile_error!("Last argument must be either a reference to the shared data or should not be present at all.") }.into(), + }, + Some(_) => return quote! { compile_error!("`self` argument, really?") }.into(), + None => unreachable!(), + } { + quote! { + ANYRUN_INTERNAL_DATA.write().unwrap().as_mut().unwrap(), + } + } else { + quote! { + ANYRUN_INTERNAL_DATA.read().unwrap().as_ref().unwrap(), + } + } + } else { + quote! {} + }; + + quote! { + #[::abi_stable::sabi_extern_fn] + fn anyrun_internal_handle_selection( + selection: ::anyrun_plugin::anyrun_interface::Match, + ) -> ::anyrun_plugin::anyrun_interface::HandleResult { + #function + + #fn_name( + selection, + #data + ) + } + } + .into() +} + +/// Function that takes the current text input as an `RString` as the first argument, and the second argument can be one of: +/// - &T +/// - &mut T +/// - +/// where T is the type returned by `init`. +/// +/// It should return an `RVec` of `Match`es. +#[proc_macro_attribute] +pub fn get_matches(_attr: TokenStream, item: TokenStream) -> TokenStream { + let function = parse_macro_input!(item as syn::ItemFn); + let fn_name = &function.sig.ident; + + let fn_call = if function.sig.inputs.len() == 2 { + let data = if match function.sig.inputs.last() { + Some(syn::FnArg::Typed(pat)) => match &*pat.ty { + Type::Reference(reference) => { + reference.mutability.is_some() + } + _ => return quote! { compile_error!("Last argument must be either a reference to the shared data or should not be present at all.") }.into(), + }, + Some(_) => return quote! { compile_error!("`self` argument, really?") }.into(), + None => unreachable!(), + } { + quote! { + ANYRUN_INTERNAL_DATA.write().unwrap().as_mut() + } + } else { + quote! { + ANYRUN_INTERNAL_DATA.read().unwrap().as_ref() + } + }; + quote! { + if let Some(data) = #data { + #fn_name(input, data) + } else { + ::abi_stable::std_types::RVec::new() + } + } + } else { + quote! { + #fn_name(input) + } + }; + + quote! { + #[::abi_stable::sabi_extern_fn] + fn anyrun_internal_get_matches(input: ::abi_stable::std_types::RString) -> u64 { + #function + + let current_id = + ANYRUN_INTERNAL_ID_COUNTER.load(::std::sync::atomic::Ordering::Relaxed); + ANYRUN_INTERNAL_ID_COUNTER + .store(current_id + 1, ::std::sync::atomic::Ordering::Relaxed); + + let handle = ::std::thread::spawn(move || { + #fn_call + }); + + *ANYRUN_INTERNAL_THREAD.lock().unwrap() = Some((handle, current_id)); + + current_id + } + } + .into() +} + +/// Function that returns the plugin info as a `PluginInfo` object. Takes no arguments. +#[proc_macro_attribute] +pub fn info(_attr: TokenStream, item: TokenStream) -> TokenStream { + let function = parse_macro_input!(item as syn::ItemFn); + let fn_name = &function.sig.ident; + + quote! { + #[::abi_stable::sabi_extern_fn] + fn anyrun_internal_info() -> ::anyrun_plugin::anyrun_interface::PluginInfo { + #function + + #fn_name() + } + } + .into() +} + +/// Function that takes an `RString` as the only argument, which points to the anyrun config directory. Returns the data +/// the plugin operates on. This data is accessible as both a normal borrow and a mutable borrow to `get_matches` and `handler`. +#[proc_macro_attribute] +pub fn init(_attr: TokenStream, item: TokenStream) -> TokenStream { + let function = parse_macro_input!(item as syn::ItemFn); + let fn_name = &function.sig.ident; + let data_type = match &function.sig.output { + ReturnType::Default => quote! {()}, + ReturnType::Type(_, data_type) => quote! {#data_type}, + }; + + quote! { + static ANYRUN_INTERNAL_THREAD: ::std::sync::Mutex< + Option<( + ::std::thread::JoinHandle< + ::abi_stable::std_types::RVec<::anyrun_plugin::anyrun_interface::Match>, + >, + u64, + )>, + > = ::std::sync::Mutex::new(None); + static ANYRUN_INTERNAL_ID_COUNTER: ::std::sync::atomic::AtomicU64 = + ::std::sync::atomic::AtomicU64::new(0); + static ANYRUN_INTERNAL_DATA: ::std::sync::RwLock> = + ::std::sync::RwLock::new(None); + + #[::abi_stable::export_root_module] + fn anyrun_internal_init_root_module() -> ::anyrun_plugin::anyrun_interface::PluginRef { + use ::abi_stable::prefix_type::PrefixTypeTrait; + ::anyrun_plugin::anyrun_interface::Plugin { + init: anyrun_internal_init, + info: anyrun_internal_info, + get_matches: anyrun_internal_get_matches, + poll_matches: anyrun_internal_poll_matches, + handle_selection: anyrun_internal_handle_selection, + } + .leak_into_prefix() + } + + #[::abi_stable::sabi_extern_fn] + fn anyrun_internal_poll_matches(id: u64) -> ::anyrun_plugin::anyrun_interface::PollResult { + match ANYRUN_INTERNAL_THREAD.try_lock() { + Ok(thread) => match thread.as_ref() { + Some((thread, task_id)) => { + if *task_id == id { + if !thread.is_finished() { + return ::anyrun_plugin::anyrun_interface::PollResult::Pending; + } + } else { + return ::anyrun_plugin::anyrun_interface::PollResult::Cancelled; + } + } + None => return ::anyrun_plugin::anyrun_interface::PollResult::Cancelled, + }, + Err(_) => return ::anyrun_plugin::anyrun_interface::PollResult::Pending, + } + + let (thread, _) = ANYRUN_INTERNAL_THREAD.lock().unwrap().take().unwrap(); + ::anyrun_plugin::anyrun_interface::PollResult::Ready(thread.join().unwrap()) + } + + #[::abi_stable::sabi_extern_fn] + fn anyrun_internal_init(config_dir: ::abi_stable::std_types::RString) { + #function + + ::std::thread::spawn(|| { + *ANYRUN_INTERNAL_DATA.write().unwrap() = Some(#fn_name(config_dir)); + }); + } + } + .into() +} diff --git a/anyrun-plugin/Cargo.toml b/anyrun-plugin/Cargo.toml index 1bfb1b1..5266059 100644 --- a/anyrun-plugin/Cargo.toml +++ b/anyrun-plugin/Cargo.toml @@ -8,3 +8,4 @@ edition = "2021" [dependencies] abi_stable = "0.11.1" anyrun-interface = { path = "../anyrun-interface" } +anyrun-plugin-macros = { path = "../anyrun-plugin-macros" } diff --git a/anyrun-plugin/src/lib.rs b/anyrun-plugin/src/lib.rs index f121b3c..9b496bf 100644 --- a/anyrun-plugin/src/lib.rs +++ b/anyrun-plugin/src/lib.rs @@ -1,115 +1,19 @@ -pub use anyrun_interface::{self, Match, PluginInfo}; +/*! +The crate for building plugins for Anyrun. -/** +Each plugin needs 4 functions defined, `init`, `info`, `get_matches` and the `handler`. Documentation +on what each of these should be is found in their respective attribute macros. +!*/ + +pub use anyrun_interface::{self, HandleResult, Match, PluginInfo}; +pub use anyrun_plugin_macros::*; + +/* The macro to create a plugin, handles asynchronous execution of getting the matches and the boilerplate for integrating with `stable_abi`. # Arguments -* `$init`: Function that takes an `RString` as the only argument, which points to the anyrun config directory. Returns the data -the plugin operates on. - -* `$info`: Function that returns the plugin info as a `PluginInfo` object. Takes no arguments. - -* `$get_matches`: Function that takes the current text input as an `RString` as the only argument, and returns an `RVec`. -This is run asynchronously automatically. - -* `$handler`: The function to handle the selection of an item. Takes a `Match` as it's only argument and returns a `HandleResult` with -the appropriate action. * `$type`: The type of the shared data to be provided to various functions. -**/ -#[macro_export] -macro_rules! plugin { - ($init:ident, $info:ident, $get_matches:ident, $handler:ident, $type:ty) => { - static ANYRUN_INTERNAL_THREAD: ::std::sync::Mutex< - Option<( - ::std::thread::JoinHandle< - ::abi_stable::std_types::RVec<::anyrun_plugin::anyrun_interface::Match>, - >, - u64, - )>, - > = ::std::sync::Mutex::new(None); - static ANYRUN_INTERNAL_ID_COUNTER: ::std::sync::atomic::AtomicU64 = - ::std::sync::atomic::AtomicU64::new(0); - static ANYRUN_INTERNAL_DATA: ::std::sync::RwLock> = - ::std::sync::RwLock::new(None); - - #[::abi_stable::export_root_module] - fn anyrun_internal_init_root_module() -> ::anyrun_plugin::anyrun_interface::PluginRef { - use ::abi_stable::prefix_type::PrefixTypeTrait; - ::anyrun_plugin::anyrun_interface::Plugin { - init: anyrun_internal_init, - info: anyrun_internal_info, - get_matches: anyrun_internal_get_matches, - poll_matches: anyrun_internal_poll_matches, - handle_selection: anyrun_internal_handle_selection, - } - .leak_into_prefix() - } - - #[::abi_stable::sabi_extern_fn] - fn anyrun_internal_init(config_dir: ::abi_stable::std_types::RString) { - ::std::thread::spawn(|| { - *ANYRUN_INTERNAL_DATA.write().unwrap() = Some($init(config_dir)); - }); - } - - #[::abi_stable::sabi_extern_fn] - fn anyrun_internal_info() -> ::anyrun_plugin::anyrun_interface::PluginInfo { - $info() - } - - #[::abi_stable::sabi_extern_fn] - fn anyrun_internal_get_matches(input: ::abi_stable::std_types::RString) -> u64 { - let current_id = - ANYRUN_INTERNAL_ID_COUNTER.load(::std::sync::atomic::Ordering::Relaxed); - ANYRUN_INTERNAL_ID_COUNTER - .store(current_id + 1, ::std::sync::atomic::Ordering::Relaxed); - - let handle = ::std::thread::spawn(move || { - if let Some(data) = ANYRUN_INTERNAL_DATA.read().unwrap().as_ref() { - $get_matches(input, data) - } else { - ::abi_stable::std_types::RVec::new() - } - }); - - *ANYRUN_INTERNAL_THREAD.lock().unwrap() = Some((handle, current_id)); - - current_id - } - - #[::abi_stable::sabi_extern_fn] - fn anyrun_internal_poll_matches(id: u64) -> ::anyrun_plugin::anyrun_interface::PollResult { - match ANYRUN_INTERNAL_THREAD.try_lock() { - Ok(thread) => match thread.as_ref() { - Some((thread, task_id)) => { - if *task_id == id { - if !thread.is_finished() { - return ::anyrun_plugin::anyrun_interface::PollResult::Pending; - } - } else { - return ::anyrun_plugin::anyrun_interface::PollResult::Cancelled; - } - } - None => return ::anyrun_plugin::anyrun_interface::PollResult::Cancelled, - }, - Err(_) => return ::anyrun_plugin::anyrun_interface::PollResult::Pending, - } - - let (thread, _) = ANYRUN_INTERNAL_THREAD.lock().unwrap().take().unwrap(); - ::anyrun_plugin::anyrun_interface::PollResult::Ready(thread.join().unwrap()) - } - - #[::abi_stable::sabi_extern_fn] - fn anyrun_internal_handle_selection( - selection: ::anyrun_plugin::anyrun_interface::Match, - ) -> ::anyrun_plugin::anyrun_interface::HandleResult { - $handler( - selection, - ANYRUN_INTERNAL_DATA.write().unwrap().as_mut().unwrap(), - ) - } - }; -} +*/ diff --git a/plugins/applications/src/lib.rs b/plugins/applications/src/lib.rs index 45a3f4f..58b125e 100644 --- a/plugins/applications/src/lib.rs +++ b/plugins/applications/src/lib.rs @@ -12,7 +12,8 @@ pub struct Config { mod scrubber; -pub fn handler(selection: Match, entries: &mut Vec<(DesktopEntry, u64)>) -> HandleResult { +#[handler] +pub fn handler(selection: Match, entries: &Vec<(DesktopEntry, u64)>) -> HandleResult { let entry = entries .iter() .find_map(|(entry, id)| { @@ -31,6 +32,7 @@ pub fn handler(selection: Match, entries: &mut Vec<(DesktopEntry, u64)>) -> Hand HandleResult::Close } +#[init] pub fn init(config_dir: RString) -> Vec<(DesktopEntry, u64)> { let config: Config = match fs::read_to_string(format!("{}/applications.ron", config_dir)) { Ok(content) => ron::from_str(&content).unwrap_or_else(|why| { @@ -49,6 +51,7 @@ pub fn init(config_dir: RString) -> Vec<(DesktopEntry, u64)> { }) } +#[get_matches] pub fn get_matches(input: RString, entries: &Vec<(DesktopEntry, u64)>) -> RVec { let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case(); let mut entries = entries @@ -81,11 +84,10 @@ pub fn get_matches(input: RString, entries: &Vec<(DesktopEntry, u64)>) -> RVec PluginInfo { PluginInfo { name: "Applications".into(), icon: "application-x-executable".into(), } } - -plugin!(init, info, get_matches, handler, Vec<(DesktopEntry, u64)>); diff --git a/plugins/dictionary/src/lib.rs b/plugins/dictionary/src/lib.rs index 4d3058f..01e4cca 100644 --- a/plugins/dictionary/src/lib.rs +++ b/plugins/dictionary/src/lib.rs @@ -1,7 +1,8 @@ use abi_stable::std_types::{ROption, RString, RVec}; -use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo}; +use anyrun_plugin::*; use serde::Deserialize; +#[allow(unused)] #[derive(Deserialize)] struct ApiResponse { word: String, @@ -11,6 +12,7 @@ struct ApiResponse { meanings: Vec, } +#[allow(unused)] #[derive(Deserialize)] struct Phonetic { text: String, @@ -24,6 +26,7 @@ struct Meaning { definitions: Vec, } +#[allow(unused)] #[derive(Deserialize)] struct Definition { definition: String, @@ -32,13 +35,16 @@ struct Definition { antonyms: Vec, } +#[init] pub fn init(_config_dir: RString) {} -pub fn handler(_match: Match, _: &mut ()) -> HandleResult { +#[handler] +pub fn handler(_match: Match) -> HandleResult { HandleResult::Copy(_match.title.into_bytes()) } -pub fn get_matches(input: RString, _: &()) -> RVec { +#[get_matches] +pub fn get_matches(input: RString) -> RVec { if !input.starts_with(":def") { return RVec::new(); } @@ -87,11 +93,10 @@ pub fn get_matches(input: RString, _: &()) -> RVec { .collect() } +#[info] fn info() -> PluginInfo { PluginInfo { name: "Dictionary".into(), icon: "accessories-dictionary".into(), } } - -plugin!(init, info, get_matches, handler, ()); diff --git a/plugins/kidex/src/lib.rs b/plugins/kidex/src/lib.rs index bcbb593..214aaaa 100644 --- a/plugins/kidex/src/lib.rs +++ b/plugins/kidex/src/lib.rs @@ -26,6 +26,7 @@ impl From for IndexAction { } } +#[handler] pub fn handler(selection: Match, state: &mut State) -> HandleResult { match &state.selection { Some(index_entry) => match selection.id.unwrap().into() { @@ -56,6 +57,7 @@ pub fn handler(selection: Match, state: &mut State) -> HandleResult { } } +#[init] pub fn init(_config_dir: RString) -> State { State { index: match kidex_common::util::get_index(None) { @@ -69,6 +71,7 @@ pub fn init(_config_dir: RString) -> State { } } +#[get_matches] pub fn get_matches(input: RString, state: &State) -> RVec { match &state.selection { Some(index_entry) => { @@ -140,11 +143,10 @@ pub fn get_matches(input: RString, state: &State) -> RVec { } } +#[info] pub fn info() -> PluginInfo { PluginInfo { name: "Kidex".into(), icon: "folder".into(), } } - -plugin!(init, info, get_matches, handler, State); diff --git a/plugins/randr/src/lib.rs b/plugins/randr/src/lib.rs index 046a7ef..b7431dc 100644 --- a/plugins/randr/src/lib.rs +++ b/plugins/randr/src/lib.rs @@ -1,7 +1,7 @@ use std::{env, fs}; use abi_stable::std_types::{ROption, RString, RVec}; -use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo}; +use anyrun_plugin::*; use fuzzy_matcher::FuzzyMatcher; use randr::{dummy::Dummy, hyprland::Hyprland, Configure, Monitor, Randr}; use serde::Deserialize; @@ -32,6 +32,7 @@ pub struct State { inner: InnerState, } +#[init] pub fn init(config_dir: RString) -> State { // Determine which Randr implementation should be used let randr: Box = if env::var("HYPRLAND_INSTANCE_SIGNATURE").is_ok() { @@ -53,6 +54,7 @@ pub fn init(config_dir: RString) -> State { } } +#[info] pub fn info() -> PluginInfo { PluginInfo { name: "Randr".into(), @@ -60,6 +62,7 @@ pub fn info() -> PluginInfo { } } +#[handler] pub fn handler(_match: Match, state: &mut State) -> HandleResult { match &state.inner { InnerState::None => { @@ -98,6 +101,7 @@ pub fn handler(_match: Match, state: &mut State) -> HandleResult { } } +#[get_matches] pub fn get_matches(input: RString, state: &State) -> RVec { if !input.starts_with(&state.config.prefix) { return RVec::new(); @@ -187,5 +191,3 @@ pub fn get_matches(input: RString, state: &State) -> RVec { vec.into_iter().map(|(_match, _)| _match).collect() } - -plugin!(init, info, get_matches, handler, State); diff --git a/plugins/rink/src/lib.rs b/plugins/rink/src/lib.rs index 9cfde1c..4386fde 100644 --- a/plugins/rink/src/lib.rs +++ b/plugins/rink/src/lib.rs @@ -1,15 +1,10 @@ use abi_stable::std_types::{ROption, RString, RVec}; -use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo}; +use anyrun_plugin::*; +use rink_core::{ast, date, gnu_units, CURRENCY_FILE}; -fn init(_config_dir: RString) { - // Currently broken due to limitations with the declarative macro anyrun_plugin crate. - // For any plugin that does something relatively time intensive like fetching something - // from the internet, the internal Mutex would block making requests way too long when typed rapidly. - - // TODO: Redesign the anyrun_plugin crate to allow for both mutable and non mutable borrows of the - // shared data for functions - - /*let mut ctx = rink_core::Context::new(); +#[init] +fn init(_config_dir: RString) -> rink_core::Context { + let mut ctx = rink_core::Context::new(); let units = gnu_units::parse_str(rink_core::DEFAULT_FILE.unwrap()); let dates = date::parse_datefile(rink_core::DATES_FILE); @@ -34,9 +29,10 @@ fn init(_config_dir: RString) { }); ctx.load_dates(dates); - ctx*/ + ctx } +#[info] fn info() -> PluginInfo { PluginInfo { name: "Rink".into(), @@ -44,11 +40,9 @@ fn info() -> PluginInfo { } } -fn get_matches(input: RString, _: &()) -> RVec { - match rink_core::one_line( - &mut rink_core::simple_context().expect("Failed to create rink context"), - &input, - ) { +#[get_matches] +fn get_matches(input: RString, ctx: &mut rink_core::Context) -> RVec { + match rink_core::one_line(ctx, &input) { Ok(result) => vec![Match { title: result.into(), description: ROption::RNone, @@ -61,8 +55,7 @@ fn get_matches(input: RString, _: &()) -> RVec { } } -fn handler(selection: Match, _: &mut ()) -> HandleResult { +#[handler] +fn handler(selection: Match) -> HandleResult { HandleResult::Copy(selection.title.into_bytes()) } - -plugin!(init, info, get_matches, handler, ()); diff --git a/plugins/shell/src/lib.rs b/plugins/shell/src/lib.rs index 6c63cd1..35abf0f 100644 --- a/plugins/shell/src/lib.rs +++ b/plugins/shell/src/lib.rs @@ -1,7 +1,7 @@ use std::{env, fs, process::Command}; use abi_stable::std_types::{ROption, RString, RVec}; -use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo}; +use anyrun_plugin::*; use serde::Deserialize; #[derive(Deserialize)] @@ -19,6 +19,7 @@ impl Default for Config { } } +#[init] fn init(config_dir: RString) -> Config { match fs::read_to_string(format!("{}/shell.ron", config_dir)) { Ok(content) => ron::from_str(&content).unwrap_or_default(), @@ -26,6 +27,7 @@ fn init(config_dir: RString) -> Config { } } +#[info] fn info() -> PluginInfo { PluginInfo { name: "Shell".into(), @@ -33,6 +35,7 @@ fn info() -> PluginInfo { } } +#[get_matches] fn get_matches(input: RString, config: &Config) -> RVec { if input.starts_with(&config.prefix) { let (_, command) = input.split_once(&config.prefix).unwrap(); @@ -63,7 +66,8 @@ fn get_matches(input: RString, config: &Config) -> RVec { } } -fn handler(selection: Match, _config: &mut Config) -> HandleResult { +#[handler] +fn handler(selection: Match) -> HandleResult { if let Err(why) = Command::new(selection.description.unwrap().as_str()) .arg("-c") .arg(selection.title.as_str()) @@ -74,5 +78,3 @@ fn handler(selection: Match, _config: &mut Config) -> HandleResult { HandleResult::Close } - -plugin!(init, info, get_matches, handler, Config); diff --git a/plugins/stdin/src/lib.rs b/plugins/stdin/src/lib.rs index 53229c8..ead5c3d 100644 --- a/plugins/stdin/src/lib.rs +++ b/plugins/stdin/src/lib.rs @@ -1,17 +1,20 @@ use std::io::stdin; use abi_stable::std_types::{ROption, RString, RVec}; -use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo}; +use anyrun_plugin::*; use fuzzy_matcher::FuzzyMatcher; +#[init] fn init(_config_dir: RString) -> Vec { stdin().lines().filter_map(|line| line.ok()).collect() } -fn handler(_match: Match, _lines: &mut Vec) -> HandleResult { +#[handler] +fn handler(_match: Match) -> HandleResult { HandleResult::Stdout(_match.title.into_bytes()) } +#[get_matches] fn get_matches(input: RString, lines: &Vec) -> RVec { let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case(); @@ -42,11 +45,10 @@ fn get_matches(input: RString, lines: &Vec) -> RVec { .into() } +#[info] fn plugin_info() -> PluginInfo { PluginInfo { name: "Stdin".into(), icon: "format-indent-more".into(), } } - -plugin!(init, plugin_info, get_matches, handler, Vec); diff --git a/plugins/symbols/src/lib.rs b/plugins/symbols/src/lib.rs index 7052668..70f1d01 100644 --- a/plugins/symbols/src/lib.rs +++ b/plugins/symbols/src/lib.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, fs}; use abi_stable::std_types::{ROption, RString, RVec}; -use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo}; +use anyrun_plugin::*; use fuzzy_matcher::FuzzyMatcher; use serde::Deserialize; @@ -18,6 +18,7 @@ struct Config { symbols: HashMap, } +#[init] fn init(config_dir: RString) -> Vec { // Try to load the config file, if it does not exist only use the static unicode characters if let Ok(content) = fs::read_to_string(format!("{}/symbols.ron", config_dir)) { @@ -46,6 +47,7 @@ fn init(config_dir: RString) -> Vec { .collect() } +#[info] fn info() -> PluginInfo { PluginInfo { name: "Symbols".into(), @@ -53,6 +55,7 @@ fn info() -> PluginInfo { } } +#[get_matches] fn get_matches(input: RString, symbols: &Vec) -> RVec { let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().ignore_case(); let mut symbols = symbols @@ -82,8 +85,7 @@ fn get_matches(input: RString, symbols: &Vec) -> RVec { .collect() } -fn handler(selection: Match, _symbols: &mut Vec) -> HandleResult { +#[handler] +fn handler(selection: Match) -> HandleResult { HandleResult::Copy(selection.title.into_bytes()) } - -plugin!(init, info, get_matches, handler, Vec); diff --git a/plugins/translate/src/lib.rs b/plugins/translate/src/lib.rs index 0d0f8d3..9c36c25 100644 --- a/plugins/translate/src/lib.rs +++ b/plugins/translate/src/lib.rs @@ -1,7 +1,7 @@ use std::fs; use abi_stable::std_types::{ROption, RString, RVec}; -use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo}; +use anyrun_plugin::*; use fuzzy_matcher::FuzzyMatcher; use serde::Deserialize; @@ -23,6 +23,7 @@ struct State { langs: Vec<(&'static str, &'static str)>, } +#[init] fn init(config_dir: RString) -> State { State { config: match fs::read_to_string(format!("{}/translate.ron", config_dir)) { @@ -138,6 +139,7 @@ fn init(config_dir: RString) -> State { } } +#[info] fn info() -> PluginInfo { PluginInfo { name: "Translate".into(), @@ -145,6 +147,7 @@ fn info() -> PluginInfo { } } +#[get_matches] fn get_matches(input: RString, data: &State) -> RVec { if !input.starts_with(&data.config.prefix) { return RVec::new(); @@ -227,8 +230,7 @@ fn get_matches(input: RString, data: &State) -> RVec { }) } -fn handler(selection: Match, _data: &mut State) -> HandleResult { +#[handler] +fn handler(selection: Match) -> HandleResult { HandleResult::Copy(selection.title.into_bytes()) } - -plugin!(init, info, get_matches, handler, State);