diff --git a/yazi-core/src/input/commands/move_.rs b/yazi-core/src/input/commands/move_.rs index aac48b7eb..b050455dc 100644 --- a/yazi-core/src/input/commands/move_.rs +++ b/yazi-core/src/input/commands/move_.rs @@ -39,8 +39,11 @@ impl Input { )); let (limit, snap) = (self.limit(), self.snap_mut()); - if snap.offset > snap.cursor { - snap.offset = snap.cursor; + let offset = InputSnap::find_window_backward(&snap.value, snap.cursor, limit / 2) + .start + .min(InputSnap::find_window_backward(&snap.value, snap.value.chars().count(), limit).start); + if snap.offset != offset { + snap.offset = offset; } else if snap.value.is_empty() { snap.offset = 0; } else { diff --git a/yazi-core/src/input/snap.rs b/yazi-core/src/input/snap.rs index e6f98232e..d23cf3cd6 100644 --- a/yazi-core/src/input/snap.rs +++ b/yazi-core/src/input/snap.rs @@ -87,4 +87,25 @@ impl InputSnap { } *v.first().unwrap()..v.last().unwrap() + 1 } + + #[inline] + pub(super) fn find_window_backward(s: &str, offset: usize, limit: usize) -> Range { + let mut width = 0; + let len = s.chars().count(); + let v: Vec<_> = s + .chars() + .rev() + .enumerate() + .skip(len.saturating_sub(offset + 1)) + .map_while(|(i, c)| { + width += c.width().unwrap_or(0); + if width < limit { Some(len.saturating_sub(i + 1)) } else { None } + }) + .collect(); + + if v.is_empty() { + return 0..0; + } + *v.last().unwrap()..v.first().unwrap() + 1 + } }