Detailed changes
@@ -15,7 +15,7 @@ use crate::{
Vim,
};
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Motion {
Left,
Backspace,
@@ -139,14 +139,22 @@ impl Motion {
pub fn inclusive(self) -> bool {
use Motion::*;
- if self.linewise() {
- return true;
- }
-
match self {
- EndOfLine | NextWordEnd { .. } | Matching => true,
- Left | Right | StartOfLine | NextWordStart { .. } | PreviousWordStart { .. } => false,
- _ => panic!("Exclusivity not defined for {self:?}"),
+ Down
+ | Up
+ | StartOfDocument
+ | EndOfDocument
+ | CurrentLine
+ | EndOfLine
+ | NextWordEnd { .. }
+ | Matching => true,
+ Left
+ | Backspace
+ | Right
+ | StartOfLine
+ | NextWordStart { .. }
+ | PreviousWordStart { .. }
+ | FirstNonWhitespace => false,
}
}
@@ -194,27 +202,29 @@ impl Motion {
times: usize,
expand_to_surrounding_newline: bool,
) {
- let (head, goal) = self.move_point(map, selection.head(), selection.goal, times);
- selection.set_head(head, goal);
+ let (new_head, goal) = self.move_point(map, selection.head(), selection.goal, times);
+ selection.set_head(new_head, goal);
if self.linewise() {
- selection.start = map.prev_line_boundary(selection.start.to_point(map)).1;
-
- if expand_to_surrounding_newline {
- if selection.end.row() < map.max_point().row() {
- *selection.end.row_mut() += 1;
- *selection.end.column_mut() = 0;
- selection.end = map.clip_point(selection.end, Bias::Right);
- // Don't reset the end here
- return;
- } else if selection.start.row() > 0 {
- *selection.start.row_mut() -= 1;
- *selection.start.column_mut() = map.line_len(selection.start.row());
- selection.start = map.clip_point(selection.start, Bias::Left);
+ if selection.start != selection.end {
+ selection.start = map.prev_line_boundary(selection.start.to_point(map)).1;
+
+ if expand_to_surrounding_newline {
+ if selection.end.row() < map.max_point().row() {
+ *selection.end.row_mut() += 1;
+ *selection.end.column_mut() = 0;
+ selection.end = map.clip_point(selection.end, Bias::Right);
+ // Don't reset the end here
+ return;
+ } else if selection.start.row() > 0 {
+ *selection.start.row_mut() -= 1;
+ *selection.start.column_mut() = map.line_len(selection.start.row());
+ selection.start = map.clip_point(selection.start, Bias::Left);
+ }
}
- }
- (_, selection.end) = map.next_line_boundary(selection.end.to_point(map));
+ (_, selection.end) = map.next_line_boundary(selection.end.to_point(map));
+ }
} else {
// If the motion is exclusive and the end of the motion is in column 1, the
// end of the motion is moved to the end of the previous line and the motion
@@ -222,6 +232,7 @@ impl Motion {
// but "d}" will not include that line.
let mut inclusive = self.inclusive();
if !inclusive
+ && self != Motion::Backspace
&& selection.end.row() > selection.start.row()
&& selection.end.column() == 0
&& selection.end.row() > 0
@@ -372,7 +372,7 @@ mod test {
Mode::{self, *},
Namespace, Operator,
},
- test::{NeovimBackedTestContext, VimTestContext},
+ test::{ExemptionFeatures, NeovimBackedTestContext, VimTestContext},
};
#[gpui::test]
@@ -741,11 +741,14 @@ mod test {
brown ˇfox
jumps ˇover"})
.await;
- cx.assert(indoc! {"
+ cx.assert_exempted(
+ indoc! {"
The quick
ˇ
- brown fox"})
- .await;
+ brown fox"},
+ ExemptionFeatures::DeletionOnEmptyLine,
+ )
+ .await;
}
#[gpui::test]
@@ -85,372 +85,271 @@ fn expand_changed_word_selection(
mod test {
use indoc::indoc;
- use crate::{
- state::Mode,
- test::{NeovimBackedTestContext, VimTestContext},
- };
+ use crate::test::{ExemptionFeatures, NeovimBackedTestContext};
#[gpui::test]
async fn test_change_h(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "h"]).mode_after(Mode::Insert);
- cx.assert("Teˇst", "Tˇst");
- cx.assert("Tˇest", "ˇest");
- cx.assert("ˇTest", "ˇTest");
- cx.assert(
- indoc! {"
- Test
- ˇtest"},
- indoc! {"
- Test
- ˇtest"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "h"]);
+ cx.assert("Teˇst").await;
+ cx.assert("Tˇest").await;
+ cx.assert("ˇTest").await;
+ cx.assert(indoc! {"
+ Test
+ ˇtest"})
+ .await;
+ }
+
+ #[gpui::test]
+ async fn test_change_backspace(cx: &mut gpui::TestAppContext) {
+ let mut cx = NeovimBackedTestContext::new(cx)
+ .await
+ .binding(["c", "backspace"]);
+ cx.assert("Teˇst").await;
+ cx.assert("Tˇest").await;
+ cx.assert("ˇTest").await;
+ cx.assert(indoc! {"
+ Test
+ ˇtest"})
+ .await;
}
#[gpui::test]
async fn test_change_l(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "l"]).mode_after(Mode::Insert);
- cx.assert("Teˇst", "Teˇt");
- cx.assert("Tesˇt", "Tesˇ");
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "l"]);
+ cx.assert("Teˇst").await;
+ cx.assert("Tesˇt").await;
}
#[gpui::test]
async fn test_change_w(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "w"]).mode_after(Mode::Insert);
- cx.assert("Teˇst", "Teˇ");
- cx.assert("Tˇest test", "Tˇ test");
- cx.assert("Testˇ test", "Testˇtest");
- cx.assert(
- indoc! {"
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "w"]);
+ cx.assert("Teˇst").await;
+ cx.assert("Tˇest test").await;
+ cx.assert("Testˇ test").await;
+ cx.assert(indoc! {"
Test teˇst
- test"},
- indoc! {"
- Test teˇ
- test"},
- );
- cx.assert(
- indoc! {"
+ test"})
+ .await;
+ cx.assert(indoc! {"
Test tesˇt
- test"},
- indoc! {"
- Test tesˇ
- test"},
- );
- cx.assert(
- indoc! {"
- Test test
- ˇ
- test"},
- indoc! {"
+ test"})
+ .await;
+ cx.assert(indoc! {"
Test test
ˇ
- test"},
- );
+ test"})
+ .await;
let mut cx = cx.binding(["c", "shift-w"]);
- cx.assert("Test teˇst-test test", "Test teˇ test");
+ cx.assert("Test teˇst-test test").await;
}
#[gpui::test]
async fn test_change_e(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "e"]).mode_after(Mode::Insert);
- cx.assert("Teˇst Test", "Teˇ Test");
- cx.assert("Tˇest test", "Tˇ test");
- cx.assert(
- indoc! {"
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "e"]);
+ cx.assert("Teˇst Test").await;
+ cx.assert("Tˇest test").await;
+ cx.assert(indoc! {"
Test teˇst
- test"},
- indoc! {"
- Test teˇ
- test"},
- );
- cx.assert(
- indoc! {"
+ test"})
+ .await;
+ cx.assert(indoc! {"
Test tesˇt
- test"},
- "Test tesˇ",
- );
- cx.assert(
- indoc! {"
+ test"})
+ .await;
+ cx.assert(indoc! {"
Test test
ˇ
- test"},
- indoc! {"
- Test test
- ˇ"},
- );
+ test"})
+ .await;
let mut cx = cx.binding(["c", "shift-e"]);
- cx.assert("Test teˇst-test test", "Test teˇ test");
+ cx.assert("Test teˇst-test test").await;
}
#[gpui::test]
async fn test_change_b(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "b"]).mode_after(Mode::Insert);
- cx.assert("Teˇst Test", "ˇst Test");
- cx.assert("Test ˇtest", "ˇtest");
- cx.assert("Test1 test2 ˇtest3", "Test1 ˇtest3");
- cx.assert(
- indoc! {"
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "b"]);
+ cx.assert("Teˇst Test").await;
+ cx.assert("Test ˇtest").await;
+ cx.assert("Test1 test2 ˇtest3").await;
+ cx.assert(indoc! {"
Test test
- ˇtest"},
- indoc! {"
- Test ˇ
- test"},
- );
+ ˇtest"})
+ .await;
println!("Marker");
- cx.assert(
- indoc! {"
+ cx.assert(indoc! {"
Test test
ˇ
- test"},
- indoc! {"
- Test ˇ
-
- test"},
- );
+ test"})
+ .await;
let mut cx = cx.binding(["c", "shift-b"]);
- cx.assert("Test test-test ˇtest", "Test ˇtest");
+ cx.assert("Test test-test ˇtest").await;
}
#[gpui::test]
async fn test_change_end_of_line(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "$"]).mode_after(Mode::Insert);
- 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"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "$"]);
+ cx.assert(indoc! {"
+ The qˇuick
+ brown fox"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ ˇ
+ brown fox"})
+ .await;
}
#[gpui::test]
async fn test_change_0(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "0"]).mode_after(Mode::Insert);
- cx.assert(
- indoc! {"
- The qˇuick
- brown fox"},
- indoc! {"
- ˇuick
- brown fox"},
- );
- cx.assert(
- indoc! {"
- The quick
- ˇ
- brown fox"},
- indoc! {"
- The quick
- ˇ
- brown fox"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "0"]);
+ cx.assert(indoc! {"
+ The qˇuick
+ brown fox"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ ˇ
+ brown fox"})
+ .await;
}
#[gpui::test]
async fn test_change_k(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "k"]).mode_after(Mode::Insert);
- cx.assert(
- indoc! {"
- The quick
- brown ˇfox
- jumps over"},
- indoc! {"
- ˇ
- jumps over"},
- );
- cx.assert(
- indoc! {"
- The quick
- brown fox
- jumps ˇover"},
- indoc! {"
- The quick
- ˇ"},
- );
- cx.assert(
- indoc! {"
- The qˇuick
- brown fox
- jumps over"},
- indoc! {"
- ˇ
- brown fox
- jumps over"},
- );
- cx.assert(
- indoc! {"
- ˇ
- brown fox
- jumps over"},
- indoc! {"
- ˇ
- brown fox
- jumps over"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "k"]);
+ cx.assert(indoc! {"
+ The quick
+ brown ˇfox
+ jumps over"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ brown fox
+ jumps ˇover"})
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ The qˇuick
+ brown fox
+ jumps over"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ ˇ
+ brown fox
+ jumps over"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
}
#[gpui::test]
async fn test_change_j(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "j"]).mode_after(Mode::Insert);
- cx.assert(
- indoc! {"
- The quick
- brown ˇfox
- jumps over"},
- indoc! {"
- The quick
- ˇ"},
- );
- cx.assert(
- indoc! {"
- The quick
- brown fox
- jumps ˇover"},
- indoc! {"
- The quick
- brown fox
- ˇ"},
- );
- cx.assert(
- indoc! {"
- The qˇuick
- brown fox
- jumps over"},
- indoc! {"
- ˇ
- jumps over"},
- );
- cx.assert(
- indoc! {"
- The quick
- brown fox
- ˇ"},
- indoc! {"
- The quick
- brown fox
- ˇ"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "j"]);
+ cx.assert(indoc! {"
+ The quick
+ brown ˇfox
+ jumps over"})
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ The quick
+ brown fox
+ jumps ˇover"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
+ cx.assert(indoc! {"
+ The qˇuick
+ brown fox
+ jumps over"})
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ The quick
+ brown fox
+ ˇ"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
}
#[gpui::test]
async fn test_change_end_of_document(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "shift-g"]).mode_after(Mode::Insert);
- cx.assert(
- indoc! {"
- The quick
- brownˇ fox
- jumps over
- the lazy"},
- indoc! {"
- The quick
- ˇ"},
- );
- cx.assert(
- indoc! {"
- The quick
- brownˇ fox
- jumps over
- the lazy"},
- indoc! {"
- The quick
- ˇ"},
- );
- 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
- ˇ"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx)
+ .await
+ .binding(["c", "shift-g"]);
+ cx.assert(indoc! {"
+ The quick
+ brownˇ fox
+ jumps over
+ the lazy"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ brownˇ fox
+ jumps over
+ the lazy"})
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ The quick
+ brown fox
+ jumps over
+ the lˇazy"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ The quick
+ brown fox
+ jumps over
+ ˇ"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
}
#[gpui::test]
async fn test_change_gg(cx: &mut gpui::TestAppContext) {
- let cx = VimTestContext::new(cx, true).await;
- let mut cx = cx.binding(["c", "g", "g"]).mode_after(Mode::Insert);
- 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"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx)
+ .await
+ .binding(["c", "g", "g"]);
+ cx.assert(indoc! {"
+ The quick
+ brownˇ fox
+ jumps over
+ the lazy"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ brown fox
+ jumps over
+ the lˇazy"})
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ The qˇuick
+ brown fox
+ jumps over
+ the lazy"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ ˇ
+ brown fox
+ jumps over
+ the lazy"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
}
#[gpui::test]
@@ -493,14 +392,15 @@ mod test {
async fn test_repeated_cb(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await;
- // Changing back any number of times from the start of the file doesn't
- // switch to insert mode in vim. This is weird and painful to implement
- cx.add_initial_state_exemption(indoc! {"
+ cx.add_initial_state_exemptions(
+ indoc! {"
ˇThe quick brown
-
+
fox jumps-over
the lazy dog
- "});
+ "},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ );
for count in 1..=5 {
cx.assert_binding_matches_all(
@@ -96,354 +96,256 @@ pub fn delete_object(vim: &mut Vim, object: Object, around: bool, cx: &mut Mutab
mod test {
use indoc::indoc;
- use crate::{state::Mode, test::VimTestContext};
+ use crate::{
+ state::Mode,
+ test::{ExemptionFeatures, NeovimBackedTestContext, 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"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "h"]);
+ cx.assert("Teˇst").await;
+ cx.assert("Tˇest").await;
+ cx.assert("ˇTest").await;
+ cx.assert(indoc! {"
+ Test
+ ˇtest"})
+ .await;
}
#[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! {"
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "l"]);
+ cx.assert("ˇTest").await;
+ cx.assert("Teˇst").await;
+ cx.assert("Tesˇt").await;
+ cx.assert(indoc! {"
Tesˇt
- test"},
- indoc! {"
- Teˇs
- test"},
- );
+ test"})
+ .await;
}
#[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 = NeovimBackedTestContext::new(cx).await.binding(["d", "w"]);
+ cx.assert("Teˇst").await;
+ cx.assert("Tˇest test").await;
+ cx.assert(indoc! {"
+ Test teˇst
+ test"})
+ .await;
+ cx.assert(indoc! {"
+ Test tesˇt
+ test"})
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ Test test
+ ˇ
+ test"},
+ ExemptionFeatures::DeletionOnEmptyLine,
+ )
+ .await;
let mut cx = cx.binding(["d", "shift-w"]);
- cx.assert("Test teˇst-test test", "Test teˇtest");
+ cx.assert("Test teˇst-test test").await;
}
#[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
- ˇ"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "e"]);
+ cx.assert("Teˇst Test").await;
+ cx.assert("Tˇest test").await;
+ cx.assert(indoc! {"
+ Test teˇst
+ test"})
+ .await;
+ cx.assert(indoc! {"
+ Test tesˇt
+ test"})
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ Test test
+ ˇ
+ test"},
+ ExemptionFeatures::DeletionOnEmptyLine,
+ )
+ .await;
let mut cx = cx.binding(["d", "shift-e"]);
- cx.assert("Test teˇst-test test", "Test teˇ test");
+ cx.assert("Test teˇst-test test").await;
}
#[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 = NeovimBackedTestContext::new(cx).await.binding(["d", "b"]);
+ cx.assert("Teˇst Test").await;
+ cx.assert("Test ˇtest").await;
+ cx.assert("Test1 test2 ˇtest3").await;
+ cx.assert(indoc! {"
+ Test test
+ ˇtest"})
+ .await;
+ cx.assert(indoc! {"
+ Test test
+ ˇ
+ test"})
+ .await;
let mut cx = cx.binding(["d", "shift-b"]);
- cx.assert("Test test-test ˇtest", "Test ˇtest");
+ cx.assert("Test test-test ˇtest").await;
}
#[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", "$"]);
- 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"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "$"]);
+ cx.assert(indoc! {"
+ The qˇuick
+ brown fox"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ ˇ
+ brown fox"})
+ .await;
}
#[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"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "0"]);
+ cx.assert(indoc! {"
+ The qˇuick
+ brown fox"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ ˇ
+ brown fox"})
+ .await;
}
#[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",
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "k"]);
+ cx.assert(indoc! {"
+ The quick
+ brown ˇfox
+ jumps over"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ brown fox
+ jumps ˇover"})
+ .await;
+ cx.assert(indoc! {"
+ The qˇuick
+ brown fox
+ jumps over"})
+ .await;
+ cx.assert(indoc! {"
+ ˇbrown fox
+ jumps over"})
+ .await;
}
#[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"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "j"]);
+ cx.assert(indoc! {"
+ The quick
+ brown ˇfox
+ jumps over"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ brown fox
+ jumps ˇover"})
+ .await;
+ cx.assert(indoc! {"
+ The qˇuick
+ brown fox
+ jumps over"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ brown fox
+ ˇ"})
+ .await;
}
#[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"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx)
+ .await
+ .binding(["d", "shift-g"]);
+ cx.assert(indoc! {"
+ The quick
+ brownˇ fox
+ jumps over
+ the lazy"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ brownˇ fox
+ jumps over
+ the lazy"})
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ The quick
+ brown fox
+ jumps over
+ the lˇazy"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ The quick
+ brown fox
+ jumps over
+ ˇ"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
}
#[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"},
- );
+ let mut cx = NeovimBackedTestContext::new(cx)
+ .await
+ .binding(["d", "g", "g"]);
+ cx.assert(indoc! {"
+ The quick
+ brownˇ fox
+ jumps over
+ the lazy"})
+ .await;
+ cx.assert(indoc! {"
+ The quick
+ brown fox
+ jumps over
+ the lˇazy"})
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ The qˇuick
+ brown fox
+ jumps over
+ the lazy"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
+ cx.assert_exempted(
+ indoc! {"
+ ˇ
+ brown fox
+ jumps over
+ the lazy"},
+ ExemptionFeatures::OperatorAbortsOnFailedMotion,
+ )
+ .await;
}
#[gpui::test]
@@ -431,7 +431,7 @@ fn surrounding_markers(
mod test {
use indoc::indoc;
- use crate::test::NeovimBackedTestContext;
+ use crate::test::{ExemptionFeatures, NeovimBackedTestContext};
const WORD_LOCATIONS: &'static str = indoc! {"
The quick ˇbrowˇnˇ
@@ -482,25 +482,46 @@ mod test {
cx.assert_binding_matches_all(["v", "i", "w"], WORD_LOCATIONS)
.await;
- // Visual text objects are slightly broken when used with non empty selections
- // cx.assert_binding_matches_all(["v", "h", "i", "w"], WORD_LOCATIONS)
- // .await;
- // cx.assert_binding_matches_all(["v", "l", "i", "w"], WORD_LOCATIONS)
- // .await;
+ cx.assert_binding_matches_all_exempted(
+ ["v", "h", "i", "w"],
+ WORD_LOCATIONS,
+ ExemptionFeatures::NonEmptyVisualTextObjects,
+ )
+ .await;
+ cx.assert_binding_matches_all_exempted(
+ ["v", "l", "i", "w"],
+ WORD_LOCATIONS,
+ ExemptionFeatures::NonEmptyVisualTextObjects,
+ )
+ .await;
cx.assert_binding_matches_all(["v", "i", "shift-w"], WORD_LOCATIONS)
.await;
- // Visual text objects are slightly broken when used with non empty selections
- // cx.assert_binding_matches_all(["v", "i", "h", "shift-w"], WORD_LOCATIONS)
- // .await;
- // cx.assert_binding_matches_all(["v", "i", "l", "shift-w"], WORD_LOCATIONS)
- // .await;
-
- // Visual around words is somewhat broken right now when it comes to newlines
- // cx.assert_binding_matches_all(["v", "a", "w"], WORD_LOCATIONS)
- // .await;
- // cx.assert_binding_matches_all(["v", "a", "shift-w"], WORD_LOCATIONS)
- // .await;
+ cx.assert_binding_matches_all_exempted(
+ ["v", "i", "h", "shift-w"],
+ WORD_LOCATIONS,
+ ExemptionFeatures::NonEmptyVisualTextObjects,
+ )
+ .await;
+ cx.assert_binding_matches_all_exempted(
+ ["v", "i", "l", "shift-w"],
+ WORD_LOCATIONS,
+ ExemptionFeatures::NonEmptyVisualTextObjects,
+ )
+ .await;
+
+ cx.assert_binding_matches_all_exempted(
+ ["v", "a", "w"],
+ WORD_LOCATIONS,
+ ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine,
+ )
+ .await;
+ cx.assert_binding_matches_all_exempted(
+ ["v", "a", "shift-w"],
+ WORD_LOCATIONS,
+ ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine,
+ )
+ .await;
}
const SENTENCE_EXAMPLES: &[&'static str] = &[
@@ -511,17 +532,15 @@ mod test {
the lazy doˇgˇ.ˇ ˇThe quick ˇ
brown fox jumps over
"},
- // Position of the cursor after deletion between lines isn't quite right.
- // Deletion in a sentence at the start of a line with whitespace is incorrect.
- // indoc! {"
- // The quick brown fox jumps.
- // Over the lazy dog
- // ˇ
- // ˇ
- // ˇ fox-jumpˇs over
- // the lazy dog.ˇ
- // ˇ
- // "},
+ indoc! {"
+ The quick brown fox jumps.
+ Over the lazy dog
+ ˇ
+ ˇ
+ ˇ fox-jumpˇs over
+ the lazy dog.ˇ
+ ˇ
+ "},
r#"ˇThe ˇquick brownˇ.)ˇ]ˇ'ˇ" Brown ˇfox jumpsˇ.ˇ "#,
];
@@ -530,15 +549,28 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx)
.await
.binding(["c", "i", "s"]);
+ cx.add_initial_state_exemptions(
+ "The quick brown fox jumps.\nOver the lazy dog\nˇ\nˇ\n fox-jumps over\nthe lazy dog.\n\n",
+ ExemptionFeatures::SentenceOnEmptyLines);
+ cx.add_initial_state_exemptions(
+ "The quick brown fox jumps.\nOver the lazy dog\n\n\nˇ foxˇ-ˇjumpˇs over\nthe lazy dog.\n\n",
+ ExemptionFeatures::SentenceAtStartOfLineWithWhitespace);
+ cx.add_initial_state_exemptions(
+ "The quick brown fox jumps.\nOver the lazy dog\n\n\n fox-jumps over\nthe lazy dog.ˇ\nˇ\n",
+ ExemptionFeatures::SentenceAfterPunctuationAtEndOfFile);
for sentence_example in SENTENCE_EXAMPLES {
cx.assert_all(sentence_example).await;
}
let mut cx = cx.binding(["c", "a", "s"]);
- // Resulting position is slightly incorrect for unintuitive reasons.
- cx.add_initial_state_exemption("The quick brown?ˇ Fox Jumps! Over the lazy.");
- // Changing around the sentence at the end of the line doesn't remove whitespace.'
- cx.add_initial_state_exemption("The quick brown.)]\'\" Brown fox jumps.ˇ ");
+ cx.add_initial_state_exemptions(
+ "The quick brown?ˇ Fox Jumps! Over the lazy.",
+ ExemptionFeatures::IncorrectLandingPosition,
+ );
+ cx.add_initial_state_exemptions(
+ "The quick brown.)]\'\" Brown fox jumps.ˇ ",
+ ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine,
+ );
for sentence_example in SENTENCE_EXAMPLES {
cx.assert_all(sentence_example).await;
@@ -550,15 +582,29 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx)
.await
.binding(["d", "i", "s"]);
+ cx.add_initial_state_exemptions(
+ "The quick brown fox jumps.\nOver the lazy dog\nˇ\nˇ\n fox-jumps over\nthe lazy dog.\n\n",
+ ExemptionFeatures::SentenceOnEmptyLines);
+ cx.add_initial_state_exemptions(
+ "The quick brown fox jumps.\nOver the lazy dog\n\n\nˇ foxˇ-ˇjumpˇs over\nthe lazy dog.\n\n",
+ ExemptionFeatures::SentenceAtStartOfLineWithWhitespace);
+ cx.add_initial_state_exemptions(
+ "The quick brown fox jumps.\nOver the lazy dog\n\n\n fox-jumps over\nthe lazy dog.ˇ\nˇ\n",
+ ExemptionFeatures::SentenceAfterPunctuationAtEndOfFile);
+
for sentence_example in SENTENCE_EXAMPLES {
cx.assert_all(sentence_example).await;
}
let mut cx = cx.binding(["d", "a", "s"]);
- // Resulting position is slightly incorrect for unintuitive reasons.
- cx.add_initial_state_exemption("The quick brown?ˇ Fox Jumps! Over the lazy.");
- // Changing around the sentence at the end of the line doesn't remove whitespace.'
- cx.add_initial_state_exemption("The quick brown.)]\'\" Brown fox jumps.ˇ ");
+ cx.add_initial_state_exemptions(
+ "The quick brown?ˇ Fox Jumps! Over the lazy.",
+ ExemptionFeatures::IncorrectLandingPosition,
+ );
+ cx.add_initial_state_exemptions(
+ "The quick brown.)]\'\" Brown fox jumps.ˇ ",
+ ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine,
+ );
for sentence_example in SENTENCE_EXAMPLES {
cx.assert_all(sentence_example).await;
@@ -571,14 +617,18 @@ mod test {
.await
.binding(["v", "i", "s"]);
for sentence_example in SENTENCE_EXAMPLES {
- cx.assert_all(sentence_example).await;
+ cx.assert_all_exempted(sentence_example, ExemptionFeatures::SentenceOnEmptyLines)
+ .await;
}
- // Visual around sentences is somewhat broken right now when it comes to newlines
- // let mut cx = cx.binding(["d", "a", "s"]);
- // for sentence_example in SENTENCE_EXAMPLES {
- // cx.assert_all(sentence_example).await;
- // }
+ let mut cx = cx.binding(["v", "a", "s"]);
+ for sentence_example in SENTENCE_EXAMPLES {
+ cx.assert_all_exempted(
+ sentence_example,
+ ExemptionFeatures::AroundSentenceStartingBetweenIncludesWrongWhitespace,
+ )
+ .await;
+ }
}
// Test string with "`" for opening surrounders and "'" for closing surrounders
@@ -588,14 +638,13 @@ mod test {
the ˇlazy dˇ'ˇoˇ`ˇg"};
const SURROUNDING_OBJECTS: &[(char, char)] = &[
- // ('\'', '\''), // Quote,
- // ('`', '`'), // Back Quote
- // ('"', '"'), // Double Quote
- // ('"', '"'), // Double Quote
- ('(', ')'), // Parentheses
- ('[', ']'), // SquareBrackets
- ('{', '}'), // CurlyBrackets
- ('<', '>'), // AngleBrackets
+ ('\'', '\''), // Quote
+ ('`', '`'), // Back Quote
+ ('"', '"'), // Double Quote
+ ('(', ')'), // Parentheses
+ ('[', ']'), // SquareBrackets
+ ('{', '}'), // CurlyBrackets
+ ('<', '>'), // AngleBrackets
];
#[gpui::test]
@@ -603,16 +652,23 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await;
for (start, end) in SURROUNDING_OBJECTS {
+ if ((start == &'\'' || start == &'`' || start == &'"')
+ && !ExemptionFeatures::QuotesSeekForward.supported())
+ || (start == &'<' && !ExemptionFeatures::AngleBracketsFreezeNeovim.supported())
+ {
+ continue;
+ }
+
let marked_string = SURROUNDING_MARKER_STRING
.replace('`', &start.to_string())
.replace('\'', &end.to_string());
- // cx.assert_binding_matches_all(["c", "i", &start.to_string()], &marked_string)
- // .await;
+ cx.assert_binding_matches_all(["c", "i", &start.to_string()], &marked_string)
+ .await;
cx.assert_binding_matches_all(["c", "i", &end.to_string()], &marked_string)
.await;
- // cx.assert_binding_matches_all(["c", "a", &start.to_string()], &marked_string)
- // .await;
+ cx.assert_binding_matches_all(["c", "a", &start.to_string()], &marked_string)
+ .await;
cx.assert_binding_matches_all(["c", "a", &end.to_string()], &marked_string)
.await;
}
@@ -623,16 +679,22 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await;
for (start, end) in SURROUNDING_OBJECTS {
+ if ((start == &'\'' || start == &'`' || start == &'"')
+ && !ExemptionFeatures::QuotesSeekForward.supported())
+ || (start == &'<' && !ExemptionFeatures::AngleBracketsFreezeNeovim.supported())
+ {
+ continue;
+ }
let marked_string = SURROUNDING_MARKER_STRING
.replace('`', &start.to_string())
.replace('\'', &end.to_string());
- // cx.assert_binding_matches_all(["d", "i", &start.to_string()], &marked_string)
- // .await;
+ cx.assert_binding_matches_all(["d", "i", &start.to_string()], &marked_string)
+ .await;
cx.assert_binding_matches_all(["d", "i", &end.to_string()], &marked_string)
.await;
- // cx.assert_binding_matches_all(["d", "a", &start.to_string()], &marked_string)
- // .await;
+ cx.assert_binding_matches_all(["d", "a", &start.to_string()], &marked_string)
+ .await;
cx.assert_binding_matches_all(["d", "a", &end.to_string()], &marked_string)
.await;
}
@@ -4,7 +4,7 @@ use gpui::ContextHandle;
use crate::state::Mode;
-use super::NeovimBackedTestContext;
+use super::{ExemptionFeatures, NeovimBackedTestContext, SUPPORTED_FEATURES};
pub struct NeovimBackedBindingTestContext<'a, const COUNT: usize> {
cx: NeovimBackedTestContext<'a>,
@@ -42,6 +42,20 @@ impl<'a, const COUNT: usize> NeovimBackedBindingTestContext<'a, COUNT> {
.await
}
+ pub async fn assert_exempted(
+ &mut self,
+ marked_positions: &str,
+ feature: ExemptionFeatures,
+ ) -> Option<(ContextHandle, ContextHandle)> {
+ if SUPPORTED_FEATURES.contains(&feature) {
+ self.cx
+ .assert_binding_matches(self.keystrokes_under_test, marked_positions)
+ .await
+ } else {
+ None
+ }
+ }
+
pub fn assert_manual(
&mut self,
initial_state: &str,
@@ -63,6 +77,18 @@ impl<'a, const COUNT: usize> NeovimBackedBindingTestContext<'a, COUNT> {
.assert_binding_matches_all(self.keystrokes_under_test, marked_positions)
.await
}
+
+ pub async fn assert_all_exempted(
+ &mut self,
+ marked_positions: &str,
+ feature: ExemptionFeatures,
+ ) {
+ if SUPPORTED_FEATURES.contains(&feature) {
+ self.cx
+ .assert_binding_matches_all(self.keystrokes_under_test, marked_positions)
+ .await
+ }
+ }
}
impl<'a, const COUNT: usize> Deref for NeovimBackedBindingTestContext<'a, COUNT> {
@@ -8,6 +8,45 @@ use util::test::marked_text_offsets;
use super::{neovim_connection::NeovimConnection, NeovimBackedBindingTestContext, VimTestContext};
use crate::state::Mode;
+pub const SUPPORTED_FEATURES: &[ExemptionFeatures] = &[];
+
+/// Enum representing features we have tests for but which don't work, yet. Used
+/// to add exemptions and automatically
+#[derive(PartialEq, Eq)]
+pub enum ExemptionFeatures {
+ // MOTIONS
+ // Deletions on empty lines miss some newlines
+ DeletionOnEmptyLine,
+ // When a motion fails, it should should not apply linewise operations
+ OperatorAbortsOnFailedMotion,
+
+ // OBJECTS
+ // Resulting position after the operation is slightly incorrect for unintuitive reasons.
+ IncorrectLandingPosition,
+ // Operator around the text object at the end of the line doesn't remove whitespace.
+ AroundObjectLeavesWhitespaceAtEndOfLine,
+ // Sentence object on empty lines
+ SentenceOnEmptyLines,
+ // Whitespace isn't included with text objects at the start of the line
+ SentenceAtStartOfLineWithWhitespace,
+ // Whitespace around sentences is slightly incorrect when starting between sentences
+ AroundSentenceStartingBetweenIncludesWrongWhitespace,
+ // Non empty selection with text objects in visual mode
+ NonEmptyVisualTextObjects,
+ // Quote style surrounding text objects don't seek forward properly
+ QuotesSeekForward,
+ // Neovim freezes up for some reason with angle brackets
+ AngleBracketsFreezeNeovim,
+ // Sentence Doesn't backtrack when its at the end of the file
+ SentenceAfterPunctuationAtEndOfFile,
+}
+
+impl ExemptionFeatures {
+ pub fn supported(&self) -> bool {
+ SUPPORTED_FEATURES.contains(self)
+ }
+}
+
pub struct NeovimBackedTestContext<'a> {
cx: VimTestContext<'a>,
// Lookup for exempted assertions. Keyed by the insertion text, and with a value indicating which
@@ -27,10 +66,22 @@ impl<'a> NeovimBackedTestContext<'a> {
}
}
- pub fn add_initial_state_exemption(&mut self, initial_state: &str) {
- let initial_state = initial_state.to_string();
- // None represents all keybindings being exempted for that initial state
- self.exemptions.insert(initial_state, None);
+ pub fn add_initial_state_exemptions(
+ &mut self,
+ marked_positions: &str,
+ missing_feature: ExemptionFeatures, // Feature required to support this exempted test case
+ ) {
+ if !missing_feature.supported() {
+ let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions);
+
+ for cursor_offset in cursor_offsets.iter() {
+ let mut marked_text = unmarked_text.clone();
+ marked_text.insert(*cursor_offset, 'ˇ');
+
+ // None represents all keybindings being exempted for that initial state
+ self.exemptions.insert(marked_text, None);
+ }
+ }
}
pub async fn simulate_shared_keystroke(&mut self, keystroke_text: &str) -> ContextHandle {
@@ -120,6 +171,18 @@ impl<'a> NeovimBackedTestContext<'a> {
}
}
+ pub async fn assert_binding_matches_all_exempted<const COUNT: usize>(
+ &mut self,
+ keystrokes: [&str; COUNT],
+ marked_positions: &str,
+ feature: ExemptionFeatures,
+ ) {
+ if SUPPORTED_FEATURES.contains(&feature) {
+ self.assert_binding_matches_all(keystrokes, marked_positions)
+ .await
+ }
+ }
+
pub fn binding<const COUNT: usize>(
self,
keystrokes: [&'static str; COUNT],
@@ -38,11 +38,6 @@ impl<'a, const COUNT: usize> VimBindingTestContext<'a, COUNT> {
}
}
- pub fn mode_after(mut self, mode_after: Mode) -> Self {
- self.mode_after = mode_after;
- self
- }
-
pub fn assert(&mut self, initial_state: &str, state_after: &str) {
self.cx.assert_binding(
self.keystrokes_under_test,
@@ -0,0 +1 @@
+[{"Text":"uick\nbrown fox"},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"},{"Text":"The quick\n\nbrown fox"},{"Mode":"Insert"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Insert"}]
@@ -0,0 +1 @@
+[{"Text":"st Test"},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"},{"Text":"test"},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"},{"Text":"Test1 test3"},{"Mode":"Insert"},{"Selection":{"start":[0,6],"end":[0,6]}},{"Mode":"Insert"},{"Text":"Test \ntest"},{"Mode":"Insert"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Insert"},{"Text":"Test \n\ntest"},{"Mode":"Insert"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Insert"},{"Text":"Test test"},{"Mode":"Insert"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Insert"}]
@@ -0,0 +1 @@
+[{"Text":"Tst"},{"Mode":"Insert"},{"Selection":{"start":[0,1],"end":[0,1]}},{"Mode":"Insert"},{"Text":"est"},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"},{"Text":"Test"},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"},{"Text":"Testtest"},{"Mode":"Insert"},{"Selection":{"start":[0,4],"end":[0,4]}},{"Mode":"Insert"}]
@@ -0,0 +1 @@
+[{"Text":"Te Test"},{"Mode":"Insert"},{"Selection":{"start":[0,2],"end":[0,2]}},{"Mode":"Insert"},{"Text":"T test"},{"Mode":"Insert"},{"Selection":{"start":[0,1],"end":[0,1]}},{"Mode":"Insert"},{"Text":"Test te\ntest"},{"Mode":"Insert"},{"Selection":{"start":[0,7],"end":[0,7]}},{"Mode":"Insert"},{"Text":"Test tes"},{"Mode":"Insert"},{"Selection":{"start":[0,8],"end":[0,8]}},{"Mode":"Insert"},{"Text":"Test test\n"},{"Mode":"Insert"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Insert"},{"Text":"Test te test"},{"Mode":"Insert"},{"Selection":{"start":[0,7],"end":[0,7]}},{"Mode":"Insert"}]
@@ -0,0 +1 @@
+[{"Text":"The quick\n"},{"Mode":"Insert"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Insert"},{"Text":"The quick\n"},{"Mode":"Insert"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Insert"}]
@@ -0,0 +1 @@
+[{"Text":"The q\nbrown fox"},{"Mode":"Insert"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Insert"},{"Text":"The quick\n\nbrown fox"},{"Mode":"Insert"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Insert"}]
@@ -0,0 +1 @@
+[{"Text":"\njumps over\nthe lazy"},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"},{"Text":""},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"}]
@@ -0,0 +1 @@
+[{"Text":"Tst"},{"Mode":"Insert"},{"Selection":{"start":[0,1],"end":[0,1]}},{"Mode":"Insert"},{"Text":"est"},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"},{"Text":"Test"},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"},{"Text":"Test\ntest"},{"Mode":"Insert"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Insert"}]
@@ -0,0 +1 @@
+[{"Text":"The quick\n"},{"Mode":"Insert"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Insert"},{"Text":"\njumps over"},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"}]
@@ -0,0 +1 @@
+[{"Text":"\njumps over"},{"Mode":"Insert"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Insert"},{"Text":"The quick\n"},{"Mode":"Insert"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Insert"}]
@@ -0,0 +1 @@
+[{"Text":"Tet"},{"Mode":"Insert"},{"Selection":{"start":[0,2],"end":[0,2]}},{"Mode":"Insert"},{"Text":"Tes"},{"Mode":"Insert"},{"Selection":{"start":[0,3],"end":[0,3]}},{"Mode":"Insert"}]
@@ -1 +1 @@
@@ -0,0 +1 @@
+[{"Text":"Te"},{"Mode":"Insert"},{"Selection":{"start":[0,2],"end":[0,2]}},{"Mode":"Insert"},{"Text":"T test"},{"Mode":"Insert"},{"Selection":{"start":[0,1],"end":[0,1]}},{"Mode":"Insert"},{"Text":"Testtest"},{"Mode":"Insert"},{"Selection":{"start":[0,4],"end":[0,4]}},{"Mode":"Insert"},{"Text":"Test te\ntest"},{"Mode":"Insert"},{"Selection":{"start":[0,7],"end":[0,7]}},{"Mode":"Insert"},{"Text":"Test tes\ntest"},{"Mode":"Insert"},{"Selection":{"start":[0,8],"end":[0,8]}},{"Mode":"Insert"},{"Text":"Test test\n\ntest"},{"Mode":"Insert"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Insert"},{"Text":"Test te test"},{"Mode":"Insert"},{"Selection":{"start":[0,7],"end":[0,7]}},{"Mode":"Insert"}]
@@ -1 +1 @@
-[{"Text":""},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"},{"Text":""},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"},{"Text":"brown fox\njumps over"},{"Mode":"Normal"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Normal"},{"Text":"The quick\njumps over"},{"Mode":"Normal"},{"Selection":{"start":[1,6],"end":[1,6]}},{"Mode":"Normal"},{"Text":"The quick\nbrown fox"},{"Mode":"Normal"},{"Selection":{"start":[1,6],"end":[1,6]}},{"Mode":"Normal"},{"Text":"The quick\nbrown fox"},{"Mode":"Normal"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Normal"}]
+[{"Text":""},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"},{"Text":""},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"},{"Text":"brown fox\njumps over"},{"Mode":"Normal"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Normal"},{"Text":"The quick\njumps over"},{"Mode":"Normal"},{"Selection":{"start":[1,6],"end":[1,6]}},{"Mode":"Normal"},{"Text":"The quick\nbrown fox"},{"Mode":"Normal"},{"Selection":{"start":[1,6],"end":[1,6]}},{"Mode":"Normal"}]
@@ -0,0 +1 @@
+[{"Text":"uick\nbrown fox"},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"},{"Text":"The quick\n\nbrown fox"},{"Mode":"Normal"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Normal"}]
@@ -0,0 +1 @@
+[{"Text":"st Test"},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"},{"Text":"test"},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"},{"Text":"Test1 test3"},{"Mode":"Normal"},{"Selection":{"start":[0,6],"end":[0,6]}},{"Mode":"Normal"},{"Text":"Test \ntest"},{"Mode":"Normal"},{"Selection":{"start":[0,4],"end":[0,4]}},{"Mode":"Normal"},{"Text":"Test \n\ntest"},{"Mode":"Normal"},{"Selection":{"start":[0,4],"end":[0,4]}},{"Mode":"Normal"},{"Text":"Test test"},{"Mode":"Normal"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Normal"}]
@@ -0,0 +1 @@
+[{"Text":"Te Test"},{"Mode":"Normal"},{"Selection":{"start":[0,2],"end":[0,2]}},{"Mode":"Normal"},{"Text":"T test"},{"Mode":"Normal"},{"Selection":{"start":[0,1],"end":[0,1]}},{"Mode":"Normal"},{"Text":"Test te\ntest"},{"Mode":"Normal"},{"Selection":{"start":[0,6],"end":[0,6]}},{"Mode":"Normal"},{"Text":"Test tes"},{"Mode":"Normal"},{"Selection":{"start":[0,7],"end":[0,7]}},{"Mode":"Normal"},{"Text":"Test te test"},{"Mode":"Normal"},{"Selection":{"start":[0,7],"end":[0,7]}},{"Mode":"Normal"}]
@@ -0,0 +1 @@
+[{"Text":"The quick"},{"Mode":"Normal"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Normal"},{"Text":"The quick"},{"Mode":"Normal"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Normal"}]
@@ -0,0 +1 @@
+[{"Text":"The q\nbrown fox"},{"Mode":"Normal"},{"Selection":{"start":[0,4],"end":[0,4]}},{"Mode":"Normal"},{"Text":"The quick\n\nbrown fox"},{"Mode":"Normal"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Normal"}]
@@ -0,0 +1 @@
+[{"Text":"jumps over\nthe lazy"},{"Mode":"Normal"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Normal"},{"Text":""},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"}]
@@ -0,0 +1 @@
+[{"Text":"Tst"},{"Mode":"Normal"},{"Selection":{"start":[0,1],"end":[0,1]}},{"Mode":"Normal"},{"Text":"est"},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"},{"Text":"Test"},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"},{"Text":"Test\ntest"},{"Mode":"Normal"},{"Selection":{"start":[1,0],"end":[1,0]}},{"Mode":"Normal"}]
@@ -0,0 +1 @@
+[{"Text":"The quick"},{"Mode":"Normal"},{"Selection":{"start":[0,6],"end":[0,6]}},{"Mode":"Normal"},{"Text":"The quick\nbrown fox\njumps over"},{"Mode":"Normal"},{"Selection":{"start":[2,6],"end":[2,6]}},{"Mode":"Normal"},{"Text":"jumps over"},{"Mode":"Normal"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Normal"},{"Text":"The quick\nbrown fox\n"},{"Mode":"Normal"},{"Selection":{"start":[2,0],"end":[2,0]}},{"Mode":"Normal"}]
@@ -0,0 +1 @@
+[{"Text":"jumps over"},{"Mode":"Normal"},{"Selection":{"start":[0,6],"end":[0,6]}},{"Mode":"Normal"},{"Text":"The quick"},{"Mode":"Normal"},{"Selection":{"start":[0,6],"end":[0,6]}},{"Mode":"Normal"},{"Text":"The quick\nbrown fox\njumps over"},{"Mode":"Normal"},{"Selection":{"start":[0,5],"end":[0,5]}},{"Mode":"Normal"},{"Text":"brown fox\njumps over"},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"}]
@@ -0,0 +1 @@
+[{"Text":"est"},{"Mode":"Normal"},{"Selection":{"start":[0,0],"end":[0,0]}},{"Mode":"Normal"},{"Text":"Tet"},{"Mode":"Normal"},{"Selection":{"start":[0,2],"end":[0,2]}},{"Mode":"Normal"},{"Text":"Tes"},{"Mode":"Normal"},{"Selection":{"start":[0,2],"end":[0,2]}},{"Mode":"Normal"},{"Text":"Tes\ntest"},{"Mode":"Normal"},{"Selection":{"start":[0,2],"end":[0,2]}},{"Mode":"Normal"}]
@@ -1 +1 @@
@@ -0,0 +1 @@
+[{"Text":"Te"},{"Mode":"Normal"},{"Selection":{"start":[0,1],"end":[0,1]}},{"Mode":"Normal"},{"Text":"Ttest"},{"Mode":"Normal"},{"Selection":{"start":[0,1],"end":[0,1]}},{"Mode":"Normal"},{"Text":"Test te\ntest"},{"Mode":"Normal"},{"Selection":{"start":[0,6],"end":[0,6]}},{"Mode":"Normal"},{"Text":"Test tes\ntest"},{"Mode":"Normal"},{"Selection":{"start":[0,7],"end":[0,7]}},{"Mode":"Normal"},{"Text":"Test tetest"},{"Mode":"Normal"},{"Selection":{"start":[0,7],"end":[0,7]}},{"Mode":"Normal"}]
@@ -1 +1 @@