diff --git a/Cargo.lock b/Cargo.lock index e25d153..4127545 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,6 +129,7 @@ version = "0.1.0" dependencies = [ "abi_stable", "anyrun-interface", + "anyrun-macros", "clap", "gtk", "gtk-layer-shell", @@ -145,21 +146,21 @@ dependencies = [ "abi_stable", ] +[[package]] +name = "anyrun-macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn 2.0.15", +] + [[package]] name = "anyrun-plugin" 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", + "anyrun-macros", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ea9d9eb..2ac6b5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = [ "anyrun", "anyrun-plugin", - "anyrun-plugin-macros", + "anyrun-macros", "anyrun-interface", "plugins/applications", "plugins/symbols", diff --git a/README.md b/README.md index 358b52e..e13c323 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,10 @@ Anyrun supports [GTK+ CSS](https://docs.gtk.org/gtk3/css-overview.html) styling. The custom arguments for anyrun are as follows: - `--config-dir`, `-c`: Override the configuration directory -- `--override-plugins`, `-o`: Override the plugins to be used, provided in the same way as in the config file. + +The rest of the arguments are automatically generated based on the config, and can be used to override +configuration parameters. For example if you want to temporarily only run the Applications and Symbols plugins on +the top side of the screen, you would run `anyrun --plugins libapplications.so --plugins libsymbols.so --position top`. # Plugin development diff --git a/anyrun-plugin-macros/Cargo.toml b/anyrun-macros/Cargo.toml similarity index 89% rename from anyrun-plugin-macros/Cargo.toml rename to anyrun-macros/Cargo.toml index e5706b1..73ac987 100644 --- a/anyrun-plugin-macros/Cargo.toml +++ b/anyrun-macros/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "anyrun-plugin-macros" +name = "anyrun-macros" version = "0.1.0" edition = "2021" diff --git a/anyrun-plugin-macros/src/lib.rs b/anyrun-macros/src/lib.rs similarity index 86% rename from anyrun-plugin-macros/src/lib.rs rename to anyrun-macros/src/lib.rs index a0ef535..7678375 100644 --- a/anyrun-plugin-macros/src/lib.rs +++ b/anyrun-macros/src/lib.rs @@ -1,6 +1,6 @@ -use proc_macro::TokenStream; +use proc_macro::{Span, TokenStream}; use quote::quote; -use syn::{parse_macro_input, ReturnType, Type}; +use syn::{parse_macro_input, parse_quote, Attribute, Ident, 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 @@ -208,3 +208,45 @@ pub fn init(_attr: TokenStream, item: TokenStream) -> TokenStream { } .into() } + +#[proc_macro_attribute] +pub fn config_args(_attr: TokenStream, item: TokenStream) -> TokenStream { + let item = parse_macro_input!(item as syn::ItemStruct); + let ident = &item.ident; + + let mut opt_item = item.clone(); + + opt_item.attrs = vec![parse_quote!(#[derive(::clap::Args)])]; + opt_item.ident = Ident::new(&format!("{}Args", opt_item.ident), Span::call_site().into()); + + let opt_ident = &opt_item.ident; + + let mut operations = quote!(); + + for field in opt_item.fields.iter_mut() { + let ty = &field.ty; + let ident = &field.ident; + field.ty = Type::Verbatim(quote!(Option<#ty>)); + field.attrs = vec![parse_quote!(#[arg(long)])]; + + operations = quote! { + #operations + if let Some(val) = opt.#ident { + self.#ident = val; + } + } + } + + quote! { + #item + + #opt_item + + impl #ident { + fn merge_opt(&mut self, opt: #opt_ident) { + #operations + } + } + } + .into() +} diff --git a/anyrun-plugin/Cargo.toml b/anyrun-plugin/Cargo.toml index 5266059..aa2866b 100644 --- a/anyrun-plugin/Cargo.toml +++ b/anyrun-plugin/Cargo.toml @@ -8,4 +8,4 @@ edition = "2021" [dependencies] abi_stable = "0.11.1" anyrun-interface = { path = "../anyrun-interface" } -anyrun-plugin-macros = { path = "../anyrun-plugin-macros" } +anyrun-macros = { path = "../anyrun-macros" } diff --git a/anyrun-plugin/src/lib.rs b/anyrun-plugin/src/lib.rs index 9b496bf..c5d7cc8 100644 --- a/anyrun-plugin/src/lib.rs +++ b/anyrun-plugin/src/lib.rs @@ -6,7 +6,7 @@ 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::*; +pub use anyrun_macros::{get_matches, handler, info, init}; /* The macro to create a plugin, handles asynchronous execution of getting the matches and the boilerplate diff --git a/anyrun/Cargo.toml b/anyrun/Cargo.toml index c4918ca..373e380 100644 --- a/anyrun/Cargo.toml +++ b/anyrun/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyrun-macros = { path = "../anyrun-macros" } abi_stable = "0.11.1" gtk = "0.16.2" gtk-layer-shell = { version = "0.5.0", features = ["v0_6"] } diff --git a/anyrun/src/main.rs b/anyrun/src/main.rs index eb0ef41..04f044f 100644 --- a/anyrun/src/main.rs +++ b/anyrun/src/main.rs @@ -11,12 +11,13 @@ use std::{ use abi_stable::std_types::{ROption, RVec}; use anyrun_interface::{HandleResult, Match, PluginInfo, PluginRef, PollResult}; -use clap::Parser; +use clap::{Parser, ValueEnum}; use gtk::{gdk, gdk_pixbuf, gio, glib, prelude::*}; use nix::unistd; use serde::Deserialize; use wl_clipboard_rs::copy; +#[anyrun_macros::config_args] #[derive(Deserialize)] struct Config { width: RelativeNum, @@ -55,7 +56,7 @@ impl Default for Config { } } -#[derive(Deserialize)] +#[derive(Deserialize, Clone, ValueEnum)] enum Layer { Background, Bottom, @@ -64,12 +65,24 @@ enum Layer { } // Could have a better name -#[derive(Deserialize)] +#[derive(Deserialize, Clone)] enum RelativeNum { Absolute(i32), Fraction(f32), } +impl From<&str> for RelativeNum { + fn from(value: &str) -> Self { + let (ty, val) = value.split_once(':').expect("Invalid RelativeNum value"); + + match ty { + "absolute" => Self::Absolute(val.parse().unwrap()), + "fraction" => Self::Fraction(val.parse().unwrap()), + _ => panic!("Invalid type of value"), + } + } +} + /// A "view" of plugin's info and matches #[derive(Clone)] struct PluginView { @@ -83,12 +96,11 @@ struct Args { /// Override the path to the config directory #[arg(short, long)] config_dir: Option<String>, - /// Override plugin selection - #[arg(short, long, value_delimiter = ' ', num_args = 1..)] - override_plugins: Option<Vec<PathBuf>>, + #[command(flatten)] + config: ConfigArgs, } -#[derive(Deserialize)] +#[derive(Deserialize, Clone, ValueEnum)] enum Position { Top, Center, @@ -183,9 +195,7 @@ fn main() { ), }; - if let Some(override_plugins) = args.override_plugins { - config.plugins = override_plugins; - } + config.merge_opt(args.config); let runtime_data: Rc<RefCell<RuntimeData>> = Rc::new(RefCell::new(RuntimeData { exclusive: None,