feat: better cfg defaults, navigation fixes, css uses one file w/ builtin backup.

This commit is contained in:
imgurbot12 2023-07-21 23:28:33 -07:00
parent 25ee2f32c4
commit 82897da0e2
6 changed files with 42 additions and 49 deletions

View file

@ -9,7 +9,7 @@ edition = "2021"
clap = { version = "4.3.15", features = ["derive"] }
dioxus = "0.3.2"
dioxus-desktop = "0.3.0"
dirs = "5.0.1"
env_logger = "0.10.0"
heck = "0.4.1"
keyboard-types = "0.6.2"
log = "0.4.19"

View file

@ -74,14 +74,13 @@ impl<'de> Deserialize<'de> for Keybind {
}
#[derive(Debug, PartialEq, Deserialize)]
#[serde(default)]
pub struct KeyConfig {
pub exec: Vec<Keybind>,
pub exit: Vec<Keybind>,
pub move_up: Vec<Keybind>,
pub move_down: Vec<Keybind>,
#[serde(default)]
pub open_menu: Vec<Keybind>,
#[serde(default)]
pub close_menu: Vec<Keybind>,
}
@ -129,23 +128,19 @@ impl Default for WindowConfig {
}
#[derive(Debug, PartialEq, Deserialize)]
#[serde(default)]
pub struct Config {
pub css: Vec<String>,
pub use_icons: bool,
pub search_regex: bool,
pub ignore_case: bool,
#[serde(default)]
pub plugins: BTreeMap<String, Vec<String>>,
#[serde(default)]
pub keybinds: KeyConfig,
#[serde(default)]
pub window: WindowConfig,
}
impl Default for Config {
fn default() -> Self {
Self {
css: vec![],
use_icons: true,
search_regex: false,
ignore_case: true,

View file

@ -5,6 +5,7 @@ use std::process::Command;
use rmenu_plugin::Action;
pub fn execute(action: &Action) {
log::info!("executing: {} {:?}", action.name, action.exec);
let args = match shell_words::split(&action.exec) {
Ok(args) => args,
Err(err) => panic!("{:?} invalid command {err}", action.exec),

View file

@ -95,13 +95,8 @@ fn TableEntry<'a>(cx: Scope<'a, GEntry<'a>>) -> Element<'a> {
ondblclick: |_| {
let action = match cx.props.entry.actions.get(0) {
Some(action) => action,
None => {
let name = &cx.props.entry.name;
log::warn!("no action to execute on {:?}", name);
return;
}
None => panic!("No Action Configured"),
};
log::info!("executing: {:?}", action.exec);
execute(action);
},
if cx.props.config.use_icons {
@ -168,7 +163,7 @@ fn App(cx: Scope<App>) -> Element {
// retrieve results build and build position-tracker
let tracker = PosTracker::new(cx, results.clone());
let (pos, subpos) = tracker.position();
log::debug!("pos: {pos}, {subpos}");
log::debug!("search: {search:?}, pos: {pos}, {subpos}");
// keyboard events
let keybinds = &cx.props.config.keybinds;

View file

@ -15,6 +15,11 @@ use clap::Parser;
use rmenu_plugin::Entry;
use thiserror::Error;
static CONFIG_DIR: &'static str = "~/.config/rmenu/";
static DEFAULT_CSS: &'static str = "~/.config/rmenu/style.css";
static DEFAULT_CONFIG: &'static str = "~/.config/rmenu/config.yaml";
static DEFAULT_CSS_CONTENT: &'static str = include_str!("../public/default.css");
#[derive(Debug, Clone)]
pub enum Format {
Json,
@ -80,7 +85,7 @@ pub struct Args {
#[arg(short, long)]
config: Option<String>,
#[arg(long)]
css: Vec<String>,
css: Option<String>,
}
impl Args {
@ -88,16 +93,7 @@ impl Args {
fn config(&self) -> Result<config::Config, RMenuError> {
let path = match &self.config {
Some(path) => path.to_owned(),
None => match dirs::config_dir() {
Some(mut dir) => {
dir.push("rmenu");
dir.push("config.yaml");
dir.to_string_lossy().to_string()
}
None => {
return Err(RMenuError::HomeNotFound);
}
},
None => shellexpand::tilde(DEFAULT_CONFIG).to_string(),
};
log::debug!("loading config from {path:?}");
let cfg = match read_to_string(path) {
@ -140,7 +136,7 @@ impl Args {
/// Load Entries From Specified Sources
fn load_sources(&self, cfg: &config::Config) -> Result<Vec<Entry>, RMenuError> {
println!("{cfg:?}");
log::debug!("config: {cfg:?}");
// execute commands to get a list of entries
let mut entries = vec![];
for plugin in self.run.iter() {
@ -188,15 +184,17 @@ impl Args {
/// Load Application
pub fn parse_app() -> Result<App, RMenuError> {
let args = Self::parse();
let mut config = args.config()?;
let config = args.config()?;
// load css files from settings
config.css.extend(args.css.clone());
let mut css = vec![];
for path in config.css.iter() {
let path = shellexpand::tilde(path).to_string();
let src = read_to_string(path)?;
css.push(src);
}
let csspath = args.css.clone().unwrap_or_else(|| DEFAULT_CSS.to_owned());
let csspath = shellexpand::tilde(&csspath).to_string();
let css = match read_to_string(csspath) {
Ok(css) => css,
Err(err) => {
log::error!("failed to load css: {err:?}");
DEFAULT_CSS_CONTENT.to_owned()
}
};
// load entries from configured sources
let entries = match args.run.len() > 0 {
true => args.load_sources(&config)?,
@ -204,7 +202,7 @@ impl Args {
};
// generate app object
return Ok(App {
css: css.join("\n"),
css,
name: "rmenu".to_owned(),
entries,
config,
@ -215,13 +213,16 @@ impl Args {
//TODO: improve search w/ modes?
//TODO: improve looks and css
//TODO: config
// - default and cli accessable modules (instead of piped in)
// - should resolve arguments/paths with home expansion
//TODO: add exit key (Esc by default?) - part of keybindings
fn main() -> Result<(), RMenuError> {
// enable log if env-var is present
if std::env::var("RUST_LOG").is_ok() {
env_logger::init();
}
// change directory to configuration dir
let cfgdir = shellexpand::tilde(CONFIG_DIR).to_string();
if let Err(err) = std::env::set_current_dir(&cfgdir) {
log::error!("failed to change directory: {err:?}");
}
// parse cli / config / application-settings
let app = Args::parse_app()?;
gui::run(app);

View file

@ -28,9 +28,9 @@ impl<'a> PosTracker<'a> {
}
/// Move X Primary Results Downwards
pub fn move_down(&self, x: usize) {
let max = std::cmp::max(self.results.len(), 1);
self.subpos.set(0);
self.pos
.modify(|v| std::cmp::min(v + x, self.results.len() - 1))
self.pos.modify(|v| std::cmp::min(v + x, max - 1))
}
/// Get Current Position/SubPosition
pub fn position(&self) -> (usize, usize) {
@ -64,11 +64,12 @@ impl<'a> PosTracker<'a> {
/// Move Down Once With Context of SubMenu
pub fn shift_down(&self) {
let index = *self.pos.get();
let result = &self.results[index];
let subpos = *self.subpos.get();
if subpos > 0 && subpos < result.actions.len() - 1 {
self.subpos.modify(|v| v + 1);
return;
if let Some(result) = &self.results.get(index) {
let subpos = *self.subpos.get();
if subpos > 0 && subpos < result.actions.len() - 1 {
self.subpos.modify(|v| v + 1);
return;
}
}
self.move_down(1)
}