diff --git a/yazi-core/src/input/commands/backward.rs b/yazi-core/src/input/commands/backward.rs index 55f88de2..4105e414 100644 --- a/yazi-core/src/input/commands/backward.rs +++ b/yazi-core/src/input/commands/backward.rs @@ -8,9 +8,6 @@ pub struct Opt; impl From<&Exec> for Opt { fn from(_: &Exec) -> Self { Self } } -impl From<()> for Opt { - fn from(_: ()) -> Self { Self } -} impl Input { pub fn backward(&mut self, _: impl Into) -> bool { diff --git a/yazi-core/src/input/commands/forward.rs b/yazi-core/src/input/commands/forward.rs index 3666dc56..55cd685e 100644 --- a/yazi-core/src/input/commands/forward.rs +++ b/yazi-core/src/input/commands/forward.rs @@ -10,9 +10,6 @@ pub struct Opt { impl From<&Exec> for Opt { fn from(e: &Exec) -> Self { Self { end_of_word: e.named.contains_key("end-of-word") } } } -impl From for Opt { - fn from(end_of_word: bool) -> Self { Self { end_of_word } } -} impl Input { pub fn forward(&mut self, opt: impl Into) -> bool { diff --git a/yazi-core/src/input/input.rs b/yazi-core/src/input/input.rs index 8ed5b381..fa3e5cca 100644 --- a/yazi-core/src/input/input.rs +++ b/yazi-core/src/input/input.rs @@ -59,37 +59,39 @@ 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) -> usize { + 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() } - fn count_characters(mut input: std::iter::Peekable>) -> usize { + fn count_characters(mut input: impl Iterator) -> usize { // Determine the current character class. - let prev = input.peek().cloned(); - let Some(prev) = prev else { - return 0; + let first = match input.next() { + Some(c) => CharKind::new(c), + None => return 0, }; // Move until we see a different character class or the end of the iterator. - input.take_while(|c| CharKind::new(*c) == CharKind::new(prev)).count() + input.take_while(|c| CharKind::new(*c) == first).count() + 1 } - let spaces_count = count_spaces(input.clone()); - let character_count = count_characters(input.skip(spaces_count).peekable()); - spaces_count + character_count + let spaces = count_spaces(input.clone()); + spaces + count_characters(input.skip(spaces)) } - fn delete_range(&mut self, range: impl RangeBounds) { + fn delete_range(&mut self, range: impl RangeBounds) -> bool { let snap = self.snap_mut(); snap.cursor = match range.start_bound() { std::ops::Bound::Included(i) => *i, std::ops::Bound::Excluded(i) => i + 1, std::ops::Bound::Unbounded => 0, }; - snap.value.drain(range); - self.flush_value(); + if snap.value.drain(range).next().is_some() { + self.flush_value(); + return true; + } + false } pub fn type_(&mut self, key: &Key) -> bool { @@ -102,17 +104,26 @@ impl Input { return self.type_str(c.encode_utf8(&mut bits)); } - use KeyCode::{Backspace, Char as C, Delete}; + use KeyCode::{Backspace, Char as C}; match key { - Key { code: Backspace, shift: false, ctrl: false, alt: false } => self.backspace(), - // Handle Emacs-style keybindings. + // Move to the start of the line Key { code: C('a'), shift: false, ctrl: true, alt: false } => self.move_(isize::MIN), + // Move to the end of the line Key { code: C('e'), shift: false, ctrl: true, alt: false } => self.move_(isize::MAX), + + // Move back a character Key { code: C('b'), shift: false, ctrl: true, alt: false } => self.move_(-1), + // Move forward a character Key { code: C('f'), shift: false, ctrl: true, alt: false } => self.move_(1), + + // Delete the character before the cursor + Key { code: Backspace, shift: false, ctrl: false, alt: false } => self.backspace(), Key { code: C('h'), shift: false, ctrl: true, alt: false } => self.backspace(), + // Delete the character under the cursor Key { code: C('d'), shift: false, ctrl: true, alt: false } => self.forward_delete(), + + // Move back to the start of the current or previous word Key { code: C('b'), shift: false, ctrl: false, alt: true } => { let snap = self.snap(); let idx = snap.idx(snap.cursor).unwrap_or(snap.len()); @@ -120,61 +131,46 @@ impl Input { let step = Self::find_word_boundary(snap.value[..idx].chars().rev()); self.move_(-(step as isize)) } + // Move forward to the end of the next word 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()); + let step = Self::find_word_boundary(snap.value.chars().skip(snap.cursor)); self.move_(step as isize) } + + // Kill backwards to the start of the line 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()); - self.delete_range(..end); - true + self.delete_range(..end) } - Key { code: C('k'), shift: false, ctrl: true, alt: false } - | Key { code: Delete, shift: false, ctrl: false, alt: false } => { + // Kill forwards to the end of the line + Key { code: C('k'), shift: false, ctrl: true, alt: false } => { let snap = self.snap_mut(); let start = snap.idx(snap.cursor).unwrap_or(snap.len()); - self.delete_range(start..); - true + self.delete_range(start..) } + + // Kill backwards to the start of the current word Key { code: C('w'), shift: false, ctrl: true, alt: false } | 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()); - self.delete_range(start..end); - true + self.delete_range(start..end) } + // Kill forwards to the end of the current word Key { code: C('d'), shift: false, ctrl: false, alt: true } => { 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()); - self.delete_range(start..end); - true + self.delete_range(start..end) } + _ => false, } } - pub fn forward_delete(&mut self) -> bool { - let snap = self.snaps.current_mut(); - // Return false when there is no character on the right to delete. - // Note that the cursor can be at index `snap.value.len()` when in - // edit mode, but it should be strictly less for forward deletion. - if snap.cursor >= snap.value.len() { - return false; - } else { - snap.value.remove(snap.idx(snap.cursor).unwrap()); - } - self.move_(0); - self.flush_value(); - true - } - pub fn type_str(&mut self, s: &str) -> bool { let snap = self.snaps.current_mut(); if snap.cursor < 1 { @@ -201,6 +197,19 @@ impl Input { true } + pub fn forward_delete(&mut self) -> bool { + let snap = self.snaps.current_mut(); + if snap.cursor >= snap.value.len() { + return false; + } else { + snap.value.remove(snap.idx(snap.cursor).unwrap()); + } + + self.move_(0); + self.flush_value(); + true + } + pub(super) fn handle_op(&mut self, cursor: usize, include: bool) -> bool { let old = self.snap().clone(); let snap = self.snaps.current_mut();