Add inclusive vs exclusive motions to vim mode

This commit is contained in:
Keith Simmons 2022-04-21 16:14:58 -07:00
parent 0c587ae73c
commit 5ea782de21
11 changed files with 1350 additions and 750 deletions

View file

@ -0,0 +1,386 @@
use crate::{motion::Motion, Vim};
use editor::Bias;
use gpui::MutableAppContext;
use language::SelectionGoal;
pub fn delete_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
vim.update_active_editor(cx, |editor, cx| {
editor.transact(cx, |editor, cx| {
editor.set_clip_at_line_ends(false, cx);
editor.move_selections(cx, |map, selection| {
let original_head = selection.head();
motion.expand_selection(map, selection, true);
selection.goal = SelectionGoal::Column(original_head.column());
});
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.linewise() {
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 crate::vim_test_context::VimTestContext;
#[gpui::test]
async fn test_delete_h(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "h"]);
cx.assert("Te|st", "T|st");
cx.assert("T|est", "|est");
cx.assert("|Test", "|Test");
cx.assert(
indoc! {"
Test
|test"},
indoc! {"
Test
|test"},
);
}
#[gpui::test]
async fn test_delete_l(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "l"]);
cx.assert("|Test", "|est");
cx.assert("Te|st", "Te|t");
cx.assert("Tes|t", "Te|s");
cx.assert(
indoc! {"
Tes|t
test"},
indoc! {"
Te|s
test"},
);
}
#[gpui::test]
async fn test_delete_w(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "w"]);
cx.assert("Te|st", "T|e");
cx.assert("T|est test", "T|test");
cx.assert(
indoc! {"
Test te|st
test"},
indoc! {"
Test t|e
test"},
);
cx.assert(
indoc! {"
Test tes|t
test"},
indoc! {"
Test te|s
test"},
);
cx.assert(
indoc! {"
Test test
|
test"},
indoc! {"
Test test
|
test"},
);
let mut cx = cx.binding(["d", "shift-W"]);
cx.assert("Test te|st-test test", "Test te|test");
}
#[gpui::test]
async fn test_delete_e(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "e"]);
cx.assert("Te|st Test", "Te| Test");
cx.assert("T|est test", "T| test");
cx.assert(
indoc! {"
Test te|st
test"},
indoc! {"
Test t|e
test"},
);
cx.assert(
indoc! {"
Test tes|t
test"},
"Test te|s",
);
cx.assert(
indoc! {"
Test test
|
test"},
indoc! {"
Test test
|
test"},
);
let mut cx = cx.binding(["d", "shift-E"]);
cx.assert("Test te|st-test test", "Test te| test");
}
#[gpui::test]
async fn test_delete_b(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "b"]);
cx.assert("Te|st Test", "|st Test");
cx.assert("Test |test", "|test");
cx.assert("Test1 test2 |test3", "Test1 |test3");
cx.assert(
indoc! {"
Test test
|test"},
// Trailing whitespace after cursor
indoc! {"
Test|
test"},
);
cx.assert(
indoc! {"
Test test
|
test"},
// Trailing whitespace after cursor
indoc! {"
Test|
test"},
);
let mut cx = cx.binding(["d", "shift-B"]);
cx.assert("Test test-test |test", "Test |test");
}
#[gpui::test]
async fn test_delete_end_of_line(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "shift-$"]);
cx.assert(
indoc! {"
The q|uick
brown fox"},
indoc! {"
The |q
brown fox"},
);
cx.assert(
indoc! {"
The quick
|
brown fox"},
indoc! {"
The quick
|
brown fox"},
);
}
#[gpui::test]
async fn test_delete_0(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "0"]);
cx.assert(
indoc! {"
The q|uick
brown fox"},
indoc! {"
|uick
brown fox"},
);
cx.assert(
indoc! {"
The quick
|
brown fox"},
indoc! {"
The quick
|
brown fox"},
);
}
#[gpui::test]
async fn test_delete_k(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "k"]);
cx.assert(
indoc! {"
The quick
brown |fox
jumps over"},
"jumps |over",
);
cx.assert(
indoc! {"
The quick
brown fox
jumps |over"},
"The qu|ick",
);
cx.assert(
indoc! {"
The q|uick
brown fox
jumps over"},
indoc! {"
brown| fox
jumps over"},
);
cx.assert(
indoc! {"
|brown fox
jumps over"},
"|jumps over",
);
}
#[gpui::test]
async fn test_delete_j(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "j"]);
cx.assert(
indoc! {"
The quick
brown |fox
jumps over"},
"The qu|ick",
);
cx.assert(
indoc! {"
The quick
brown fox
jumps |over"},
indoc! {"
The quick
brown |fox"},
);
cx.assert(
indoc! {"
The q|uick
brown fox
jumps over"},
"jumps| over",
);
cx.assert(
indoc! {"
The quick
brown fox
|"},
indoc! {"
The quick
|brown fox"},
);
}
#[gpui::test]
async fn test_delete_end_of_document(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "shift-G"]);
cx.assert(
indoc! {"
The quick
brown| fox
jumps over
the lazy"},
"The q|uick",
);
cx.assert(
indoc! {"
The quick
brown| fox
jumps over
the lazy"},
"The q|uick",
);
cx.assert(
indoc! {"
The quick
brown fox
jumps over
the l|azy"},
indoc! {"
The quick
brown fox
jumps| over"},
);
cx.assert(
indoc! {"
The quick
brown fox
jumps over
|"},
indoc! {"
The quick
brown fox
|jumps over"},
);
}
#[gpui::test]
async fn test_delete_gg(cx: &mut gpui::TestAppContext) {
let cx = VimTestContext::new(cx, true).await;
let mut cx = cx.binding(["d", "g", "g"]);
cx.assert(
indoc! {"
The quick
brown| fox
jumps over
the lazy"},
indoc! {"
jumps| over
the lazy"},
);
cx.assert(
indoc! {"
The quick
brown fox
jumps over
the l|azy"},
"|",
);
cx.assert(
indoc! {"
The q|uick
brown fox
jumps over
the lazy"},
indoc! {"
brown| fox
jumps over
the lazy"},
);
cx.assert(
indoc! {"
|
brown fox
jumps over
the lazy"},
indoc! {"
|brown fox
jumps over
the lazy"},
);
}
}