mirror of
https://github.com/imgurbot12/rmenu.git
synced 2025-02-12 05:05:06 +01:00
feat: allow plugins to have their own config overrides
This commit is contained in:
parent
19901cbe34
commit
7d1a12c05d
8 changed files with 121 additions and 84 deletions
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)?;
|
||||
|
|
114
rmenu/src/cli.rs
114
rmenu/src/cli.rs
|
@ -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:?}"),
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue