feat(input): history up/down

This commit is contained in:
OliverGuy 2026-05-07 00:31:13 +02:00
parent 3f5cc47a48
commit 311830b234
9 changed files with 121 additions and 4 deletions

View file

@ -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)?;

View file

@ -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" },

View file

@ -22,6 +22,7 @@ impl Input {
on!(r#move, "move");
on!(backward);
on!(forward);
on!(history);
match self.mode() {
InputMode::Normal => {

View 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!());
}
}

View file

@ -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);

View 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())
}
}
}
}
}

View file

@ -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);

View 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()) }
}

View file

@ -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);