add move_prev_long_word_end and extend_prev_long_word_end (#6905)
This commit is contained in:
parent
2f9b63999f
commit
352d1574a6
2 changed files with 114 additions and 3 deletions
|
@ -177,6 +177,10 @@ pub fn move_prev_word_start(slice: RopeSlice, range: Range, count: usize) -> Ran
|
|||
word_move(slice, range, count, WordMotionTarget::PrevWordStart)
|
||||
}
|
||||
|
||||
pub fn move_prev_word_end(slice: RopeSlice, range: Range, count: usize) -> Range {
|
||||
word_move(slice, range, count, WordMotionTarget::PrevWordEnd)
|
||||
}
|
||||
|
||||
pub fn move_next_long_word_start(slice: RopeSlice, range: Range, count: usize) -> Range {
|
||||
word_move(slice, range, count, WordMotionTarget::NextLongWordStart)
|
||||
}
|
||||
|
@ -189,8 +193,8 @@ pub fn move_prev_long_word_start(slice: RopeSlice, range: Range, count: usize) -
|
|||
word_move(slice, range, count, WordMotionTarget::PrevLongWordStart)
|
||||
}
|
||||
|
||||
pub fn move_prev_word_end(slice: RopeSlice, range: Range, count: usize) -> Range {
|
||||
word_move(slice, range, count, WordMotionTarget::PrevWordEnd)
|
||||
pub fn move_prev_long_word_end(slice: RopeSlice, range: Range, count: usize) -> Range {
|
||||
word_move(slice, range, count, WordMotionTarget::PrevLongWordEnd)
|
||||
}
|
||||
|
||||
fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTarget) -> Range {
|
||||
|
@ -199,6 +203,7 @@ fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTar
|
|||
WordMotionTarget::PrevWordStart
|
||||
| WordMotionTarget::PrevLongWordStart
|
||||
| WordMotionTarget::PrevWordEnd
|
||||
| WordMotionTarget::PrevLongWordEnd
|
||||
);
|
||||
|
||||
// Special-case early-out.
|
||||
|
@ -377,6 +382,7 @@ pub enum WordMotionTarget {
|
|||
NextLongWordStart,
|
||||
NextLongWordEnd,
|
||||
PrevLongWordStart,
|
||||
PrevLongWordEnd,
|
||||
}
|
||||
|
||||
pub trait CharHelpers {
|
||||
|
@ -393,6 +399,7 @@ impl CharHelpers for Chars<'_> {
|
|||
WordMotionTarget::PrevWordStart
|
||||
| WordMotionTarget::PrevLongWordStart
|
||||
| WordMotionTarget::PrevWordEnd
|
||||
| WordMotionTarget::PrevLongWordEnd
|
||||
);
|
||||
|
||||
// Reverse the iterator if needed for the motion direction.
|
||||
|
@ -479,7 +486,7 @@ fn reached_target(target: WordMotionTarget, prev_ch: char, next_ch: char) -> boo
|
|||
is_word_boundary(prev_ch, next_ch)
|
||||
&& (!prev_ch.is_whitespace() || char_is_line_ending(next_ch))
|
||||
}
|
||||
WordMotionTarget::NextLongWordStart => {
|
||||
WordMotionTarget::NextLongWordStart | WordMotionTarget::PrevLongWordEnd => {
|
||||
is_long_word_boundary(prev_ch, next_ch)
|
||||
&& (char_is_line_ending(next_ch) || !next_ch.is_whitespace())
|
||||
}
|
||||
|
@ -1445,6 +1452,100 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behaviour_when_moving_to_end_of_prev_long_words() {
|
||||
let tests = [
|
||||
(
|
||||
"Basic backward motion from the middle of a word",
|
||||
vec![(1, Range::new(3, 3), Range::new(4, 0))],
|
||||
),
|
||||
("Starting from after boundary retreats the anchor",
|
||||
vec![(1, Range::new(0, 9), Range::new(8, 0))],
|
||||
),
|
||||
(
|
||||
"Jump to end of a word succeeded by whitespace",
|
||||
vec![(1, Range::new(10, 10), Range::new(10, 4))],
|
||||
),
|
||||
(
|
||||
" Jump to start of line from end of word preceded by whitespace",
|
||||
vec![(1, Range::new(3, 4), Range::new(4, 0))],
|
||||
),
|
||||
("Previous anchor is irrelevant for backward motions",
|
||||
vec![(1, Range::new(12, 5), Range::new(6, 0))]),
|
||||
(
|
||||
" Starting from whitespace moves to first space in sequence",
|
||||
vec![(1, Range::new(0, 4), Range::new(4, 0))],
|
||||
),
|
||||
("Identifiers_with_underscores are considered a single word",
|
||||
vec![(1, Range::new(0, 20), Range::new(20, 0))]),
|
||||
(
|
||||
"Jumping\n \nback through a newline selects whitespace",
|
||||
vec![(1, Range::new(0, 13), Range::new(12, 8))],
|
||||
),
|
||||
(
|
||||
"Jumping to start of word from the end selects the word",
|
||||
vec![(1, Range::new(6, 7), Range::new(7, 0))],
|
||||
),
|
||||
(
|
||||
"alphanumeric.!,and.?=punctuation are treated exactly the same",
|
||||
vec![(1, Range::new(29, 30), Range::new(30, 0))],
|
||||
),
|
||||
(
|
||||
"... ... punctuation and spaces behave as expected",
|
||||
vec![
|
||||
(1, Range::new(0, 10), Range::new(9, 3)),
|
||||
(1, Range::new(10, 6), Range::new(7, 3)),
|
||||
],
|
||||
),
|
||||
(".._.._ punctuation is joined by underscores into a single block",
|
||||
vec![(1, Range::new(0, 6), Range::new(6, 0))]),
|
||||
(
|
||||
"Newlines\n\nare bridged seamlessly.",
|
||||
vec![(1, Range::new(0, 10), Range::new(8, 0))],
|
||||
),
|
||||
(
|
||||
"Jumping \n\n\n\n\nback from within a newline group selects previous block",
|
||||
vec![(1, Range::new(0, 13), Range::new(11, 7))],
|
||||
),
|
||||
(
|
||||
"Failed motions do not modify the range",
|
||||
vec![(0, Range::new(3, 0), Range::new(3, 0))],
|
||||
),
|
||||
(
|
||||
"Multiple motions at once resolve correctly",
|
||||
vec![(3, Range::new(19, 19), Range::new(8, 0))],
|
||||
),
|
||||
(
|
||||
"Excessive motions are performed partially",
|
||||
vec![(999, Range::new(40, 40), Range::new(9, 0))],
|
||||
),
|
||||
(
|
||||
"", // Edge case of moving backwards in empty string
|
||||
vec![(1, Range::new(0, 0), Range::new(0, 0))],
|
||||
),
|
||||
(
|
||||
"\n\n\n\n\n", // Edge case of moving backwards in all newlines
|
||||
vec![(1, Range::new(5, 5), Range::new(0, 0))],
|
||||
),
|
||||
(" \n \nJumping back through alternated space blocks and newlines selects the space blocks",
|
||||
vec![
|
||||
(1, Range::new(0, 8), Range::new(7, 4)),
|
||||
(1, Range::new(7, 4), Range::new(3, 0)),
|
||||
]),
|
||||
("ヒーリ..クス multibyte characters behave as normal characters, including when interacting with punctuation",
|
||||
vec![
|
||||
(1, Range::new(0, 8), Range::new(7, 0)),
|
||||
]),
|
||||
];
|
||||
|
||||
for (sample, scenario) in tests {
|
||||
for (count, begin, expected_end) in scenario.into_iter() {
|
||||
let range = move_prev_long_word_end(Rope::from(sample).slice(..), begin, count);
|
||||
assert_eq!(range, expected_end, "Case failed: [{}]", sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_behaviour_when_moving_to_prev_paragraph_single() {
|
||||
let tests = [
|
||||
|
|
|
@ -247,6 +247,7 @@ impl MappableCommand {
|
|||
move_next_long_word_start, "Move to start of next long word",
|
||||
move_prev_long_word_start, "Move to start of previous long word",
|
||||
move_next_long_word_end, "Move to end of next long word",
|
||||
move_prev_long_word_end, "Move to end of previous long word",
|
||||
extend_next_word_start, "Extend to start of next word",
|
||||
extend_prev_word_start, "Extend to start of previous word",
|
||||
extend_next_word_end, "Extend to end of next word",
|
||||
|
@ -254,6 +255,7 @@ impl MappableCommand {
|
|||
extend_next_long_word_start, "Extend to start of next long word",
|
||||
extend_prev_long_word_start, "Extend to start of previous long word",
|
||||
extend_next_long_word_end, "Extend to end of next long word",
|
||||
extend_prev_long_word_end, "Extend to end of prev long word",
|
||||
find_till_char, "Move till next occurrence of char",
|
||||
find_next_char, "Move to next occurrence of char",
|
||||
extend_till_char, "Extend till next occurrence of char",
|
||||
|
@ -1067,6 +1069,10 @@ fn move_prev_long_word_start(cx: &mut Context) {
|
|||
move_word_impl(cx, movement::move_prev_long_word_start)
|
||||
}
|
||||
|
||||
fn move_prev_long_word_end(cx: &mut Context) {
|
||||
move_word_impl(cx, movement::move_prev_long_word_end)
|
||||
}
|
||||
|
||||
fn move_next_long_word_end(cx: &mut Context) {
|
||||
move_word_impl(cx, movement::move_next_long_word_end)
|
||||
}
|
||||
|
@ -1224,6 +1230,10 @@ fn extend_prev_long_word_start(cx: &mut Context) {
|
|||
extend_word_impl(cx, movement::move_prev_long_word_start)
|
||||
}
|
||||
|
||||
fn extend_prev_long_word_end(cx: &mut Context) {
|
||||
extend_word_impl(cx, movement::move_prev_long_word_end)
|
||||
}
|
||||
|
||||
fn extend_next_long_word_end(cx: &mut Context) {
|
||||
extend_word_impl(cx, movement::move_next_long_word_end)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue