normal.rs

   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}