mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat(input): history up/down
This commit is contained in:
parent
3f5cc47a48
commit
311830b234
9 changed files with 121 additions and 4 deletions
|
|
@ -20,7 +20,12 @@ impl Actor for Close {
|
|||
|
||||
if let Some(tx) = input.tx.take() {
|
||||
let value = input.snap().value.clone();
|
||||
_ = tx.send(if form.submit { InputEvent::Submit(value) } else { InputEvent::Cancel(value) });
|
||||
if form.submit {
|
||||
yazi_widgets::input::INPUT_HISTORY.lock().unwrap().push(value.clone());
|
||||
_ = tx.send(InputEvent::Submit(value));
|
||||
} else {
|
||||
_ = tx.send(InputEvent::Cancel(value));
|
||||
}
|
||||
}
|
||||
|
||||
act!(cmp:close, cx)?;
|
||||
|
|
|
|||
|
|
@ -304,6 +304,12 @@ keymap = [
|
|||
{ on = "p", run = "paste", desc = "Paste copied characters after the cursor" },
|
||||
{ on = "P", run = "paste --before", desc = "Paste copied characters before the cursor" },
|
||||
|
||||
# History
|
||||
{ on = "<Up>", run = "history up", desc = "Navigate to the previous history entry" },
|
||||
{ on = "<Down>", run = "history down", desc = "Navigate to the next history entry" },
|
||||
{ on = "<C-p>", run = "history up", desc = "Navigate to the previous history entry" },
|
||||
{ on = "<C-n>", run = "history down", desc = "Navigate to the next history entry" },
|
||||
|
||||
# Undo/Redo/Casefy
|
||||
{ on = "u", run = [ "undo", "casefy lower" ], desc = "Undo, or lowercase if in visual mode" },
|
||||
{ on = "U", run = "casefy upper", desc = "Uppercase" },
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ impl Input {
|
|||
on!(r#move, "move");
|
||||
on!(backward);
|
||||
on!(forward);
|
||||
on!(history);
|
||||
|
||||
match self.mode() {
|
||||
InputMode::Normal => {
|
||||
|
|
|
|||
23
yazi-widgets/src/input/actor/history.rs
Normal file
23
yazi-widgets/src/input/actor/history.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::input::{Input, InputOp, INPUT_HISTORY, parser::HistoryOpt};
|
||||
|
||||
impl Input {
|
||||
pub fn history(&mut self, opt: HistoryOpt) -> Result<Data> {
|
||||
if self.snap().op != InputOp::None {
|
||||
succ!();
|
||||
}
|
||||
|
||||
let new_value = INPUT_HISTORY.lock().unwrap().navigate(opt.up, &self.snap().value);
|
||||
let Some(value) = new_value else { succ!() };
|
||||
|
||||
let snap = self.snap_mut();
|
||||
snap.value = value;
|
||||
snap.cursor = snap.count();
|
||||
|
||||
act!(r#move, self)?;
|
||||
succ!(render!());
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(actor backspace backward casefy complete delete escape forward insert kill paste r#move r#type redo replace undo visual yank);
|
||||
yazi_macro::mod_flat!(actor backspace backward casefy complete delete escape forward history insert kill paste r#move r#type redo replace undo visual yank);
|
||||
|
|
|
|||
63
yazi-widgets/src/input/history.rs
Normal file
63
yazi-widgets/src/input/history.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use std::sync::Mutex;
|
||||
|
||||
pub static INPUT_HISTORY: Mutex<InputHistory> = Mutex::new(InputHistory::new());
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct InputHistory {
|
||||
entries: Vec<String>,
|
||||
idx: Option<usize>,
|
||||
draft: String,
|
||||
}
|
||||
|
||||
impl InputHistory {
|
||||
pub const fn new() -> Self {
|
||||
Self { entries: Vec::new(), idx: None, draft: String::new() }
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: String) {
|
||||
if value.is_empty() {
|
||||
return;
|
||||
}
|
||||
if self.entries.last().map(String::as_str) != Some(&value) {
|
||||
self.entries.push(value);
|
||||
}
|
||||
self.reset();
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.idx = None;
|
||||
self.draft.clear();
|
||||
}
|
||||
|
||||
pub fn navigate(&mut self, up: bool, current: &str) -> Option<String> {
|
||||
if self.entries.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if up {
|
||||
let new_idx = match self.idx {
|
||||
None => {
|
||||
self.draft = current.to_owned();
|
||||
self.entries.len() - 1
|
||||
}
|
||||
Some(0) => return None,
|
||||
Some(i) => i - 1,
|
||||
};
|
||||
self.idx = Some(new_idx);
|
||||
Some(self.entries[new_idx].clone())
|
||||
} else {
|
||||
match self.idx {
|
||||
None => None,
|
||||
Some(i) if i + 1 >= self.entries.len() => {
|
||||
self.idx = None;
|
||||
let draft = std::mem::take(&mut self.draft);
|
||||
Some(draft)
|
||||
}
|
||||
Some(i) => {
|
||||
self.idx = Some(i + 1);
|
||||
Some(self.entries[i + 1].clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
yazi_macro::mod_pub!(actor parser);
|
||||
|
||||
yazi_macro::mod_flat!(event input mode op option snap snaps widget);
|
||||
yazi_macro::mod_flat!(event history input mode op option snap snaps widget);
|
||||
|
|
|
|||
19
yazi-widgets/src/input/parser/history.rs
Normal file
19
yazi-widgets/src/input/parser/history.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
use yazi_shared::event::ActionCow;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HistoryOpt {
|
||||
pub up: bool,
|
||||
}
|
||||
|
||||
impl From<ActionCow> for HistoryOpt {
|
||||
fn from(a: ActionCow) -> Self { Self { up: a.str(0) == "up" } }
|
||||
}
|
||||
|
||||
impl FromLua for HistoryOpt {
|
||||
fn from_lua(_: Value, _: &Lua) -> mlua::Result<Self> { Err("unsupported".into_lua_err()) }
|
||||
}
|
||||
|
||||
impl IntoLua for HistoryOpt {
|
||||
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(backspace backward casefy complete delete forward insert kill paste r#move);
|
||||
yazi_macro::mod_flat!(backspace backward casefy complete delete forward history insert kill paste r#move);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue