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