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

View File

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

View File

@ -25,6 +25,15 @@ plugins:
drun:
exec: ["~/.config/rmenu/rmenu-desktop"]
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:
exec: ["~/.config/rmenu/rmenu-network"]
cache: false

View File

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

View File

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

View File

@ -1,6 +1,7 @@
//! RMENU Configuration Implementations
use heck::AsPascalCase;
use keyboard_types::{Code, Modifiers};
use rmenu_plugin::Options;
use serde::{de::Error, Deserialize};
use std::collections::BTreeMap;
use std::str::FromStr;
@ -201,6 +202,8 @@ pub struct PluginConfig {
pub cache: CacheSetting,
#[serde(default)]
pub placeholder: Option<String>,
#[serde(default)]
pub options: Option<Options>,
}
#[inline]
@ -249,6 +252,7 @@ pub struct Config {
pub plugins: BTreeMap<String, PluginConfig>,
pub keybinds: KeyConfig,
pub window: WindowConfig,
pub css: Option<String>,
pub terminal: Option<String>,
}
@ -264,7 +268,67 @@ impl Default for Config {
plugins: Default::default(),
keybinds: 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
use std::fs::{create_dir_all, read_to_string, write};
use std::fs::{create_dir_all, write};
use std::io;
use std::path::PathBuf;
use std::sync::Mutex;
@ -37,9 +37,9 @@ fn make_temp() -> Result<(), io::Error> {
/// Convert SVG to PNG Image
fn svg_to_png(path: &str, dest: &PathBuf, pixels: u32) -> Result<(), SvgError> {
// 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 tree = resvg::usvg::Tree::from_str(&xml, &opt)?;
let tree = resvg::usvg::Tree::from_data(&xml, &opt)?;
let rtree = resvg::Tree::from_usvg(&tree);
// generate pixel-buffer and scale according to size preference
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 config = cli.get_config()?;
let entries = cli.get_entries(&mut config)?;
let css = cli.get_css();
let css = cli.get_css(&config);
let theme = cli.get_theme();
// update config based on cli-settings and entries