mirror of
https://github.com/imgurbot12/rmenu.git
synced 2025-01-27 05:18:33 +01:00
feat: added jump next/prev keybinds, bincode does not support tagged items
This commit is contained in:
parent
59e8cf6c22
commit
3f7baff1fb
9 changed files with 99 additions and 27 deletions
|
@ -14,6 +14,7 @@ name = "rmenu-build"
|
|||
path = "src/bin/main.rs"
|
||||
|
||||
[dependencies]
|
||||
bincode = "1.3.3"
|
||||
clap = { version = "4.3.22", features = ["derive"] }
|
||||
serde = { version = "1.0.171", features = ["derive"] }
|
||||
serde_json = "1.0.105"
|
||||
|
|
|
@ -155,6 +155,12 @@ struct OptionArgs {
|
|||
/// Override Close-Menu Keybinds
|
||||
#[arg(short = 'c', long)]
|
||||
pub key_close_menu: Option<Vec<String>>,
|
||||
/// Override Jump-Next Keybinds
|
||||
#[arg(short = 'j', long)]
|
||||
pub key_jump_next: Option<Vec<String>>,
|
||||
/// Override Jump-Previous Keybinds
|
||||
#[arg(short = 'J', long)]
|
||||
pub key_jump_prev: Option<Vec<String>>,
|
||||
// window settings
|
||||
/// Override Window Title
|
||||
#[arg(short, long)]
|
||||
|
@ -187,6 +193,8 @@ impl Into<Options> for OptionArgs {
|
|||
key_move_prev: self.key_move_prev,
|
||||
key_open_menu: self.key_open_menu,
|
||||
key_close_menu: self.key_close_menu,
|
||||
key_jump_next: self.key_jump_next,
|
||||
key_jump_prev: self.key_jump_prev,
|
||||
title: self.title,
|
||||
decorate: self.deocorate,
|
||||
fullscreen: self.fullscreen,
|
||||
|
|
|
@ -110,6 +110,10 @@ pub struct Options {
|
|||
pub key_open_menu: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub key_close_menu: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub key_jump_next: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub key_jump_prev: Option<Vec<String>>,
|
||||
// window settings
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub title: Option<String>,
|
||||
|
|
|
@ -6,7 +6,6 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bincode = "1.3.3"
|
||||
cached = "0.44.0"
|
||||
clap = { version = "4.3.15", features = ["derive"] }
|
||||
dioxus = "0.4.0"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//! RMenu Plugin Result Cache
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
|
@ -25,7 +24,7 @@ pub enum CacheError {
|
|||
#[error("Cache File Error")]
|
||||
FileError(#[from] std::io::Error),
|
||||
#[error("Encoding Error")]
|
||||
EncodingError(#[from] bincode::Error),
|
||||
EncodingError(#[from] serde_json::Error),
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -69,7 +68,7 @@ pub fn read_cache(name: &str, cfg: &PluginConfig) -> Result<Vec<Entry>, CacheErr
|
|||
}
|
||||
// attempt to read content
|
||||
let data = fs::read(path)?;
|
||||
let results: Vec<Entry> = bincode::deserialize(&data)?;
|
||||
let results: Vec<Entry> = serde_json::from_slice(&data)?;
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
|
@ -79,10 +78,10 @@ pub fn write_cache(name: &str, cfg: &PluginConfig, entries: &Vec<Entry>) -> Resu
|
|||
match cfg.cache {
|
||||
CacheSetting::NoCache => {}
|
||||
_ => {
|
||||
println!("writing {} entries", entries.len());
|
||||
let path = cache_file(name);
|
||||
let data = bincode::serialize(entries)?;
|
||||
let mut f = fs::File::create(path)?;
|
||||
f.write_all(&data)?;
|
||||
let f = fs::File::create(path)?;
|
||||
serde_json::to_writer(f, entries)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -117,6 +117,12 @@ pub struct Args {
|
|||
/// Override close-menu keybind
|
||||
#[arg(long)]
|
||||
key_close_menu: Option<Vec<Keybind>>,
|
||||
/// Override jump-next keybind
|
||||
#[arg(long)]
|
||||
key_jump_next: Option<Vec<Keybind>>,
|
||||
/// Override jump-previous keybind
|
||||
#[arg(long)]
|
||||
key_jump_prev: Option<Vec<Keybind>>,
|
||||
|
||||
//window settings
|
||||
/// Override Window Title
|
||||
|
@ -240,6 +246,8 @@ impl Args {
|
|||
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);
|
||||
// override window settings
|
||||
cli_replace!(config.window.title, self.title, true);
|
||||
cli_replace!(config.window.size.width, self.width, true);
|
||||
|
@ -307,6 +315,8 @@ impl Args {
|
|||
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);
|
||||
|
@ -362,7 +372,7 @@ impl Args {
|
|||
let main = args
|
||||
.get(0)
|
||||
.ok_or_else(|| RMenuError::InvalidPlugin(name.to_owned()))?;
|
||||
// spawn command and handle command entries
|
||||
// spawn command
|
||||
let mut command = Command::new(main)
|
||||
.args(&args[1..])
|
||||
.stdout(Stdio::piped())
|
||||
|
@ -371,8 +381,10 @@ impl Args {
|
|||
.stdout
|
||||
.as_mut()
|
||||
.ok_or_else(|| RMenuError::CommandError(None))?;
|
||||
// parse and read entries into vector of results
|
||||
let reader = BufReader::new(stdout);
|
||||
self.read_entries(reader, &mut entries, config)?;
|
||||
let mut entry = vec![];
|
||||
self.read_entries(reader, &mut entry, config)?;
|
||||
let status = command.wait()?;
|
||||
if !status.success() {
|
||||
return Err(RMenuError::CommandError(Some(status)));
|
||||
|
@ -381,10 +393,12 @@ impl Args {
|
|||
if config.search.placeholder.is_none() {
|
||||
config.search.placeholder = plugin.placeholder.clone();
|
||||
}
|
||||
match crate::cache::write_cache(&name, &plugin, &entries) {
|
||||
match crate::cache::write_cache(&name, &plugin, &entry) {
|
||||
Ok(_) => {}
|
||||
Err(err) => log::error!("cache write error: {err:?}"),
|
||||
}
|
||||
// write collected entries to main output
|
||||
entries.append(&mut entry);
|
||||
}
|
||||
Ok(entries)
|
||||
}
|
||||
|
|
|
@ -87,6 +87,8 @@ pub struct KeyConfig {
|
|||
pub move_prev: Vec<Keybind>,
|
||||
pub open_menu: Vec<Keybind>,
|
||||
pub close_menu: Vec<Keybind>,
|
||||
pub jump_next: Vec<Keybind>,
|
||||
pub jump_prev: Vec<Keybind>,
|
||||
}
|
||||
|
||||
impl Default for KeyConfig {
|
||||
|
@ -98,6 +100,8 @@ impl Default for KeyConfig {
|
|||
move_prev: vec![Keybind::new(Code::ArrowDown)],
|
||||
open_menu: vec![],
|
||||
close_menu: vec![],
|
||||
jump_next: vec![Keybind::new(Code::PageDown)],
|
||||
jump_prev: vec![Keybind::new(Code::PageUp)],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -236,6 +240,7 @@ impl Default for SearchConfig {
|
|||
pub struct Config {
|
||||
pub page_size: usize,
|
||||
pub page_load: f64,
|
||||
pub jump_dist: usize,
|
||||
#[serde(default = "_true")]
|
||||
pub use_icons: bool,
|
||||
#[serde(default = "_true")]
|
||||
|
@ -252,6 +257,7 @@ impl Default for Config {
|
|||
Self {
|
||||
page_size: 50,
|
||||
page_load: 0.8,
|
||||
jump_dist: 5,
|
||||
use_icons: true,
|
||||
use_comments: true,
|
||||
search: Default::default(),
|
||||
|
|
|
@ -205,14 +205,18 @@ fn App<'a>(cx: Scope<App>) -> Element {
|
|||
k_updater.set_event(KeyEvent::Exec);
|
||||
} else if matches(&keybinds.exit, &mods, &code) {
|
||||
k_updater.set_event(KeyEvent::Exit);
|
||||
} else if matches(&keybinds.move_prev, &mods, &code) {
|
||||
k_updater.set_event(KeyEvent::ShiftUp);
|
||||
} else if matches(&keybinds.move_next, &mods, &code) {
|
||||
k_updater.set_event(KeyEvent::ShiftDown);
|
||||
k_updater.set_event(KeyEvent::MoveNext);
|
||||
} else if matches(&keybinds.move_prev, &mods, &code) {
|
||||
k_updater.set_event(KeyEvent::MovePrev);
|
||||
} else if matches(&keybinds.open_menu, &mods, &code) {
|
||||
k_updater.set_event(KeyEvent::OpenMenu);
|
||||
} else if matches(&keybinds.close_menu, &mods, &code) {
|
||||
k_updater.set_event(KeyEvent::CloseMenu);
|
||||
} else if matches(&keybinds.jump_next, &mods, &code) {
|
||||
k_updater.set_event(KeyEvent::JumpNext)
|
||||
} else if matches(&keybinds.jump_prev, &mods, &code) {
|
||||
k_updater.set_event(KeyEvent::JumpPrev)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -18,10 +18,12 @@ fn scroll<T>(cx: Scope<T>, pos: usize) {
|
|||
pub enum KeyEvent {
|
||||
Exec,
|
||||
Exit,
|
||||
ShiftUp,
|
||||
ShiftDown,
|
||||
MovePrev,
|
||||
MoveNext,
|
||||
OpenMenu,
|
||||
CloseMenu,
|
||||
JumpNext,
|
||||
JumpPrev,
|
||||
}
|
||||
|
||||
pub struct InnerState {
|
||||
|
@ -46,8 +48,20 @@ impl InnerState {
|
|||
self.pos = std::cmp::min(self.pos + x, max - 1)
|
||||
}
|
||||
|
||||
/// Jump a spefified number of results upwards
|
||||
#[inline]
|
||||
pub fn jump_up(&mut self, jump: usize) {
|
||||
self.move_up(jump)
|
||||
}
|
||||
|
||||
/// Jump a specified number of results downwards
|
||||
pub fn jump_down(&mut self, jump: usize, results: &Vec<&Entry>) {
|
||||
let max = std::cmp::max(results.len(), 1);
|
||||
self.move_down(jump, max);
|
||||
}
|
||||
|
||||
/// Move Up Once With Context of SubMenu
|
||||
pub fn shift_up(&mut self) {
|
||||
pub fn move_prev(&mut self) {
|
||||
if self.subpos > 0 {
|
||||
self.subpos -= 1;
|
||||
return;
|
||||
|
@ -56,15 +70,14 @@ impl InnerState {
|
|||
}
|
||||
|
||||
/// Move Down Once With Context of SubMenu
|
||||
pub fn shift_down(&mut self, results: &Vec<&Entry>) {
|
||||
pub fn move_next(&mut self, results: &Vec<&Entry>) {
|
||||
if let Some(result) = results.get(self.pos) {
|
||||
if self.subpos > 0 && self.subpos < result.actions.len() - 1 {
|
||||
self.subpos += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
let max = std::cmp::max(results.len(), 1);
|
||||
self.move_down(1, max);
|
||||
self.jump_down(1, results)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,13 +177,22 @@ impl<'a> AppState<'a> {
|
|||
KeyEvent::Exec => self.execute(),
|
||||
KeyEvent::OpenMenu => self.open_menu(),
|
||||
KeyEvent::CloseMenu => self.close_menu(),
|
||||
KeyEvent::ShiftUp => {
|
||||
self.shift_up();
|
||||
KeyEvent::MovePrev => {
|
||||
self.move_prev();
|
||||
let pos = self.position().0;
|
||||
scroll(cx, if pos <= 3 { pos } else { pos + 3 })
|
||||
}
|
||||
KeyEvent::ShiftDown => {
|
||||
self.shift_down();
|
||||
KeyEvent::MoveNext => {
|
||||
self.move_next();
|
||||
scroll(cx, self.position().0 + 3)
|
||||
}
|
||||
KeyEvent::JumpPrev => {
|
||||
self.jump_prev();
|
||||
let pos = self.position().0;
|
||||
scroll(cx, if pos <= 3 { pos } else { pos + 3 })
|
||||
}
|
||||
KeyEvent::JumpNext => {
|
||||
self.jump_next();
|
||||
scroll(cx, self.position().0 + 3)
|
||||
}
|
||||
};
|
||||
|
@ -265,13 +287,28 @@ impl<'a> AppState<'a> {
|
|||
|
||||
/// Move Up Once With Context of SubMenu
|
||||
#[inline]
|
||||
pub fn shift_up(&self) {
|
||||
self.state.with_mut(|s| s.shift_up());
|
||||
pub fn move_prev(&self) {
|
||||
self.state.with_mut(|s| s.move_prev());
|
||||
}
|
||||
|
||||
/// Move Down Once With Context of SubMenu
|
||||
#[inline]
|
||||
pub fn shift_down(&self) {
|
||||
self.state.with_mut(|s| s.shift_down(&self.results))
|
||||
pub fn move_next(&self) {
|
||||
self.state.with_mut(|s| s.move_next(&self.results))
|
||||
}
|
||||
|
||||
/// Jump a Configured Distance Up the Results
|
||||
#[inline]
|
||||
pub fn jump_prev(&self) {
|
||||
let distance = self.app.config.jump_dist;
|
||||
self.state.with_mut(|s| s.jump_up(distance))
|
||||
}
|
||||
|
||||
/// Jump a Configured Distance Down the Results
|
||||
#[inline]
|
||||
pub fn jump_next(&self) {
|
||||
let distance = self.app.config.jump_dist;
|
||||
self.state
|
||||
.with_mut(|s| s.jump_down(distance, &self.results))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue