feat: allow plugins to have their own config overrides

This commit is contained in:
imgurbot12 2023-08-20 13:59:32 -07:00
parent 19901cbe34
commit 7d1a12c05d
8 changed files with 121 additions and 84 deletions

View file

@ -171,6 +171,9 @@ struct OptionArgs {
/// Override Window Fullscreen Settings /// Override Window Fullscreen Settings
#[arg(short, long)] #[arg(short, long)]
pub fullscreen: Option<bool>, pub fullscreen: Option<bool>,
/// Override Window Tranparent Settings
#[arg(short, long)]
pub transparent: Option<bool>,
/// Override Window Width /// Override Window Width
#[arg(short = 'w', long)] #[arg(short = 'w', long)]
pub window_width: Option<f64>, pub window_width: Option<f64>,
@ -198,6 +201,7 @@ impl Into<Options> for OptionArgs {
title: self.title, title: self.title,
decorate: self.deocorate, decorate: self.deocorate,
fullscreen: self.fullscreen, fullscreen: self.fullscreen,
transparent: self.transparent,
window_width: self.window_width, window_width: self.window_width,
window_height: self.window_height, window_height: self.window_height,
} }

View file

@ -120,6 +120,8 @@ pub struct Options {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub decorate: Option<bool>, pub decorate: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub transparent: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fullscreen: Option<bool>, pub fullscreen: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub window_width: Option<f64>, pub window_width: Option<f64>,

View file

@ -25,6 +25,15 @@ plugins:
drun: drun:
exec: ["~/.config/rmenu/rmenu-desktop"] exec: ["~/.config/rmenu/rmenu-desktop"]
cache: onlogin cache: onlogin
options:
css: ~/Code/rust/rmenu2/themes/fullscreen.css
transparent: true
window_width: 1200
window_height: 800
key_move_prev: ["Arrow-Left"]
key_move_next: ["Arrow-Right"]
key_jump_prev: ["Arrow-Up"]
key_jump_next: ["Arrow-Down"]
network: network:
exec: ["~/.config/rmenu/rmenu-network"] exec: ["~/.config/rmenu/rmenu-network"]
cache: false cache: false

View file

@ -78,7 +78,7 @@ pub fn write_cache(name: &str, cfg: &PluginConfig, entries: &Vec<Entry>) -> Resu
match cfg.cache { match cfg.cache {
CacheSetting::NoCache => {} CacheSetting::NoCache => {}
_ => { _ => {
println!("writing {} entries", entries.len()); log::debug!("{name:?} writing {} entries", entries.len());
let path = cache_file(name); let path = cache_file(name);
let f = fs::File::create(path)?; let f = fs::File::create(path)?;
serde_json::to_writer(f, entries)?; serde_json::to_writer(f, entries)?;

View file

@ -8,7 +8,7 @@ use clap::Parser;
use rmenu_plugin::{Entry, Message}; use rmenu_plugin::{Entry, Message};
use thiserror::Error; use thiserror::Error;
use crate::config::{Config, Keybind}; use crate::config::{cfg_replace, Config, Keybind};
use crate::{DEFAULT_CONFIG, DEFAULT_CSS}; use crate::{DEFAULT_CONFIG, DEFAULT_CSS};
/// Allowed Formats for Entry Ingestion /// Allowed Formats for Entry Ingestion
@ -177,33 +177,6 @@ pub enum RMenuError {
pub type Result<T> = std::result::Result<T, RMenuError>; pub type Result<T> = std::result::Result<T, RMenuError>;
macro_rules! cli_replace {
($key:expr, $repl:expr) => {
if $repl.is_some() {
$key = $repl.clone();
}
};
($key:expr, $repl:expr, true) => {
if let Some(value) = $repl.as_ref() {
$key = value.to_owned();
}
};
}
macro_rules! cli_keybind {
($key:expr, $repl:expr) => {
if let Some(bind_strings) = $repl.as_ref() {
let mut keybinds = vec![];
for bind_str in bind_strings.iter() {
let bind =
Keybind::from_str(bind_str).map_err(|e| RMenuError::InvalidKeybind(e))?;
keybinds.push(bind);
}
$key = keybinds;
}
};
}
impl Args { impl Args {
/// Load Configuration File /// Load Configuration File
pub fn get_config(&self) -> Result<Config> { pub fn get_config(&self) -> Result<Config> {
@ -233,32 +206,32 @@ impl Args {
config.use_icons = self.use_icons.unwrap_or(config.use_icons); config.use_icons = self.use_icons.unwrap_or(config.use_icons);
config.use_comments = self.use_icons.unwrap_or(config.use_comments); config.use_comments = self.use_icons.unwrap_or(config.use_comments);
// override search settings // override search settings
cli_replace!(config.search.restrict, self.search_restrict); cfg_replace!(config.search.restrict, self.search_restrict);
cli_replace!(config.search.min_length, self.search_min_length); cfg_replace!(config.search.min_length, self.search_min_length);
cli_replace!(config.search.max_length, self.search_max_length); cfg_replace!(config.search.max_length, self.search_max_length);
cli_replace!(config.search.use_regex, self.search_regex, true); cfg_replace!(config.search.use_regex, self.search_regex, true);
cli_replace!(config.search.ignore_case, self.ignore_case, true); cfg_replace!(config.search.ignore_case, self.ignore_case, true);
cli_replace!(config.search.placeholder, self.placeholder); cfg_replace!(config.search.placeholder, self.placeholder);
// override keybind settings // override keybind settings
cli_replace!(config.keybinds.exec, self.key_exec, true); cfg_replace!(config.keybinds.exec, self.key_exec, true);
cli_replace!(config.keybinds.exit, self.key_exit, true); cfg_replace!(config.keybinds.exit, self.key_exit, true);
cli_replace!(config.keybinds.move_next, self.key_move_next, true); cfg_replace!(config.keybinds.move_next, self.key_move_next, true);
cli_replace!(config.keybinds.move_prev, self.key_move_prev, true); cfg_replace!(config.keybinds.move_prev, self.key_move_prev, true);
cli_replace!(config.keybinds.open_menu, self.key_open_menu, true); cfg_replace!(config.keybinds.open_menu, self.key_open_menu, true);
cli_replace!(config.keybinds.close_menu, self.key_close_menu, true); cfg_replace!(config.keybinds.close_menu, self.key_close_menu, true);
cli_replace!(config.keybinds.jump_next, self.key_jump_next, true); cfg_replace!(config.keybinds.jump_next, self.key_jump_next, true);
cli_replace!(config.keybinds.jump_prev, self.key_jump_prev, true); cfg_replace!(config.keybinds.jump_prev, self.key_jump_prev, true);
// override window settings // override window settings
cli_replace!(config.window.title, self.title, true); cfg_replace!(config.window.title, self.title, true);
cli_replace!(config.window.size.width, self.width, true); cfg_replace!(config.window.size.width, self.width, true);
cli_replace!(config.window.size.height, self.height, true); cfg_replace!(config.window.size.height, self.height, true);
cli_replace!(config.window.position.x, self.xpos, true); cfg_replace!(config.window.position.x, self.xpos, true);
cli_replace!(config.window.position.y, self.ypos, true); cfg_replace!(config.window.position.y, self.ypos, true);
cli_replace!(config.window.focus, self.focus, true); cfg_replace!(config.window.focus, self.focus, true);
cli_replace!(config.window.decorate, self.decorate, true); cfg_replace!(config.window.decorate, self.decorate, true);
cli_replace!(config.window.transparent, self.transparent, true); cfg_replace!(config.window.transparent, self.transparent, true);
cli_replace!(config.window.always_top, self.always_top, true); cfg_replace!(config.window.always_top, self.always_top, true);
cli_replace!(config.window.fullscreen, self.fullscreen); cfg_replace!(config.window.fullscreen, self.fullscreen);
config config
} }
@ -275,8 +248,8 @@ impl Args {
} }
/// Load Additional CSS or Default /// Load Additional CSS or Default
pub fn get_css(&self) -> String { pub fn get_css(&self, c: &Config) -> String {
if let Some(css) = self.css.as_ref() { if let Some(css) = self.css.as_ref().or(c.css.as_ref()) {
let path = shellexpand::tilde(&css).to_string(); let path = shellexpand::tilde(&css).to_string();
match read_to_string(&path) { match read_to_string(&path) {
Ok(theme) => return theme, Ok(theme) => return theme,
@ -299,30 +272,9 @@ impl Args {
let msg: Message = serde_json::from_str(&line)?; let msg: Message = serde_json::from_str(&line)?;
match msg { match msg {
Message::Entry(entry) => v.push(entry), Message::Entry(entry) => v.push(entry),
Message::Options(options) => { Message::Options(options) => c
// base settings .update(&options)
self.css = self.css.clone().or(options.css); .map_err(|s| RMenuError::InvalidKeybind(s))?,
// search settings
cli_replace!(c.search.placeholder, options.placeholder);
cli_replace!(c.search.restrict, options.search_restrict);
cli_replace!(c.search.min_length, options.search_min_length);
cli_replace!(c.search.max_length, options.search_max_length);
// keybind settings
cli_keybind!(c.keybinds.exec, options.key_exec);
cli_keybind!(c.keybinds.exec, options.key_exec);
cli_keybind!(c.keybinds.exit, options.key_exit);
cli_keybind!(c.keybinds.move_next, options.key_move_next);
cli_keybind!(c.keybinds.move_prev, options.key_move_prev);
cli_keybind!(c.keybinds.open_menu, options.key_open_menu);
cli_keybind!(c.keybinds.close_menu, options.key_close_menu);
cli_keybind!(c.keybinds.jump_next, options.key_jump_next);
cli_keybind!(c.keybinds.jump_prev, options.key_jump_prev);
// window settings
cli_replace!(c.window.title, options.title, true);
cli_replace!(c.window.decorate, options.decorate, true);
cli_replace!(c.window.size.width, options.window_width, true);
cli_replace!(c.window.size.height, options.window_height, true);
}
} }
} }
} }
@ -355,6 +307,12 @@ impl Args {
.get(&name) .get(&name)
.cloned() .cloned()
.ok_or_else(|| RMenuError::NoSuchPlugin(name.to_owned()))?; .ok_or_else(|| RMenuError::NoSuchPlugin(name.to_owned()))?;
// update config w/ plugin options when available
if let Some(options) = plugin.options.as_ref() {
config
.update(options)
.map_err(|e| RMenuError::InvalidKeybind(e))?;
}
// read cache when available // read cache when available
match crate::cache::read_cache(&name, &plugin) { match crate::cache::read_cache(&name, &plugin) {
Err(err) => log::error!("cache read failed: {err:?}"), Err(err) => log::error!("cache read failed: {err:?}"),

View file

@ -1,6 +1,7 @@
//! RMENU Configuration Implementations //! RMENU Configuration Implementations
use heck::AsPascalCase; use heck::AsPascalCase;
use keyboard_types::{Code, Modifiers}; use keyboard_types::{Code, Modifiers};
use rmenu_plugin::Options;
use serde::{de::Error, Deserialize}; use serde::{de::Error, Deserialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::str::FromStr; use std::str::FromStr;
@ -201,6 +202,8 @@ pub struct PluginConfig {
pub cache: CacheSetting, pub cache: CacheSetting,
#[serde(default)] #[serde(default)]
pub placeholder: Option<String>, pub placeholder: Option<String>,
#[serde(default)]
pub options: Option<Options>,
} }
#[inline] #[inline]
@ -249,6 +252,7 @@ pub struct Config {
pub plugins: BTreeMap<String, PluginConfig>, pub plugins: BTreeMap<String, PluginConfig>,
pub keybinds: KeyConfig, pub keybinds: KeyConfig,
pub window: WindowConfig, pub window: WindowConfig,
pub css: Option<String>,
pub terminal: Option<String>, pub terminal: Option<String>,
} }
@ -264,7 +268,67 @@ impl Default for Config {
plugins: Default::default(), plugins: Default::default(),
keybinds: Default::default(), keybinds: Default::default(),
window: Default::default(), window: Default::default(),
terminal: Default::default(), css: None,
terminal: None,
} }
} }
} }
macro_rules! cfg_replace {
($key:expr, $repl:expr) => {
if $repl.is_some() {
$key = $repl.clone();
}
};
($key:expr, $repl:expr, true) => {
if let Some(value) = $repl.as_ref() {
$key = value.to_owned();
}
};
}
macro_rules! cfg_keybind {
($key:expr, $repl:expr) => {
if let Some(bind_strings) = $repl.as_ref() {
let mut keybinds = vec![];
for bind_str in bind_strings.iter() {
let bind = Keybind::from_str(bind_str)?;
keybinds.push(bind);
}
$key = keybinds;
}
};
}
pub(crate) use cfg_keybind;
pub(crate) use cfg_replace;
impl Config {
/// Update Configuration from Options Object
pub fn update(&mut self, options: &Options) -> Result<(), String> {
cfg_replace!(self.css, options.css);
// search settings
cfg_replace!(self.search.placeholder, options.placeholder);
cfg_replace!(self.search.restrict, options.search_restrict);
cfg_replace!(self.search.min_length, options.search_min_length);
cfg_replace!(self.search.max_length, options.search_max_length);
// keybind settings
cfg_keybind!(self.keybinds.exec, options.key_exec);
cfg_keybind!(self.keybinds.exec, options.key_exec);
cfg_keybind!(self.keybinds.exit, options.key_exit);
cfg_keybind!(self.keybinds.move_next, options.key_move_next);
cfg_keybind!(self.keybinds.move_prev, options.key_move_prev);
cfg_keybind!(self.keybinds.open_menu, options.key_open_menu);
cfg_keybind!(self.keybinds.close_menu, options.key_close_menu);
cfg_keybind!(self.keybinds.jump_next, options.key_jump_next);
cfg_keybind!(self.keybinds.jump_prev, options.key_jump_prev);
// window settings
cfg_replace!(self.window.title, options.title, true);
cfg_replace!(self.window.decorate, options.decorate, true);
cfg_replace!(self.window.fullscreen, options.fullscreen);
cfg_replace!(self.window.transparent, options.transparent, true);
cfg_replace!(self.window.size.width, options.window_width, true);
cfg_replace!(self.window.size.height, options.window_height, true);
Ok(())
}
}

View file

@ -1,5 +1,5 @@
//! GUI Image Processing //! GUI Image Processing
use std::fs::{create_dir_all, read_to_string, write}; use std::fs::{create_dir_all, write};
use std::io; use std::io;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Mutex; use std::sync::Mutex;
@ -37,9 +37,9 @@ fn make_temp() -> Result<(), io::Error> {
/// Convert SVG to PNG Image /// Convert SVG to PNG Image
fn svg_to_png(path: &str, dest: &PathBuf, pixels: u32) -> Result<(), SvgError> { fn svg_to_png(path: &str, dest: &PathBuf, pixels: u32) -> Result<(), SvgError> {
// read and convert to resvg document tree // read and convert to resvg document tree
let xml = read_to_string(path)?; let xml = std::fs::read(path)?;
let opt = resvg::usvg::Options::default(); let opt = resvg::usvg::Options::default();
let tree = resvg::usvg::Tree::from_str(&xml, &opt)?; let tree = resvg::usvg::Tree::from_data(&xml, &opt)?;
let rtree = resvg::Tree::from_usvg(&tree); let rtree = resvg::Tree::from_usvg(&tree);
// generate pixel-buffer and scale according to size preference // generate pixel-buffer and scale according to size preference
let size = rtree.size.to_int_size(); let size = rtree.size.to_int_size();

View file

@ -45,7 +45,7 @@ fn main() -> cli::Result<()> {
let mut cli = cli::Args::parse(); let mut cli = cli::Args::parse();
let mut config = cli.get_config()?; let mut config = cli.get_config()?;
let entries = cli.get_entries(&mut config)?; let entries = cli.get_entries(&mut config)?;
let css = cli.get_css(); let css = cli.get_css(&config);
let theme = cli.get_theme(); let theme = cli.get_theme();
// update config based on cli-settings and entries // update config based on cli-settings and entries