392 lines
10 KiB
Rust
392 lines
10 KiB
Rust
use crate::{motion::Motion, Vim};
|
|
use collections::HashMap;
|
|
use editor::{Autoscroll, Bias};
|
|
use gpui::MutableAppContext;
|
|
|
|
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);
|
|
let mut original_columns: HashMap<_, _> = Default::default();
|
|
editor.change_selections(Some(Autoscroll::Fit), cx, |s| {
|
|
s.move_with(|map, selection| {
|
|
let original_head = selection.head();
|
|
motion.expand_selection(map, selection, true);
|
|
original_columns.insert(selection.id, original_head.column());
|
|
});
|
|
});
|
|
editor.insert(&"", cx);
|
|
|
|
// Fixup cursor position after the deletion
|
|
editor.set_clip_at_line_ends(true, cx);
|
|
editor.change_selections(Some(Autoscroll::Fit), cx, |s| {
|
|
s.move_with(|map, selection| {
|
|
let mut cursor = selection.head();
|
|
if motion.linewise() {
|
|
if let Some(column) = original_columns.get(&selection.id) {
|
|
*cursor.column_mut() = *column
|
|
}
|
|
}
|
|
cursor = map.clip_point(cursor, Bias::Left);
|
|
selection.collapse_to(cursor, selection.goal)
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
#[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"},
|
|
);
|
|
}
|
|
}
|