From 0bdb52fd1ba1d29c2821629d9c6d169440ced809 Mon Sep 17 00:00:00 2001 From: Francis Chua Date: Sun, 12 Nov 2023 18:04:52 +0000 Subject: [PATCH] separate vim and emacs logic (find_word_boundary) --- yazi-core/src/input/commands/backward.rs | 22 +++++++++++-- yazi-core/src/input/commands/forward.rs | 30 ++++++++++++----- yazi-core/src/input/input.rs | 42 +++++++++++------------- 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/yazi-core/src/input/commands/backward.rs b/yazi-core/src/input/commands/backward.rs index f23c914c..55f88de2 100644 --- a/yazi-core/src/input/commands/backward.rs +++ b/yazi-core/src/input/commands/backward.rs @@ -1,4 +1,5 @@ use yazi_config::keymap::Exec; +use yazi_shared::CharKind; use crate::input::Input; @@ -14,9 +15,24 @@ impl From<()> for Opt { impl Input { pub fn backward(&mut self, _: impl Into) -> bool { let snap = self.snap(); - let idx = snap.idx(snap.cursor).unwrap_or(snap.len()); + if snap.cursor == 0 { + return self.move_(0); + } - let step = Self::find_word_boundary(snap.value[..idx].chars().rev(), false, true); - self.move_(-(step as isize)) + let idx = snap.idx(snap.cursor).unwrap_or(snap.len()); + let mut it = snap.value[..idx].chars().rev().enumerate(); + let mut prev = CharKind::new(it.next().unwrap().1); + for (i, c) in it { + let c = CharKind::new(c); + if prev != CharKind::Space && prev != c { + return self.move_(-(i as isize)); + } + prev = c; + } + + if prev != CharKind::Space { + return self.move_(-(snap.len() as isize)); + } + false } } diff --git a/yazi-core/src/input/commands/forward.rs b/yazi-core/src/input/commands/forward.rs index 4a6eb000..3666dc56 100644 --- a/yazi-core/src/input/commands/forward.rs +++ b/yazi-core/src/input/commands/forward.rs @@ -1,4 +1,5 @@ use yazi_config::keymap::Exec; +use yazi_shared::CharKind; use crate::input::{op::InputOp, Input}; @@ -18,14 +19,27 @@ impl Input { let opt = opt.into() as Opt; let snap = self.snap(); - let idx = snap.idx(snap.cursor).unwrap_or(snap.len()); + if snap.value.is_empty() { + return self.move_(0); + } - let step = Self::find_word_boundary( - snap.value[idx..].chars(), - // If not in vim mode or just moving (not deleting or yanking), use end_of_word. - if let InputOp::None = snap.op { opt.end_of_word } else { false }, - opt.end_of_word, - ); - self.move_(step as isize) + let mut it = snap.value.chars().skip(snap.cursor).enumerate(); + let mut prev = CharKind::new(it.next().unwrap().1); + for (i, c) in it { + let c = CharKind::new(c); + let b = if opt.end_of_word { + prev != CharKind::Space && prev != c && i != 1 + } else { + c != CharKind::Space && c != prev + }; + if b && !matches!(snap.op, InputOp::None | InputOp::Select(_)) { + return self.move_(i as isize); + } else if b { + return self.move_(if opt.end_of_word { i - 1 } else { i } as isize); + } + prev = c; + } + + self.move_(snap.len() as isize) } } diff --git a/yazi-core/src/input/input.rs b/yazi-core/src/input/input.rs index 7e34fa09..8ed5b381 100644 --- a/yazi-core/src/input/input.rs +++ b/yazi-core/src/input/input.rs @@ -59,15 +59,7 @@ impl Input { /// /// Otherwise, returns how many characters to move to reach right *AFTER* the /// word boundary, or the end of the iterator. - pub(super) fn find_word_boundary( - input: impl Iterator + Clone, - stop_before_boundary: bool, - skip_whitespace_first: bool, - ) -> usize { - // If we want the *NEXT* end of word, then we want to skip the current - // character. - let input = input.skip(stop_before_boundary.into()); - + pub(super) fn find_word_boundary(input: impl Iterator + Clone) -> usize { fn count_spaces(input: impl Iterator) -> usize { // Move until we don't see any more whitespace. input.take_while(|c| CharKind::new(*c) == CharKind::Space).count() @@ -84,15 +76,9 @@ impl Input { input.take_while(|c| CharKind::new(*c) == CharKind::new(prev)).count() } - if skip_whitespace_first { - let spaces_count = count_spaces(input.clone()); - let character_count = count_characters(input.skip(spaces_count).peekable()); - spaces_count + character_count - } else { - let character_count = count_characters(input.clone().peekable()); - let spaces_count = count_spaces(input.skip(character_count)); - spaces_count + character_count - } + let spaces_count = count_spaces(input.clone()); + let character_count = count_characters(input.skip(spaces_count).peekable()); + spaces_count + character_count } fn delete_range(&mut self, range: impl RangeBounds) { @@ -127,8 +113,20 @@ impl Input { Key { code: C('f'), shift: false, ctrl: true, alt: false } => self.move_(1), Key { code: C('h'), shift: false, ctrl: true, alt: false } => self.backspace(), Key { code: C('d'), shift: false, ctrl: true, alt: false } => self.forward_delete(), - Key { code: C('b'), shift: false, ctrl: false, alt: true } => self.backward(()), - Key { code: C('f'), shift: false, ctrl: false, alt: true } => self.forward(false), + Key { code: C('b'), shift: false, ctrl: false, alt: true } => { + let snap = self.snap(); + let idx = snap.idx(snap.cursor).unwrap_or(snap.len()); + + let step = Self::find_word_boundary(snap.value[..idx].chars().rev()); + self.move_(-(step as isize)) + } + Key { code: C('f'), shift: false, ctrl: false, alt: true } => { + let snap = self.snap(); + let idx = snap.idx(snap.cursor).unwrap_or(snap.len()); + + let step = Self::find_word_boundary(snap.value[idx..].chars()); + self.move_(step as isize) + } Key { code: C('u'), shift: false, ctrl: true, alt: false } => { let snap = self.snap_mut(); let end = snap.idx(snap.cursor).unwrap_or(snap.len()); @@ -146,7 +144,7 @@ impl Input { | Key { code: Backspace, shift: false, ctrl: false, alt: true } => { let snap = self.snap_mut(); let end = snap.idx(snap.cursor).unwrap_or(snap.len()); - let start = end - Self::find_word_boundary(snap.value[..end].chars().rev(), false, false); + let start = end - Self::find_word_boundary(snap.value[..end].chars().rev()); self.delete_range(start..end); true } @@ -154,7 +152,7 @@ impl Input { let snap = self.snap_mut(); let start = snap.idx(snap.cursor).unwrap_or(snap.len()); // Hitting this keybind `ab |cd `should give `|cd`. - let end = start + Self::find_word_boundary(snap.value[start..].chars(), false, false); + let end = start + Self::find_word_boundary(snap.value[start..].chars()); self.delete_range(start..end); true }