806 lines
22 KiB
Rust
806 lines
22 KiB
Rust
use crate::{
|
|
motion::Motion,
|
|
state::{Mode, Operator},
|
|
Vim,
|
|
};
|
|
use editor::Bias;
|
|
use gpui::MutableAppContext;
|
|
use language::SelectionGoal;
|
|
|
|
pub fn normal_motion(motion: Motion, cx: &mut MutableAppContext) {
|
|
Vim::update(cx, |vim, cx| {
|
|
match vim.state.operator_stack.pop() {
|
|
None => move_cursor(vim, motion, cx),
|
|
Some(Operator::Change) => change_over(vim, motion, cx),
|
|
Some(Operator::Delete) => delete_over(vim, motion, cx),
|
|
Some(Operator::Namespace(_)) => {
|
|
// Can't do anything for a namespace operator. Ignoring
|
|
}
|
|
}
|
|
vim.clear_operator(cx);
|
|
});
|
|
}
|
|
|
|
fn move_cursor(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
|
|
vim.update_active_editor(cx, |editor, cx| {
|
|
editor.move_cursors(cx, |map, cursor, goal| {
|
|
motion.move_point(map, cursor, goal, true)
|
|
})
|
|
});
|
|
}
|
|
|
|
fn change_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
|
|
vim.update_active_editor(cx, |editor, cx| {
|
|
editor.transact(cx, |editor, cx| {
|
|
// Don't clip at line ends during change operation
|
|
editor.set_clip_at_line_ends(false, cx);
|
|
editor.move_selections(cx, |map, selection| {
|
|
let (head, goal) = motion.move_point(map, selection.head(), selection.goal, false);
|
|
selection.set_head(head, goal);
|
|
|
|
if motion.line_wise() {
|
|
selection.start = map.prev_line_boundary(selection.start.to_point(map)).1;
|
|
selection.end = map.next_line_boundary(selection.end.to_point(map)).1;
|
|
}
|
|
});
|
|
editor.set_clip_at_line_ends(true, cx);
|
|
editor.insert(&"", cx);
|
|
});
|
|
});
|
|
vim.switch_mode(Mode::Insert, cx)
|
|
}
|
|
|
|
fn delete_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
|
|
vim.update_active_editor(cx, |editor, cx| {
|
|
editor.transact(cx, |editor, cx| {
|
|
// Use goal column to preserve previous position
|
|
editor.set_clip_at_line_ends(false, cx);
|
|
editor.move_selections(cx, |map, selection| {
|
|
let original_head = selection.head();
|
|
let (head, _) = motion.move_point(map, selection.head(), selection.goal, false);
|
|
// Set the goal column to the original position in order to fix it up
|
|
// after the deletion
|
|
selection.set_head(head, SelectionGoal::Column(original_head.column()));
|
|
|
|
if motion.line_wise() {
|
|
if selection.end.row() == map.max_point().row() {
|
|
// Delete previous line break since we are at the end of the document
|
|
if selection.start.row() > 0 {
|
|
*selection.start.row_mut() = selection.start.row().saturating_sub(1);
|
|
selection.start = map.clip_point(selection.start, Bias::Left);
|
|
selection.start =
|
|
map.next_line_boundary(selection.start.to_point(map)).1;
|
|
} else {
|
|
// Selection covers the whole document. Just delete to the start of the
|
|
// line.
|
|
selection.start =
|
|
map.prev_line_boundary(selection.start.to_point(map)).1;
|
|
}
|
|
selection.end = map.next_line_boundary(selection.end.to_point(map)).1;
|
|
} else {
|
|
// Delete next line break so that we leave the previous line alone
|
|
selection.start = map.prev_line_boundary(selection.start.to_point(map)).1;
|
|
*selection.end.column_mut() = 0;
|
|
*selection.end.row_mut() += 1;
|
|
selection.end = map.clip_point(selection.end, Bias::Left);
|
|
}
|
|
}
|
|
});
|
|
editor.insert(&"", cx);
|
|
|
|
// Fixup cursor position after the deletion
|
|
editor.set_clip_at_line_ends(true, cx);
|
|
editor.move_cursors(cx, |map, mut cursor, goal| {
|
|
if motion.line_wise() {
|
|
if let SelectionGoal::Column(column) = goal {
|
|
*cursor.column_mut() = column
|
|
}
|
|
}
|
|
(map.clip_point(cursor, Bias::Left), SelectionGoal::None)
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use indoc::indoc;
|
|
use util::test::marked_text;
|
|
|
|
use crate::{
|
|
state::{
|
|
Mode::{self, *},
|
|
Namespace, Operator,
|
|
},
|
|
vim_test_context::VimTestContext,
|
|
};
|
|
|
|
#[gpui::test]
|
|
async fn test_hjkl(cx: &mut gpui::TestAppContext) {
|
|
let mut cx = VimTestContext::new(cx, true, "Test\nTestTest\nTest").await;
|
|
cx.simulate_keystroke("l");
|
|
cx.assert_editor_state(indoc! {"
|
|
T|est
|
|
TestTest
|
|
Test"});
|
|
cx.simulate_keystroke("h");
|
|
cx.assert_editor_state(indoc! {"
|
|
|Test
|
|
TestTest
|
|
Test"});
|
|
cx.simulate_keystroke("j");
|
|
cx.assert_editor_state(indoc! {"
|
|
Test
|
|
|TestTest
|
|
Test"});
|
|
cx.simulate_keystroke("k");
|
|
cx.assert_editor_state(indoc! {"
|
|
|Test
|
|
TestTest
|
|
Test"});
|
|
cx.simulate_keystroke("j");
|
|
cx.assert_editor_state(indoc! {"
|
|
Test
|
|
|TestTest
|
|
Test"});
|
|
|
|
// When moving left, cursor does not wrap to the previous line
|
|
cx.simulate_keystroke("h");
|
|
cx.assert_editor_state(indoc! {"
|
|
Test
|
|
|TestTest
|
|
Test"});
|
|
|
|
// When moving right, cursor does not reach the line end or wrap to the next line
|
|
for _ in 0..9 {
|
|
cx.simulate_keystroke("l");
|
|
}
|
|
cx.assert_editor_state(indoc! {"
|
|
Test
|
|
TestTes|t
|
|
Test"});
|
|
|
|
// Goal column respects the inability to reach the end of the line
|
|
cx.simulate_keystroke("k");
|
|
cx.assert_editor_state(indoc! {"
|
|
Tes|t
|
|
TestTest
|
|
Test"});
|
|
cx.simulate_keystroke("j");
|
|
cx.assert_editor_state(indoc! {"
|
|
Test
|
|
TestTes|t
|
|
Test"});
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_jump_to_line_boundaries(cx: &mut gpui::TestAppContext) {
|
|
let initial_content = indoc! {"
|
|
Test Test
|
|
|
|
T"};
|
|
let mut cx = VimTestContext::new(cx, true, initial_content).await;
|
|
|
|
cx.simulate_keystroke("shift-$");
|
|
cx.assert_editor_state(indoc! {"
|
|
Test Tes|t
|
|
|
|
T"});
|
|
cx.simulate_keystroke("0");
|
|
cx.assert_editor_state(indoc! {"
|
|
|Test Test
|
|
|
|
T"});
|
|
|
|
cx.simulate_keystroke("j");
|
|
cx.simulate_keystroke("shift-$");
|
|
cx.assert_editor_state(indoc! {"
|
|
Test Test
|
|
|
|
|
T"});
|
|
cx.simulate_keystroke("0");
|
|
cx.assert_editor_state(indoc! {"
|
|
Test Test
|
|
|
|
|
T"});
|
|
|
|
cx.simulate_keystroke("j");
|
|
cx.simulate_keystroke("shift-$");
|
|
cx.assert_editor_state(indoc! {"
|
|
Test Test
|
|
|
|
|T"});
|
|
cx.simulate_keystroke("0");
|
|
cx.assert_editor_state(indoc! {"
|
|
Test Test
|
|
|
|
|T"});
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_jump_to_end(cx: &mut gpui::TestAppContext) {
|
|
let mut cx = VimTestContext::new(cx, true, "").await;
|
|
|
|
cx.set_state(
|
|
indoc! {"
|
|
The |quick
|
|
|
|
brown fox jumps
|
|
over the lazy dog"},
|
|
Mode::Normal,
|
|
);
|
|
cx.simulate_keystroke("shift-G");
|
|
cx.assert_editor_state(indoc! {"
|
|
The quick
|
|
|
|
brown fox jumps
|
|
over| the lazy dog"});
|
|
|
|
// Repeat the action doesn't move
|
|
cx.simulate_keystroke("shift-G");
|
|
cx.assert_editor_state(indoc! {"
|
|
The quick
|
|
|
|
brown fox jumps
|
|
over| the lazy dog"});
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_next_word_start(cx: &mut gpui::TestAppContext) {
|
|
let (initial_content, cursor_offsets) = marked_text(indoc! {"
|
|
The |quick|-|brown
|
|
|
|
|
|
|
|
|fox_jumps |over
|
|
|th||e"});
|
|
let mut cx = VimTestContext::new(cx, true, &initial_content).await;
|
|
|
|
for cursor_offset in cursor_offsets {
|
|
cx.simulate_keystroke("w");
|
|
cx.assert_newest_selection_head_offset(cursor_offset);
|
|
}
|
|
|
|
// Reset and test ignoring punctuation
|
|
cx.simulate_keystrokes(["g", "g", "0"]);
|
|
let (_, cursor_offsets) = marked_text(indoc! {"
|
|
The |quick-brown
|
|
|
|
|
|
|
|
|fox_jumps |over
|
|
|th||e"});
|
|
|
|
for cursor_offset in cursor_offsets {
|
|
cx.simulate_keystroke("shift-W");
|
|
cx.assert_newest_selection_head_offset(cursor_offset);
|
|
}
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_next_word_end(cx: &mut gpui::TestAppContext) {
|
|
let (initial_content, cursor_offsets) = marked_text(indoc! {"
|
|
Th|e quic|k|-brow|n
|
|
|
|
|
|
fox_jump|s ove|r
|
|
th|e"});
|
|
let mut cx = VimTestContext::new(cx, true, &initial_content).await;
|
|
|
|
for cursor_offset in cursor_offsets {
|
|
cx.simulate_keystroke("e");
|
|
cx.assert_newest_selection_head_offset(cursor_offset);
|
|
}
|
|
|
|
// Reset and test ignoring punctuation
|
|
cx.simulate_keystrokes(["g", "g", "0"]);
|
|
let (_, cursor_offsets) = marked_text(indoc! {"
|
|
Th|e quick-brow|n
|
|
|
|
|
|
fox_jump|s ove|r
|
|
th||e"});
|
|
for cursor_offset in cursor_offsets {
|
|
cx.simulate_keystroke("shift-E");
|
|
cx.assert_newest_selection_head_offset(cursor_offset);
|
|
}
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_previous_word_start(cx: &mut gpui::TestAppContext) {
|
|
let (initial_content, cursor_offsets) = marked_text(indoc! {"
|
|
||The |quick|-|brown
|
|
|
|
|
|
|
|
|fox_jumps |over
|
|
|the"});
|
|
let mut cx = VimTestContext::new(cx, true, &initial_content).await;
|
|
cx.simulate_keystrokes(["shift-G", "shift-$"]);
|
|
|
|
for cursor_offset in cursor_offsets.into_iter().rev() {
|
|
cx.simulate_keystroke("b");
|
|
cx.assert_newest_selection_head_offset(cursor_offset);
|
|
}
|
|
|
|
// Reset and test ignoring punctuation
|
|
cx.simulate_keystrokes(["shift-G", "shift-$"]);
|
|
let (_, cursor_offsets) = marked_text(indoc! {"
|
|
||The |quick-brown
|
|
|
|
|
|
|
|
|fox_jumps |over
|
|
|the"});
|
|
for cursor_offset in cursor_offsets.into_iter().rev() {
|
|
cx.simulate_keystroke("shift-B");
|
|
cx.assert_newest_selection_head_offset(cursor_offset);
|
|
}
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_g_prefix_and_abort(cx: &mut gpui::TestAppContext) {
|
|
let mut cx = VimTestContext::new(cx, true, "").await;
|
|
|
|
// Can abort with escape to get back to normal mode
|
|
cx.simulate_keystroke("g");
|
|
assert_eq!(cx.mode(), Normal);
|
|
assert_eq!(
|
|
cx.active_operator(),
|
|
Some(Operator::Namespace(Namespace::G))
|
|
);
|
|
cx.simulate_keystroke("escape");
|
|
assert_eq!(cx.mode(), Normal);
|
|
assert_eq!(cx.active_operator(), None);
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_move_to_start(cx: &mut gpui::TestAppContext) {
|
|
let mut cx = VimTestContext::new(cx, true, "").await;
|
|
|
|
cx.set_state(
|
|
indoc! {"
|
|
The q|uick
|
|
|
|
brown fox jumps
|
|
over the lazy dog"},
|
|
Mode::Normal,
|
|
);
|
|
|
|
// Jump to the end to
|
|
cx.simulate_keystroke("shift-G");
|
|
cx.assert_editor_state(indoc! {"
|
|
The quick
|
|
|
|
brown fox jumps
|
|
over |the lazy dog"});
|
|
|
|
// Jump to the start
|
|
cx.simulate_keystrokes(["g", "g"]);
|
|
cx.assert_editor_state(indoc! {"
|
|
The q|uick
|
|
|
|
brown fox jumps
|
|
over the lazy dog"});
|
|
assert_eq!(cx.mode(), Normal);
|
|
assert_eq!(cx.active_operator(), None);
|
|
|
|
// Repeat action doesn't change
|
|
cx.simulate_keystrokes(["g", "g"]);
|
|
cx.assert_editor_state(indoc! {"
|
|
The q|uick
|
|
|
|
brown fox jumps
|
|
over the lazy dog"});
|
|
assert_eq!(cx.mode(), Normal);
|
|
assert_eq!(cx.active_operator(), None);
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_change(cx: &mut gpui::TestAppContext) {
|
|
fn assert(motion: &str, initial_state: &str, state_after: &str, cx: &mut VimTestContext) {
|
|
cx.assert_binding(
|
|
["c", motion],
|
|
initial_state,
|
|
Mode::Normal,
|
|
state_after,
|
|
Mode::Insert,
|
|
);
|
|
}
|
|
let cx = &mut VimTestContext::new(cx, true, "").await;
|
|
assert("h", "Te|st", "T|st", cx);
|
|
assert("l", "Te|st", "Te|t", cx);
|
|
assert("w", "|Test", "|", cx);
|
|
assert("w", "Te|st", "Te|", cx);
|
|
assert("w", "Te|st Test", "Te| Test", cx);
|
|
assert("e", "Te|st Test", "Te| Test", cx);
|
|
assert("b", "Te|st", "|st", cx);
|
|
assert("b", "Test Te|st", "Test |st", cx);
|
|
assert(
|
|
"w",
|
|
indoc! {"
|
|
The quick
|
|
brown |fox
|
|
jumps over"},
|
|
indoc! {"
|
|
The quick
|
|
brown |
|
|
jumps over"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"shift-W",
|
|
indoc! {"
|
|
The quick
|
|
brown |fox-fox
|
|
jumps over"},
|
|
indoc! {"
|
|
The quick
|
|
brown |
|
|
jumps over"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"k",
|
|
indoc! {"
|
|
The quick
|
|
brown |fox"},
|
|
indoc! {"
|
|
|"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"j",
|
|
indoc! {"
|
|
The q|uick
|
|
brown fox"},
|
|
indoc! {"
|
|
|"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"shift-$",
|
|
indoc! {"
|
|
The q|uick
|
|
brown fox"},
|
|
indoc! {"
|
|
The q|
|
|
brown fox"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"0",
|
|
indoc! {"
|
|
The q|uick
|
|
brown fox"},
|
|
indoc! {"
|
|
|uick
|
|
brown fox"},
|
|
cx,
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_delete(cx: &mut gpui::TestAppContext) {
|
|
fn assert(motion: &str, initial_state: &str, state_after: &str, cx: &mut VimTestContext) {
|
|
cx.assert_binding(
|
|
["d", motion],
|
|
initial_state,
|
|
Mode::Normal,
|
|
state_after,
|
|
Mode::Normal,
|
|
);
|
|
}
|
|
let cx = &mut VimTestContext::new(cx, true, "").await;
|
|
assert("h", "Te|st", "T|st", cx);
|
|
assert("l", "Te|st", "Te|t", cx);
|
|
assert("w", "|Test", "|", cx);
|
|
assert("w", "Te|st", "T|e", cx);
|
|
assert("w", "Te|st Test", "Te|Test", cx);
|
|
assert("e", "Te|st Test", "Te| Test", cx);
|
|
assert("b", "Te|st", "|st", cx);
|
|
assert("b", "Test Te|st", "Test |st", cx);
|
|
assert(
|
|
"w",
|
|
indoc! {"
|
|
The quick
|
|
brown |fox
|
|
jumps over"},
|
|
// Trailing space after cursor
|
|
indoc! {"
|
|
The quick
|
|
brown|
|
|
jumps over"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"shift-W",
|
|
indoc! {"
|
|
The quick
|
|
brown |fox-fox
|
|
jumps over"},
|
|
// Trailing space after cursor
|
|
indoc! {"
|
|
The quick
|
|
brown|
|
|
jumps over"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"shift-$",
|
|
indoc! {"
|
|
The q|uick
|
|
brown fox"},
|
|
indoc! {"
|
|
The |q
|
|
brown fox"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"0",
|
|
indoc! {"
|
|
The q|uick
|
|
brown fox"},
|
|
indoc! {"
|
|
|uick
|
|
brown fox"},
|
|
cx,
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_linewise_delete(cx: &mut gpui::TestAppContext) {
|
|
fn assert(motion: &str, initial_state: &str, state_after: &str, cx: &mut VimTestContext) {
|
|
cx.assert_binding(
|
|
["d", motion],
|
|
initial_state,
|
|
Mode::Normal,
|
|
state_after,
|
|
Mode::Normal,
|
|
);
|
|
}
|
|
let cx = &mut VimTestContext::new(cx, true, "").await;
|
|
assert(
|
|
"k",
|
|
indoc! {"
|
|
The quick
|
|
brown |fox
|
|
jumps over"},
|
|
indoc! {"
|
|
jumps |over"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"k",
|
|
indoc! {"
|
|
The quick
|
|
brown fox
|
|
jumps |over"},
|
|
indoc! {"
|
|
The qu|ick"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"j",
|
|
indoc! {"
|
|
The q|uick
|
|
brown fox
|
|
jumps over"},
|
|
indoc! {"
|
|
jumps| over"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"j",
|
|
indoc! {"
|
|
The quick
|
|
brown| fox
|
|
jumps over"},
|
|
indoc! {"
|
|
The q|uick"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"j",
|
|
indoc! {"
|
|
The quick
|
|
brown| fox
|
|
jumps over"},
|
|
indoc! {"
|
|
The q|uick"},
|
|
cx,
|
|
);
|
|
cx.assert_binding(
|
|
["d", "g", "g"],
|
|
indoc! {"
|
|
The quick
|
|
brown| fox
|
|
jumps over
|
|
the lazy"},
|
|
Mode::Normal,
|
|
indoc! {"
|
|
jumps| over
|
|
the lazy"},
|
|
Mode::Normal,
|
|
);
|
|
cx.assert_binding(
|
|
["d", "g", "g"],
|
|
indoc! {"
|
|
The quick
|
|
brown fox
|
|
jumps over
|
|
the l|azy"},
|
|
Mode::Normal,
|
|
"|",
|
|
Mode::Normal,
|
|
);
|
|
assert(
|
|
"shift-G",
|
|
indoc! {"
|
|
The quick
|
|
brown| fox
|
|
jumps over
|
|
the lazy"},
|
|
indoc! {"
|
|
The q|uick"},
|
|
cx,
|
|
);
|
|
cx.assert_binding(
|
|
["d", "g", "g"],
|
|
indoc! {"
|
|
The q|uick
|
|
brown fox
|
|
jumps over
|
|
the lazy"},
|
|
Mode::Normal,
|
|
indoc! {"
|
|
brown| fox
|
|
jumps over
|
|
the lazy"},
|
|
Mode::Normal,
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_linewise_change(cx: &mut gpui::TestAppContext) {
|
|
fn assert(motion: &str, initial_state: &str, state_after: &str, cx: &mut VimTestContext) {
|
|
cx.assert_binding(
|
|
["c", motion],
|
|
initial_state,
|
|
Mode::Normal,
|
|
state_after,
|
|
Mode::Insert,
|
|
);
|
|
}
|
|
let cx = &mut VimTestContext::new(cx, true, "").await;
|
|
assert(
|
|
"k",
|
|
indoc! {"
|
|
The quick
|
|
brown |fox
|
|
jumps over"},
|
|
indoc! {"
|
|
|
|
|
jumps over"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"k",
|
|
indoc! {"
|
|
The quick
|
|
brown fox
|
|
jumps |over"},
|
|
indoc! {"
|
|
The quick
|
|
|"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"j",
|
|
indoc! {"
|
|
The q|uick
|
|
brown fox
|
|
jumps over"},
|
|
indoc! {"
|
|
|
|
|
jumps over"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"j",
|
|
indoc! {"
|
|
The quick
|
|
brown| fox
|
|
jumps over"},
|
|
indoc! {"
|
|
The quick
|
|
|"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"j",
|
|
indoc! {"
|
|
The quick
|
|
brown| fox
|
|
jumps over"},
|
|
indoc! {"
|
|
The quick
|
|
|"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"shift-G",
|
|
indoc! {"
|
|
The quick
|
|
brown| fox
|
|
jumps over
|
|
the lazy"},
|
|
indoc! {"
|
|
The quick
|
|
|"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"shift-G",
|
|
indoc! {"
|
|
The quick
|
|
brown| fox
|
|
jumps over
|
|
the lazy"},
|
|
indoc! {"
|
|
The quick
|
|
|"},
|
|
cx,
|
|
);
|
|
assert(
|
|
"shift-G",
|
|
indoc! {"
|
|
The quick
|
|
brown fox
|
|
jumps over
|
|
the l|azy"},
|
|
indoc! {"
|
|
The quick
|
|
brown fox
|
|
jumps over
|
|
|"},
|
|
cx,
|
|
);
|
|
cx.assert_binding(
|
|
["c", "g", "g"],
|
|
indoc! {"
|
|
The quick
|
|
brown| fox
|
|
jumps over
|
|
the lazy"},
|
|
Mode::Normal,
|
|
indoc! {"
|
|
|
|
|
jumps over
|
|
the lazy"},
|
|
Mode::Insert,
|
|
);
|
|
cx.assert_binding(
|
|
["c", "g", "g"],
|
|
indoc! {"
|
|
The quick
|
|
brown fox
|
|
jumps over
|
|
the l|azy"},
|
|
Mode::Normal,
|
|
"|",
|
|
Mode::Insert,
|
|
);
|
|
cx.assert_binding(
|
|
["c", "g", "g"],
|
|
indoc! {"
|
|
The q|uick
|
|
brown fox
|
|
jumps over
|
|
the lazy"},
|
|
Mode::Normal,
|
|
indoc! {"
|
|
|
|
|
brown fox
|
|
jumps over
|
|
the lazy"},
|
|
Mode::Insert,
|
|
);
|
|
}
|
|
}
|