feat(history): one snap per history

This commit is contained in:
OliverGuy 2026-05-07 01:23:04 +02:00
parent 5c3ea6e2ff
commit 3a42011fd3
2 changed files with 48 additions and 24 deletions

View file

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

View file

@ -1,17 +1,20 @@
use std::sync::Mutex;
use std::{mem, sync::Mutex};
use super::{InputMode, InputSnaps};
pub static INPUT_HISTORY: Mutex<InputHistory> = Mutex::new(InputHistory::new());
#[derive(Debug, Default)]
#[derive(Default)]
pub struct InputHistory {
entries: Vec<String>,
entry_snaps: Vec<Option<InputSnaps>>,
idx: Option<usize>,
draft: String,
draft: Option<InputSnaps>,
}
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<String> {
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
}
}