1mod change;
2mod delete;
3
4use crate::{
5 motion::Motion,
6 state::{Mode, Operator},
7 Vim,
8};
9use change::init as change_init;
10use gpui::{actions, MutableAppContext, ViewContext};
11use language::SelectionGoal;
12use workspace::Workspace;
13
14use self::{change::change_over, delete::delete_over};
15
16actions!(
17 vim,
18 [
19 InsertAfter,
20 InsertFirstNonWhitespace,
21 InsertEndOfLine,
22 InsertLineAbove,
23 InsertLineBelow,
24 DeleteLeft,
25 DeleteRight,
26 ChangeToEndOfLine,
27 DeleteToEndOfLine,
28 ]
29);
30
31pub fn init(cx: &mut MutableAppContext) {
32 cx.add_action(insert_after);
33 cx.add_action(insert_first_non_whitespace);
34 cx.add_action(insert_end_of_line);
35 cx.add_action(insert_line_above);
36 cx.add_action(insert_line_below);
37 cx.add_action(|_: &mut Workspace, _: &DeleteLeft, cx| {
38 Vim::update(cx, |vim, cx| {
39 delete_over(vim, Motion::Left, cx);
40 })
41 });
42 cx.add_action(|_: &mut Workspace, _: &DeleteRight, cx| {
43 Vim::update(cx, |vim, cx| {
44 delete_over(vim, Motion::Right, cx);
45 })
46 });
47 cx.add_action(|_: &mut Workspace, _: &ChangeToEndOfLine, cx| {
48 Vim::update(cx, |vim, cx| {
49 change_over(vim, Motion::EndOfLine, cx);
50 })
51 });
52 cx.add_action(|_: &mut Workspace, _: &DeleteToEndOfLine, cx| {
53 Vim::update(cx, |vim, cx| {
54 delete_over(vim, Motion::EndOfLine, cx);
55 })
56 });
57
58 change_init(cx);
59}
60
61pub fn normal_motion(motion: Motion, cx: &mut MutableAppContext) {
62 Vim::update(cx, |vim, cx| {
63 match vim.state.operator_stack.pop() {
64 None => move_cursor(vim, motion, cx),
65 Some(Operator::Change) => change_over(vim, motion, cx),
66 Some(Operator::Delete) => delete_over(vim, motion, cx),
67 Some(Operator::Namespace(_)) => {
68 // Can't do anything for a namespace operator. Ignoring
69 }
70 }
71 vim.clear_operator(cx);
72 });
73}
74
75fn move_cursor(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
76 vim.update_active_editor(cx, |editor, cx| {
77 editor.move_cursors(cx, |map, cursor, goal| motion.move_point(map, cursor, goal))
78 });
79}
80
81fn insert_after(_: &mut Workspace, _: &InsertAfter, cx: &mut ViewContext<Workspace>) {
82 Vim::update(cx, |vim, cx| {
83 vim.switch_mode(Mode::Insert, cx);
84 vim.update_active_editor(cx, |editor, cx| {
85 editor.move_cursors(cx, |map, cursor, goal| {
86 Motion::Right.move_point(map, cursor, goal)
87 });
88 });
89 });
90}
91
92fn insert_first_non_whitespace(
93 _: &mut Workspace,
94 _: &InsertFirstNonWhitespace,
95 cx: &mut ViewContext<Workspace>,
96) {
97 Vim::update(cx, |vim, cx| {
98 vim.switch_mode(Mode::Insert, cx);
99 vim.update_active_editor(cx, |editor, cx| {
100 editor.move_cursors(cx, |map, cursor, goal| {
101 Motion::FirstNonWhitespace.move_point(map, cursor, goal)
102 });
103 });
104 });
105}
106
107fn insert_end_of_line(_: &mut Workspace, _: &InsertEndOfLine, cx: &mut ViewContext<Workspace>) {
108 Vim::update(cx, |vim, cx| {
109 vim.switch_mode(Mode::Insert, cx);
110 vim.update_active_editor(cx, |editor, cx| {
111 editor.move_cursors(cx, |map, cursor, goal| {
112 Motion::EndOfLine.move_point(map, cursor, goal)
113 });
114 });
115 });
116}
117
118fn insert_line_above(_: &mut Workspace, _: &InsertLineAbove, cx: &mut ViewContext<Workspace>) {
119 Vim::update(cx, |vim, cx| {
120 vim.switch_mode(Mode::Insert, cx);
121 vim.update_active_editor(cx, |editor, cx| {
122 editor.transact(cx, |editor, cx| {
123 editor.move_cursors(cx, |map, cursor, goal| {
124 let (indent, _) = map.line_indent(cursor.row());
125 let (cursor, _) = Motion::EndOfLine.move_point(map, cursor, goal);
126 (cursor, SelectionGoal::Column(indent))
127 });
128 editor.insert("\n", cx);
129 editor.move_cursors(cx, |_, mut cursor, goal| {
130 if let SelectionGoal::Column(column) = goal {
131 *cursor.column_mut() = column;
132 }
133 (cursor, SelectionGoal::None)
134 });
135 });
136 });
137 });
138}
139
140fn insert_line_below(_: &mut Workspace, _: &InsertLineAbove, cx: &mut ViewContext<Workspace>) {
141 Vim::update(cx, |vim, cx| {
142 vim.switch_mode(Mode::Insert, cx);
143 vim.update_active_editor(cx, |editor, cx| {
144 editor.transact(cx, |editor, cx| {
145 editor.move_cursors(cx, |map, cursor, goal| {
146 let (indent, _) = map.line_indent(cursor.row());
147 let (cursor, _) = Motion::StartOfLine.move_point(map, cursor, goal);
148 (cursor, SelectionGoal::Column(indent))
149 });
150 editor.insert("\n", cx);
151 editor.move_cursors(cx, |_, mut cursor, goal| {
152 *cursor.row_mut() -= 1;
153 if let SelectionGoal::Column(column) = goal {
154 *cursor.column_mut() = column;
155 }
156 (cursor, SelectionGoal::None)
157 });
158 });
159 });
160 });
161}
162
163#[cfg(test)]
164mod test {
165 use indoc::indoc;
166 use util::test::marked_text;
167
168 use crate::{
169 state::{
170 Mode::{self, *},
171 Namespace, Operator,
172 },
173 vim_test_context::VimTestContext,
174 };
175
176 #[gpui::test]
177 async fn test_h(cx: &mut gpui::TestAppContext) {
178 let cx = VimTestContext::new(cx, true).await;
179 let mut cx = cx.binding(["h"]);
180 cx.assert("The q|uick", "The |quick");
181 cx.assert("|The quick", "|The quick");
182 cx.assert(
183 indoc! {"
184 The quick
185 |brown"},
186 indoc! {"
187 The quick
188 |brown"},
189 );
190 }
191
192 #[gpui::test]
193 async fn test_backspace(cx: &mut gpui::TestAppContext) {
194 let cx = VimTestContext::new(cx, true).await;
195 let mut cx = cx.binding(["backspace"]);
196 cx.assert("The q|uick", "The |quick");
197 cx.assert("|The quick", "|The quick");
198 cx.assert(
199 indoc! {"
200 The quick
201 |brown"},
202 indoc! {"
203 The quick
204 |brown"},
205 );
206 }
207
208 #[gpui::test]
209 async fn test_j(cx: &mut gpui::TestAppContext) {
210 let cx = VimTestContext::new(cx, true).await;
211 let mut cx = cx.binding(["j"]);
212 cx.assert(
213 indoc! {"
214 The |quick
215 brown fox"},
216 indoc! {"
217 The quick
218 brow|n fox"},
219 );
220 cx.assert(
221 indoc! {"
222 The quick
223 brow|n fox"},
224 indoc! {"
225 The quick
226 brow|n fox"},
227 );
228 cx.assert(
229 indoc! {"
230 The quic|k
231 brown"},
232 indoc! {"
233 The quick
234 brow|n"},
235 );
236 cx.assert(
237 indoc! {"
238 The quick
239 |brown"},
240 indoc! {"
241 The quick
242 |brown"},
243 );
244 }
245
246 #[gpui::test]
247 async fn test_k(cx: &mut gpui::TestAppContext) {
248 let cx = VimTestContext::new(cx, true).await;
249 let mut cx = cx.binding(["k"]);
250 cx.assert(
251 indoc! {"
252 The |quick
253 brown fox"},
254 indoc! {"
255 The |quick
256 brown fox"},
257 );
258 cx.assert(
259 indoc! {"
260 The quick
261 brow|n fox"},
262 indoc! {"
263 The |quick
264 brown fox"},
265 );
266 cx.assert(
267 indoc! {"
268 The
269 quic|k"},
270 indoc! {"
271 Th|e
272 quick"},
273 );
274 }
275
276 #[gpui::test]
277 async fn test_l(cx: &mut gpui::TestAppContext) {
278 let cx = VimTestContext::new(cx, true).await;
279 let mut cx = cx.binding(["l"]);
280 cx.assert("The q|uick", "The qu|ick");
281 cx.assert("The quic|k", "The quic|k");
282 cx.assert(
283 indoc! {"
284 The quic|k
285 brown"},
286 indoc! {"
287 The quic|k
288 brown"},
289 );
290 }
291
292 #[gpui::test]
293 async fn test_jump_to_line_boundaries(cx: &mut gpui::TestAppContext) {
294 let cx = VimTestContext::new(cx, true).await;
295 let mut cx = cx.binding(["shift-$"]);
296 cx.assert("T|est test", "Test tes|t");
297 cx.assert("Test tes|t", "Test tes|t");
298 cx.assert(
299 indoc! {"
300 The |quick
301 brown"},
302 indoc! {"
303 The quic|k
304 brown"},
305 );
306 cx.assert(
307 indoc! {"
308 The quic|k
309 brown"},
310 indoc! {"
311 The quic|k
312 brown"},
313 );
314
315 let mut cx = cx.binding(["0"]);
316 cx.assert("Test |test", "|Test test");
317 cx.assert("|Test test", "|Test test");
318 cx.assert(
319 indoc! {"
320 The |quick
321 brown"},
322 indoc! {"
323 |The quick
324 brown"},
325 );
326 cx.assert(
327 indoc! {"
328 |The quick
329 brown"},
330 indoc! {"
331 |The quick
332 brown"},
333 );
334 }
335
336 #[gpui::test]
337 async fn test_jump_to_end(cx: &mut gpui::TestAppContext) {
338 let cx = VimTestContext::new(cx, true).await;
339 let mut cx = cx.binding(["shift-G"]);
340
341 cx.assert(
342 indoc! {"
343 The |quick
344
345 brown fox jumps
346 over the lazy dog"},
347 indoc! {"
348 The quick
349
350 brown fox jumps
351 over| the lazy dog"},
352 );
353 cx.assert(
354 indoc! {"
355 The quick
356
357 brown fox jumps
358 over| the lazy dog"},
359 indoc! {"
360 The quick
361
362 brown fox jumps
363 over| the lazy dog"},
364 );
365 cx.assert(
366 indoc! {"
367 The qui|ck
368
369 brown"},
370 indoc! {"
371 The quick
372
373 brow|n"},
374 );
375 cx.assert(
376 indoc! {"
377 The qui|ck
378
379 "},
380 indoc! {"
381 The quick
382
383 |"},
384 );
385 }
386
387 #[gpui::test]
388 async fn test_w(cx: &mut gpui::TestAppContext) {
389 let mut cx = VimTestContext::new(cx, true).await;
390 let (_, cursor_offsets) = marked_text(indoc! {"
391 The |quick|-|brown
392 |
393 |
394 |fox_jumps |over
395 |th||e"});
396 cx.set_state(
397 indoc! {"
398 |The quick-brown
399
400
401 fox_jumps over
402 the"},
403 Mode::Normal,
404 );
405
406 for cursor_offset in cursor_offsets {
407 cx.simulate_keystroke("w");
408 cx.assert_newest_selection_head_offset(cursor_offset);
409 }
410
411 // Reset and test ignoring punctuation
412 let (_, cursor_offsets) = marked_text(indoc! {"
413 The |quick-brown
414 |
415 |
416 |fox_jumps |over
417 |th||e"});
418 cx.set_state(
419 indoc! {"
420 |The quick-brown
421
422
423 fox_jumps over
424 the"},
425 Mode::Normal,
426 );
427
428 for cursor_offset in cursor_offsets {
429 cx.simulate_keystroke("shift-W");
430 cx.assert_newest_selection_head_offset(cursor_offset);
431 }
432 }
433
434 #[gpui::test]
435 async fn test_e(cx: &mut gpui::TestAppContext) {
436 let mut cx = VimTestContext::new(cx, true).await;
437 let (_, cursor_offsets) = marked_text(indoc! {"
438 Th|e quic|k|-brow|n
439
440
441 fox_jump|s ove|r
442 th|e"});
443 cx.set_state(
444 indoc! {"
445 |The quick-brown
446
447
448 fox_jumps over
449 the"},
450 Mode::Normal,
451 );
452
453 for cursor_offset in cursor_offsets {
454 cx.simulate_keystroke("e");
455 cx.assert_newest_selection_head_offset(cursor_offset);
456 }
457
458 // Reset and test ignoring punctuation
459 let (_, cursor_offsets) = marked_text(indoc! {"
460 Th|e quick-brow|n
461
462
463 fox_jump|s ove|r
464 th||e"});
465 cx.set_state(
466 indoc! {"
467 |The quick-brown
468
469
470 fox_jumps over
471 the"},
472 Mode::Normal,
473 );
474 for cursor_offset in cursor_offsets {
475 cx.simulate_keystroke("shift-E");
476 cx.assert_newest_selection_head_offset(cursor_offset);
477 }
478 }
479
480 #[gpui::test]
481 async fn test_b(cx: &mut gpui::TestAppContext) {
482 let mut cx = VimTestContext::new(cx, true).await;
483 let (_, cursor_offsets) = marked_text(indoc! {"
484 ||The |quick|-|brown
485 |
486 |
487 |fox_jumps |over
488 |the"});
489 cx.set_state(
490 indoc! {"
491 The quick-brown
492
493
494 fox_jumps over
495 th|e"},
496 Mode::Normal,
497 );
498
499 for cursor_offset in cursor_offsets.into_iter().rev() {
500 cx.simulate_keystroke("b");
501 cx.assert_newest_selection_head_offset(cursor_offset);
502 }
503
504 // Reset and test ignoring punctuation
505 let (_, cursor_offsets) = marked_text(indoc! {"
506 ||The |quick-brown
507 |
508 |
509 |fox_jumps |over
510 |the"});
511 cx.set_state(
512 indoc! {"
513 The quick-brown
514
515
516 fox_jumps over
517 th|e"},
518 Mode::Normal,
519 );
520 for cursor_offset in cursor_offsets.into_iter().rev() {
521 cx.simulate_keystroke("shift-B");
522 cx.assert_newest_selection_head_offset(cursor_offset);
523 }
524 }
525
526 #[gpui::test]
527 async fn test_g_prefix_and_abort(cx: &mut gpui::TestAppContext) {
528 let mut cx = VimTestContext::new(cx, true).await;
529
530 // Can abort with escape to get back to normal mode
531 cx.simulate_keystroke("g");
532 assert_eq!(cx.mode(), Normal);
533 assert_eq!(
534 cx.active_operator(),
535 Some(Operator::Namespace(Namespace::G))
536 );
537 cx.simulate_keystroke("escape");
538 assert_eq!(cx.mode(), Normal);
539 assert_eq!(cx.active_operator(), None);
540 }
541
542 #[gpui::test]
543 async fn test_gg(cx: &mut gpui::TestAppContext) {
544 let cx = VimTestContext::new(cx, true).await;
545 let mut cx = cx.binding(["g", "g"]);
546 cx.assert(
547 indoc! {"
548 The quick
549
550 brown fox jumps
551 over |the lazy dog"},
552 indoc! {"
553 The q|uick
554
555 brown fox jumps
556 over the lazy dog"},
557 );
558 cx.assert(
559 indoc! {"
560 The q|uick
561
562 brown fox jumps
563 over the lazy dog"},
564 indoc! {"
565 The q|uick
566
567 brown fox jumps
568 over the lazy dog"},
569 );
570 cx.assert(
571 indoc! {"
572 The quick
573
574 brown fox jumps
575 over the la|zy dog"},
576 indoc! {"
577 The quic|k
578
579 brown fox jumps
580 over the lazy dog"},
581 );
582 cx.assert(
583 indoc! {"
584
585
586 brown fox jumps
587 over the la|zy dog"},
588 indoc! {"
589 |
590
591 brown fox jumps
592 over the lazy dog"},
593 );
594 }
595
596 #[gpui::test]
597 async fn test_a(cx: &mut gpui::TestAppContext) {
598 let cx = VimTestContext::new(cx, true).await;
599 let mut cx = cx.binding(["a"]).mode_after(Mode::Insert);
600
601 cx.assert("The q|uick", "The qu|ick");
602 cx.assert("The quic|k", "The quick|");
603 }
604
605 #[gpui::test]
606 async fn test_insert_end_of_line(cx: &mut gpui::TestAppContext) {
607 let cx = VimTestContext::new(cx, true).await;
608 let mut cx = cx.binding(["shift-A"]).mode_after(Mode::Insert);
609 cx.assert("The q|uick", "The quick|");
610 cx.assert("The q|uick ", "The quick |");
611 cx.assert("|", "|");
612 cx.assert(
613 indoc! {"
614 The q|uick
615 brown fox"},
616 indoc! {"
617 The quick|
618 brown fox"},
619 );
620 cx.assert(
621 indoc! {"
622 |
623 The quick"},
624 indoc! {"
625 |
626 The quick"},
627 );
628 }
629
630 #[gpui::test]
631 async fn test_jump_to_first_non_whitespace(cx: &mut gpui::TestAppContext) {
632 let cx = VimTestContext::new(cx, true).await;
633 let mut cx = cx.binding(["shift-^"]);
634 cx.assert("The q|uick", "|The quick");
635 cx.assert(" The q|uick", " |The quick");
636 cx.assert("|", "|");
637 cx.assert(
638 indoc! {"
639 The q|uick
640 brown fox"},
641 indoc! {"
642 |The quick
643 brown fox"},
644 );
645 cx.assert(
646 indoc! {"
647 |
648 The quick"},
649 indoc! {"
650 |
651 The quick"},
652 );
653 cx.assert(
654 indoc! {"
655 |
656 The quick"},
657 indoc! {"
658 |
659 The quick"},
660 );
661 }
662
663 #[gpui::test]
664 async fn test_insert_first_non_whitespace(cx: &mut gpui::TestAppContext) {
665 let cx = VimTestContext::new(cx, true).await;
666 let mut cx = cx.binding(["shift-I"]).mode_after(Mode::Insert);
667 cx.assert("The q|uick", "|The quick");
668 cx.assert(" The q|uick", " |The quick");
669 cx.assert("|", "|");
670 cx.assert(
671 indoc! {"
672 The q|uick
673 brown fox"},
674 indoc! {"
675 |The quick
676 brown fox"},
677 );
678 cx.assert(
679 indoc! {"
680 |
681 The quick"},
682 indoc! {"
683 |
684 The quick"},
685 );
686 }
687
688 #[gpui::test]
689 async fn test_delete_to_end_of_line(cx: &mut gpui::TestAppContext) {
690 let cx = VimTestContext::new(cx, true).await;
691 let mut cx = cx.binding(["shift-D"]);
692 cx.assert(
693 indoc! {"
694 The q|uick
695 brown fox"},
696 indoc! {"
697 The |q
698 brown fox"},
699 );
700 cx.assert(
701 indoc! {"
702 The quick
703 |
704 brown fox"},
705 indoc! {"
706 The quick
707 |
708 brown fox"},
709 );
710 }
711
712 #[gpui::test]
713 async fn test_x(cx: &mut gpui::TestAppContext) {
714 let cx = VimTestContext::new(cx, true).await;
715 let mut cx = cx.binding(["x"]);
716 cx.assert("|Test", "|est");
717 cx.assert("Te|st", "Te|t");
718 cx.assert("Tes|t", "Te|s");
719 cx.assert(
720 indoc! {"
721 Tes|t
722 test"},
723 indoc! {"
724 Te|s
725 test"},
726 );
727 }
728
729 #[gpui::test]
730 async fn test_delete_left(cx: &mut gpui::TestAppContext) {
731 let cx = VimTestContext::new(cx, true).await;
732 let mut cx = cx.binding(["shift-X"]);
733 cx.assert("Te|st", "T|st");
734 cx.assert("T|est", "|est");
735 cx.assert("|Test", "|Test");
736 cx.assert(
737 indoc! {"
738 Test
739 |test"},
740 indoc! {"
741 Test
742 |test"},
743 );
744 }
745
746 #[gpui::test]
747 async fn test_o(cx: &mut gpui::TestAppContext) {
748 let cx = VimTestContext::new(cx, true).await;
749 let mut cx = cx.binding(["o"]).mode_after(Mode::Insert);
750
751 cx.assert(
752 "|",
753 indoc! {"
754
755 |"},
756 );
757 cx.assert(
758 "The |quick",
759 indoc! {"
760 The quick
761 |"},
762 );
763 cx.assert(
764 indoc! {"
765 The quick
766 brown |fox
767 jumps over"},
768 indoc! {"
769 The quick
770 brown fox
771 |
772 jumps over"},
773 );
774 cx.assert(
775 indoc! {"
776 The quick
777 brown fox
778 jumps |over"},
779 indoc! {"
780 The quick
781 brown fox
782 jumps over
783 |"},
784 );
785 cx.assert(
786 indoc! {"
787 The q|uick
788 brown fox
789 jumps over"},
790 indoc! {"
791 The quick
792 |
793 brown fox
794 jumps over"},
795 );
796 cx.assert(
797 indoc! {"
798 The quick
799 |
800 brown fox"},
801 indoc! {"
802 The quick
803
804 |
805 brown fox"},
806 );
807 cx.assert(
808 indoc! {"
809 fn test() {
810 println!(|);
811 }"},
812 indoc! {"
813 fn test() {
814 println!();
815 |
816 }"},
817 );
818 cx.assert(
819 indoc! {"
820 fn test(|) {
821 println!();
822 }"},
823 indoc! {"
824 fn test() {
825 |
826 println!();
827 }"},
828 );
829 }
830
831 #[gpui::test]
832 async fn test_insert_line_above(cx: &mut gpui::TestAppContext) {
833 let cx = VimTestContext::new(cx, true).await;
834 let mut cx = cx.binding(["shift-O"]).mode_after(Mode::Insert);
835
836 cx.assert(
837 "|",
838 indoc! {"
839 |
840 "},
841 );
842 cx.assert(
843 "The |quick",
844 indoc! {"
845 |
846 The quick"},
847 );
848 cx.assert(
849 indoc! {"
850 The quick
851 brown |fox
852 jumps over"},
853 indoc! {"
854 The quick
855 |
856 brown fox
857 jumps over"},
858 );
859 cx.assert(
860 indoc! {"
861 The quick
862 brown fox
863 jumps |over"},
864 indoc! {"
865 The quick
866 brown fox
867 |
868 jumps over"},
869 );
870 cx.assert(
871 indoc! {"
872 The q|uick
873 brown fox
874 jumps over"},
875 indoc! {"
876 |
877 The quick
878 brown fox
879 jumps over"},
880 );
881 cx.assert(
882 indoc! {"
883 The quick
884 |
885 brown fox"},
886 indoc! {"
887 The quick
888 |
889
890 brown fox"},
891 );
892 cx.assert(
893 indoc! {"
894 fn test() {
895 println!(|);
896 }"},
897 indoc! {"
898 fn test() {
899 |
900 println!();
901 }"},
902 );
903 cx.assert(
904 indoc! {"
905 fn test(|) {
906 println!();
907 }"},
908 indoc! {"
909 |
910 fn test() {
911 println!();
912 }"},
913 );
914 }
915
916 #[gpui::test]
917 async fn test_dd(cx: &mut gpui::TestAppContext) {
918 let cx = VimTestContext::new(cx, true).await;
919 let mut cx = cx.binding(["d", "d"]);
920
921 cx.assert("|", "|");
922 cx.assert("The |quick", "|");
923 cx.assert(
924 indoc! {"
925 The quick
926 brown |fox
927 jumps over"},
928 indoc! {"
929 The quick
930 jumps |over"},
931 );
932 cx.assert(
933 indoc! {"
934 The quick
935 brown fox
936 jumps |over"},
937 indoc! {"
938 The quick
939 brown |fox"},
940 );
941 cx.assert(
942 indoc! {"
943 The q|uick
944 brown fox
945 jumps over"},
946 indoc! {"
947 brown| fox
948 jumps over"},
949 );
950 cx.assert(
951 indoc! {"
952 The quick
953 |
954 brown fox"},
955 indoc! {"
956 The quick
957 |brown fox"},
958 );
959 }
960
961 #[gpui::test]
962 async fn test_cc(cx: &mut gpui::TestAppContext) {
963 let cx = VimTestContext::new(cx, true).await;
964 let mut cx = cx.binding(["c", "c"]).mode_after(Mode::Insert);
965
966 cx.assert("|", "|");
967 cx.assert("The |quick", "|");
968 cx.assert(
969 indoc! {"
970 The quick
971 brown |fox
972 jumps over"},
973 indoc! {"
974 The quick
975 |
976 jumps over"},
977 );
978 cx.assert(
979 indoc! {"
980 The quick
981 brown fox
982 jumps |over"},
983 indoc! {"
984 The quick
985 brown fox
986 |"},
987 );
988 cx.assert(
989 indoc! {"
990 The q|uick
991 brown fox
992 jumps over"},
993 indoc! {"
994 |
995 brown fox
996 jumps over"},
997 );
998 cx.assert(
999 indoc! {"
1000 The quick
1001 |
1002 brown fox"},
1003 indoc! {"
1004 The quick
1005 |
1006 brown fox"},
1007 );
1008 }
1009}