separate vim and emacs logic (find_word_boundary)

This commit is contained in:
Francis Chua 2023-11-12 18:04:52 +00:00
parent c60ba82699
commit 0bdb52fd1b
3 changed files with 61 additions and 33 deletions

View file

@ -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<Opt>) -> 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
}
}

View file

@ -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)
}
}

View file

@ -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<Item = char> + 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<Item = char> + Clone) -> usize {
fn count_spaces(input: impl Iterator<Item = char>) -> 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
}
}
fn delete_range(&mut self, range: impl RangeBounds<usize>) {
@ -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
}