2022-04-21 23:14:58 +00:00
|
|
|
mod change;
|
|
|
|
mod delete;
|
|
|
|
|
|
|
|
use crate::{motion::Motion, state::Operator, Vim};
|
|
|
|
use change::init as change_init;
|
|
|
|
use gpui::{actions, MutableAppContext};
|
|
|
|
|
|
|
|
use self::{change::change_over, delete::delete_over};
|
|
|
|
|
|
|
|
actions!(vim, [InsertLineAbove, InsertLineBelow, InsertAfter]);
|
|
|
|
|
|
|
|
pub fn init(cx: &mut MutableAppContext) {
|
|
|
|
change_init(cx);
|
|
|
|
}
|
2022-03-28 00:58:28 +00:00
|
|
|
|
2022-04-15 23:00:44 +00:00
|
|
|
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),
|
2022-04-19 18:36:44 +00:00
|
|
|
Some(Operator::Namespace(_)) => {
|
|
|
|
// Can't do anything for a namespace operator. Ignoring
|
|
|
|
}
|
2022-04-15 23:00:44 +00:00
|
|
|
}
|
|
|
|
vim.clear_operator(cx);
|
2022-03-28 00:58:28 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-04-15 23:00:44 +00:00
|
|
|
fn move_cursor(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
|
|
|
|
vim.update_active_editor(cx, |editor, cx| {
|
2022-04-21 23:14:58 +00:00
|
|
|
editor.move_cursors(cx, |map, cursor, goal| motion.move_point(map, cursor, goal))
|
2022-03-28 00:58:28 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use indoc::indoc;
|
|
|
|
use util::test::marked_text;
|
|
|
|
|
2022-04-15 23:00:44 +00:00
|
|
|
use crate::{
|
|
|
|
state::{
|
|
|
|
Mode::{self, *},
|
|
|
|
Namespace, Operator,
|
|
|
|
},
|
|
|
|
vim_test_context::VimTestContext,
|
|
|
|
};
|
2022-03-28 00:58:28 +00:00
|
|
|
|
|
|
|
#[gpui::test]
|
2022-04-21 23:14:58 +00:00
|
|
|
async fn test_h(cx: &mut gpui::TestAppContext) {
|
|
|
|
let cx = VimTestContext::new(cx, true).await;
|
|
|
|
let mut cx = cx.binding(["h"]);
|
|
|
|
cx.assert("The q|uick", "The |quick");
|
|
|
|
cx.assert("|The quick", "|The quick");
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
|brown"},
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
|brown"},
|
|
|
|
);
|
|
|
|
}
|
2022-03-28 00:58:28 +00:00
|
|
|
|
2022-04-21 23:14:58 +00:00
|
|
|
#[gpui::test]
|
|
|
|
async fn test_l(cx: &mut gpui::TestAppContext) {
|
|
|
|
let cx = VimTestContext::new(cx, true).await;
|
|
|
|
let mut cx = cx.binding(["l"]);
|
|
|
|
cx.assert("The q|uick", "The qu|ick");
|
|
|
|
cx.assert("The quic|k", "The quic|k");
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The quic|k
|
|
|
|
brown"},
|
|
|
|
indoc! {"
|
|
|
|
The quic|k
|
|
|
|
brown"},
|
|
|
|
);
|
|
|
|
}
|
2022-03-28 00:58:28 +00:00
|
|
|
|
2022-04-21 23:14:58 +00:00
|
|
|
#[gpui::test]
|
|
|
|
async fn test_j(cx: &mut gpui::TestAppContext) {
|
|
|
|
let cx = VimTestContext::new(cx, true).await;
|
|
|
|
let mut cx = cx.binding(["j"]);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The |quick
|
|
|
|
brown fox"},
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
brow|n fox"},
|
|
|
|
);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
brow|n fox"},
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
brow|n fox"},
|
|
|
|
);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The quic|k
|
|
|
|
brown"},
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
brow|n"},
|
|
|
|
);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
|brown"},
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
|brown"},
|
|
|
|
);
|
|
|
|
}
|
2022-03-28 00:58:28 +00:00
|
|
|
|
2022-04-21 23:14:58 +00:00
|
|
|
#[gpui::test]
|
|
|
|
async fn test_k(cx: &mut gpui::TestAppContext) {
|
|
|
|
let cx = VimTestContext::new(cx, true).await;
|
|
|
|
let mut cx = cx.binding(["k"]);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The |quick
|
|
|
|
brown fox"},
|
|
|
|
indoc! {"
|
|
|
|
The |quick
|
|
|
|
brown fox"},
|
|
|
|
);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
brow|n fox"},
|
|
|
|
indoc! {"
|
|
|
|
The |quick
|
|
|
|
brown fox"},
|
|
|
|
);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The
|
|
|
|
quic|k"},
|
|
|
|
indoc! {"
|
|
|
|
Th|e
|
|
|
|
quick"},
|
|
|
|
);
|
2022-03-28 00:58:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[gpui::test]
|
|
|
|
async fn test_jump_to_line_boundaries(cx: &mut gpui::TestAppContext) {
|
2022-04-21 23:14:58 +00:00
|
|
|
let cx = VimTestContext::new(cx, true).await;
|
|
|
|
let mut cx = cx.binding(["shift-$"]);
|
|
|
|
cx.assert("T|est test", "Test tes|t");
|
|
|
|
cx.assert("Test tes|t", "Test tes|t");
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The |quick
|
|
|
|
brown"},
|
|
|
|
indoc! {"
|
|
|
|
The quic|k
|
|
|
|
brown"},
|
|
|
|
);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The quic|k
|
|
|
|
brown"},
|
|
|
|
indoc! {"
|
|
|
|
The quic|k
|
|
|
|
brown"},
|
|
|
|
);
|
2022-03-28 00:58:28 +00:00
|
|
|
|
2022-04-21 23:14:58 +00:00
|
|
|
let mut cx = cx.binding(["0"]);
|
|
|
|
cx.assert("Test |test", "|Test test");
|
|
|
|
cx.assert("|Test test", "|Test test");
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The |quick
|
|
|
|
brown"},
|
|
|
|
indoc! {"
|
|
|
|
|The quick
|
|
|
|
brown"},
|
|
|
|
);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
|The quick
|
|
|
|
brown"},
|
|
|
|
indoc! {"
|
|
|
|
|The quick
|
|
|
|
brown"},
|
|
|
|
);
|
2022-03-28 00:58:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[gpui::test]
|
|
|
|
async fn test_jump_to_end(cx: &mut gpui::TestAppContext) {
|
2022-04-21 23:14:58 +00:00
|
|
|
let cx = VimTestContext::new(cx, true).await;
|
|
|
|
let mut cx = cx.binding(["shift-G"]);
|
2022-04-19 18:36:44 +00:00
|
|
|
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.assert(
|
2022-04-19 18:36:44 +00:00
|
|
|
indoc! {"
|
2022-04-21 23:14:58 +00:00
|
|
|
The |quick
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over the lazy dog"},
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over| the lazy dog"},
|
2022-04-19 18:36:44 +00:00
|
|
|
);
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over| the lazy dog"},
|
|
|
|
indoc! {"
|
|
|
|
The quick
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over| the lazy dog"},
|
|
|
|
);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The qui|ck
|
|
|
|
|
|
|
|
brown"},
|
|
|
|
indoc! {"
|
2022-03-28 00:58:28 +00:00
|
|
|
The quick
|
|
|
|
|
2022-04-21 23:14:58 +00:00
|
|
|
brow|n"},
|
|
|
|
);
|
|
|
|
cx.assert(
|
|
|
|
indoc! {"
|
|
|
|
The qui|ck
|
|
|
|
|
|
|
|
"},
|
|
|
|
indoc! {"
|
2022-03-28 00:58:28 +00:00
|
|
|
The quick
|
|
|
|
|
2022-04-21 23:14:58 +00:00
|
|
|
|"},
|
|
|
|
);
|
2022-03-28 00:58:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[gpui::test]
|
|
|
|
async fn test_next_word_start(cx: &mut gpui::TestAppContext) {
|
2022-04-21 23:14:58 +00:00
|
|
|
let mut cx = VimTestContext::new(cx, true).await;
|
|
|
|
let (_, cursor_offsets) = marked_text(indoc! {"
|
2022-03-28 00:58:28 +00:00
|
|
|
The |quick|-|brown
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|fox_jumps |over
|
|
|
|
|th||e"});
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.set_state(
|
|
|
|
indoc! {"
|
|
|
|
|The quick-brown
|
|
|
|
|
|
|
|
|
|
|
|
fox_jumps over
|
|
|
|
the"},
|
|
|
|
Mode::Normal,
|
|
|
|
);
|
2022-03-28 00:58:28 +00:00
|
|
|
|
|
|
|
for cursor_offset in cursor_offsets {
|
|
|
|
cx.simulate_keystroke("w");
|
|
|
|
cx.assert_newest_selection_head_offset(cursor_offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset and test ignoring punctuation
|
|
|
|
let (_, cursor_offsets) = marked_text(indoc! {"
|
|
|
|
The |quick-brown
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|fox_jumps |over
|
|
|
|
|th||e"});
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.set_state(
|
|
|
|
indoc! {"
|
|
|
|
|The quick-brown
|
|
|
|
|
|
|
|
|
|
|
|
fox_jumps over
|
|
|
|
the"},
|
|
|
|
Mode::Normal,
|
|
|
|
);
|
2022-03-28 00:58:28 +00:00
|
|
|
|
|
|
|
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) {
|
2022-04-21 23:14:58 +00:00
|
|
|
let mut cx = VimTestContext::new(cx, true).await;
|
|
|
|
let (_, cursor_offsets) = marked_text(indoc! {"
|
2022-03-28 00:58:28 +00:00
|
|
|
Th|e quic|k|-brow|n
|
|
|
|
|
|
|
|
|
|
|
|
fox_jump|s ove|r
|
|
|
|
th|e"});
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.set_state(
|
|
|
|
indoc! {"
|
|
|
|
|The quick-brown
|
|
|
|
|
|
|
|
|
|
|
|
fox_jumps over
|
|
|
|
the"},
|
|
|
|
Mode::Normal,
|
|
|
|
);
|
2022-03-28 00:58:28 +00:00
|
|
|
|
|
|
|
for cursor_offset in cursor_offsets {
|
|
|
|
cx.simulate_keystroke("e");
|
|
|
|
cx.assert_newest_selection_head_offset(cursor_offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset and test ignoring punctuation
|
|
|
|
let (_, cursor_offsets) = marked_text(indoc! {"
|
|
|
|
Th|e quick-brow|n
|
|
|
|
|
|
|
|
|
|
|
|
fox_jump|s ove|r
|
|
|
|
th||e"});
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.set_state(
|
|
|
|
indoc! {"
|
|
|
|
|The quick-brown
|
|
|
|
|
|
|
|
|
|
|
|
fox_jumps over
|
|
|
|
the"},
|
|
|
|
Mode::Normal,
|
|
|
|
);
|
2022-03-28 00:58:28 +00:00
|
|
|
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) {
|
2022-04-21 23:14:58 +00:00
|
|
|
let mut cx = VimTestContext::new(cx, true).await;
|
|
|
|
let (_, cursor_offsets) = marked_text(indoc! {"
|
2022-03-28 00:58:28 +00:00
|
|
|
||The |quick|-|brown
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|fox_jumps |over
|
|
|
|
|the"});
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.set_state(
|
|
|
|
indoc! {"
|
|
|
|
The quick-brown
|
|
|
|
|
|
|
|
|
|
|
|
fox_jumps over
|
|
|
|
th|e"},
|
|
|
|
Mode::Normal,
|
|
|
|
);
|
2022-03-28 00:58:28 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
let (_, cursor_offsets) = marked_text(indoc! {"
|
|
|
|
||The |quick-brown
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|fox_jumps |over
|
|
|
|
|the"});
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.set_state(
|
|
|
|
indoc! {"
|
|
|
|
The quick-brown
|
|
|
|
|
|
|
|
|
|
|
|
fox_jumps over
|
|
|
|
th|e"},
|
|
|
|
Mode::Normal,
|
|
|
|
);
|
2022-03-28 00:58:28 +00:00
|
|
|
for cursor_offset in cursor_offsets.into_iter().rev() {
|
|
|
|
cx.simulate_keystroke("shift-B");
|
|
|
|
cx.assert_newest_selection_head_offset(cursor_offset);
|
|
|
|
}
|
|
|
|
}
|
2022-04-15 23:00:44 +00:00
|
|
|
|
|
|
|
#[gpui::test]
|
|
|
|
async fn test_g_prefix_and_abort(cx: &mut gpui::TestAppContext) {
|
2022-04-21 23:14:58 +00:00
|
|
|
let mut cx = VimTestContext::new(cx, true).await;
|
2022-04-15 23:00:44 +00:00
|
|
|
|
|
|
|
// 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) {
|
2022-04-21 23:14:58 +00:00
|
|
|
let cx = VimTestContext::new(cx, true).await;
|
|
|
|
let mut cx = cx.binding(["g", "g"]);
|
|
|
|
cx.assert(
|
2022-04-19 18:36:44 +00:00
|
|
|
indoc! {"
|
2022-04-21 23:14:58 +00:00
|
|
|
The quick
|
2022-04-15 23:00:44 +00:00
|
|
|
|
2022-04-21 23:14:58 +00:00
|
|
|
brown fox jumps
|
|
|
|
over |the lazy dog"},
|
2022-04-15 23:00:44 +00:00
|
|
|
indoc! {"
|
2022-04-21 23:14:58 +00:00
|
|
|
The q|uick
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over the lazy dog"},
|
2022-04-15 23:00:44 +00:00
|
|
|
);
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.assert(
|
2022-04-19 18:36:44 +00:00
|
|
|
indoc! {"
|
2022-04-21 23:14:58 +00:00
|
|
|
The q|uick
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over the lazy dog"},
|
2022-04-19 18:36:44 +00:00
|
|
|
indoc! {"
|
2022-04-21 23:14:58 +00:00
|
|
|
The q|uick
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over the lazy dog"},
|
2022-04-19 18:36:44 +00:00
|
|
|
);
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.assert(
|
2022-04-19 18:36:44 +00:00
|
|
|
indoc! {"
|
2022-04-21 23:14:58 +00:00
|
|
|
The quick
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over the la|zy dog"},
|
2022-04-19 18:36:44 +00:00
|
|
|
indoc! {"
|
2022-04-21 23:14:58 +00:00
|
|
|
The quic|k
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over the lazy dog"},
|
2022-04-19 18:36:44 +00:00
|
|
|
);
|
2022-04-21 23:14:58 +00:00
|
|
|
cx.assert(
|
2022-04-19 18:36:44 +00:00
|
|
|
indoc! {"
|
2022-04-21 23:14:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over the la|zy dog"},
|
2022-04-19 18:36:44 +00:00
|
|
|
indoc! {"
|
2022-04-21 23:14:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
brown fox jumps
|
|
|
|
over the lazy dog"},
|
2022-04-19 18:36:44 +00:00
|
|
|
);
|
2022-04-15 23:00:44 +00:00
|
|
|
}
|
2022-03-28 00:58:28 +00:00
|
|
|
}
|