From 3a42011fd3cfd2b3a78a6fc78b04a78a25080c3a Mon Sep 17 00:00:00 2001 From: OliverGuy Date: Thu, 7 May 2026 01:23:04 +0200 Subject: [PATCH] feat(history): one snap per history --- yazi-widgets/src/input/actor/history.rs | 12 ++--- yazi-widgets/src/input/history.rs | 60 ++++++++++++++++++------- 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/yazi-widgets/src/input/actor/history.rs b/yazi-widgets/src/input/actor/history.rs index c982e521..5cf4645c 100644 --- a/yazi-widgets/src/input/actor/history.rs +++ b/yazi-widgets/src/input/actor/history.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use yazi_macro::{act, render, succ}; +use yazi_macro::{render, succ}; use yazi_shared::data::Data; use crate::input::{INPUT_HISTORY, Input, InputOp, parser::HistoryOpt}; @@ -10,14 +10,10 @@ impl Input { succ!(); } - let new_value = INPUT_HISTORY.lock().unwrap().navigate(opt.offset, &self.snap().value); - let Some(value) = new_value else { succ!() }; + if !INPUT_HISTORY.lock().unwrap().navigate(opt.offset, &mut self.snaps, self.limit) { + succ!(); + } - let snap = self.snap_mut(); - snap.value = value; - snap.cursor = snap.count(); - - act!(r#move, self)?; succ!(render!()); } } diff --git a/yazi-widgets/src/input/history.rs b/yazi-widgets/src/input/history.rs index e123019d..920d8560 100644 --- a/yazi-widgets/src/input/history.rs +++ b/yazi-widgets/src/input/history.rs @@ -1,17 +1,20 @@ -use std::sync::Mutex; +use std::{mem, sync::Mutex}; + +use super::{InputMode, InputSnaps}; pub static INPUT_HISTORY: Mutex = Mutex::new(InputHistory::new()); -#[derive(Debug, Default)] +#[derive(Default)] pub struct InputHistory { entries: Vec, + entry_snaps: Vec>, idx: Option, - draft: String, + draft: Option, } impl InputHistory { pub const fn new() -> Self { - Self { entries: Vec::new(), idx: None, draft: String::new() } + Self { entries: Vec::new(), entry_snaps: Vec::new(), idx: None, draft: None } } pub fn push(&mut self, value: String) { @@ -20,18 +23,19 @@ impl InputHistory { } if self.entries.last().map(String::as_str) != Some(&value) { self.entries.push(value); + self.entry_snaps.push(None); } self.reset(); } pub fn reset(&mut self) { self.idx = None; - self.draft.clear(); + self.draft = None; } - pub fn navigate(&mut self, step: i64, current: &str) -> Option { + pub fn navigate(&mut self, step: i64, snaps: &mut InputSnaps, limit: usize) -> bool { if self.entries.is_empty() || step == 0 { - return None; + return false; } let len = self.entries.len() as i64; @@ -39,18 +43,42 @@ impl InputHistory { let new_pos = (pos + step).clamp(0, len); if new_pos == pos { - return None; + return false; } - if new_pos == len { - self.idx = None; - Some(std::mem::take(&mut self.draft)) + let mode = snaps.current().mode; + + // Save current snaps into draft or the slot we're leaving + let old = mem::take(snaps); + if let Some(old_idx) = self.idx { + self.entry_snaps[old_idx] = Some(old); } else { - if self.idx.is_none() { - self.draft = current.to_owned(); - } - self.idx = Some(new_pos as usize); - Some(self.entries[new_pos as usize].clone()) + self.draft = Some(old); } + + // Load target snaps + *snaps = if new_pos == len { + self.idx = None; + self.draft.take().unwrap_or_default() + } else { + let new_idx = new_pos as usize; + self.idx = Some(new_idx); + if self.entry_snaps[new_idx].is_none() { + let value = self.entries[new_idx].clone(); + self.entry_snaps[new_idx] = Some(Self::initial_snaps(value, mode, limit)); + } + self.entry_snaps[new_idx].take().unwrap() + }; + + true + } + + fn initial_snaps(value: String, mode: InputMode, limit: usize) -> InputSnaps { + let mut snaps = InputSnaps::new(value, false, limit); + let snap = snaps.current_mut(); + snap.mode = mode; + snap.cursor = snap.count().saturating_sub(mode.delta()); + snap.resize(limit); + snaps } }