fix inconsistency with vim in moving by words

This commit is contained in:
Francis Chua 2023-11-12 00:40:27 +00:00
parent 7a6bda4787
commit 14e1494a72
3 changed files with 32 additions and 18 deletions

View file

@ -16,7 +16,7 @@ impl Input {
let snap = self.snap(); let snap = self.snap();
let idx = snap.idx(snap.cursor).unwrap_or(snap.len()); let idx = snap.idx(snap.cursor).unwrap_or(snap.len());
let step = Self::find_word_boundary(snap.value[..idx].chars().rev(), false); let step = Self::find_word_boundary(snap.value[..idx].chars().rev(), false, true);
self.move_(-(step as isize)) self.move_(-(step as isize))
} }
} }

View file

@ -20,7 +20,7 @@ impl Input {
let snap = self.snap(); let snap = self.snap();
let idx = snap.idx(snap.cursor).unwrap_or(snap.len()); let idx = snap.idx(snap.cursor).unwrap_or(snap.len());
let step = Self::find_word_boundary(snap.value[idx..].chars(), opt.end_of_word); let step = Self::find_word_boundary(snap.value[idx..].chars(), opt.end_of_word, opt.end_of_word);
self.move_(step as isize) self.move_(step as isize)
} }
} }

View file

@ -48,8 +48,10 @@ impl Input {
/// Searches for a word boundary and returns the movement in the cursor /// Searches for a word boundary and returns the movement in the cursor
/// position. /// position.
/// ///
/// A word boundary is where the [`CharKind`] changes. However, we also skip /// A word boundary is where the [`CharKind`] changes.
/// initial whitespace. ///
/// If `skip_whitespace_first` is true, we skip initial whitespace.
/// Otherwise, we skip whitespace after reaching a word boundary.
/// ///
/// If `stop_before_boundary` is true, returns how many characters the cursor /// If `stop_before_boundary` is true, returns how many characters the cursor
/// needs to move to be at the character *BEFORE* the word boundary, or until /// needs to move to be at the character *BEFORE* the word boundary, or until
@ -60,25 +62,37 @@ impl Input {
pub(super) fn find_word_boundary( pub(super) fn find_word_boundary(
input: impl Iterator<Item = char> + Clone, input: impl Iterator<Item = char> + Clone,
stop_before_boundary: bool, stop_before_boundary: bool,
skip_whitespace_first: bool,
) -> usize { ) -> usize {
// If we want the *NEXT* end of word, then we want to skip the current // If we want the *NEXT* end of word, then we want to skip the current
// character. // character.
let input = input.skip(stop_before_boundary.into()); let input = input.skip(stop_before_boundary.into());
fn count_spaces(input: impl Iterator<Item = char>) -> usize {
// Move until we don't see any more whitespace. // Move until we don't see any more whitespace.
let spaces_count = input.clone().take_while(|c| CharKind::new(*c) == CharKind::Space).count(); input.take_while(|c| CharKind::new(*c) == CharKind::Space).count()
let mut input = input.skip(spaces_count).peekable(); }
fn count_characters(mut input: std::iter::Peekable<impl Iterator<Item = char>>) -> usize {
// Determine the current character class. // Determine the current character class.
let prev = input.peek().cloned(); let prev = input.peek().cloned();
let Some(prev) = prev else { let Some(prev) = prev else {
return spaces_count; return 0;
}; };
// Move until we see a different character class or the end of the iterator. // Move until we see a different character class or the end of the iterator.
let character_count = input.take_while(|c| CharKind::new(*c) == CharKind::new(prev)).count(); 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 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>) { fn delete_range(&mut self, range: impl RangeBounds<usize>) {
@ -132,14 +146,14 @@ impl Input {
| Key { code: Backspace, shift: false, ctrl: false, alt: true } => { | Key { code: Backspace, shift: false, ctrl: false, alt: true } => {
let snap = self.snap_mut(); let snap = self.snap_mut();
let end = snap.idx(snap.cursor).unwrap_or(snap.len()); let end = snap.idx(snap.cursor).unwrap_or(snap.len());
let start = end - Self::find_word_boundary(snap.value[..end].chars().rev(), false); let start = end - Self::find_word_boundary(snap.value[..end].chars().rev(), false, false);
self.delete_range(start..end); self.delete_range(start..end);
true true
} }
Key { code: C('d'), shift: false, ctrl: false, alt: true } => { Key { code: C('d'), shift: false, ctrl: false, alt: true } => {
let snap = self.snap_mut(); let snap = self.snap_mut();
let start = snap.idx(snap.cursor).unwrap_or(snap.len()); let start = snap.idx(snap.cursor).unwrap_or(snap.len());
let end = start + Self::find_word_boundary(snap.value[start..].chars(), false); let end = start + Self::find_word_boundary(snap.value[start..].chars(), false, true);
self.delete_range(start..end); self.delete_range(start..end);
true true
} }