test.rs

   1mod neovim_backed_test_context;
   2mod neovim_connection;
   3mod vim_test_context;
   4
   5use std::time::Duration;
   6
   7use collections::HashMap;
   8use command_palette::CommandPalette;
   9use editor::{actions::DeleteLine, display_map::DisplayRow, DisplayPoint};
  10use futures::StreamExt;
  11use gpui::{KeyBinding, Modifiers, MouseButton, TestAppContext};
  12pub use neovim_backed_test_context::*;
  13use settings::SettingsStore;
  14pub use vim_test_context::*;
  15
  16use indoc::indoc;
  17use search::BufferSearchBar;
  18use workspace::WorkspaceSettings;
  19
  20use crate::{insert::NormalBefore, motion, state::Mode};
  21
  22#[gpui::test]
  23async fn test_initially_disabled(cx: &mut gpui::TestAppContext) {
  24    let mut cx = VimTestContext::new(cx, false).await;
  25    cx.simulate_keystrokes("h j k l");
  26    cx.assert_editor_state("hjklˇ");
  27}
  28
  29#[gpui::test]
  30async fn test_neovim(cx: &mut gpui::TestAppContext) {
  31    let mut cx = NeovimBackedTestContext::new(cx).await;
  32
  33    cx.simulate_shared_keystrokes("i").await;
  34    cx.shared_state().await.assert_matches();
  35    cx.simulate_shared_keystrokes("shift-t e s t space t e s t escape 0 d w")
  36        .await;
  37    cx.shared_state().await.assert_matches();
  38    cx.assert_editor_state("ˇtest");
  39}
  40
  41#[gpui::test]
  42async fn test_toggle_through_settings(cx: &mut gpui::TestAppContext) {
  43    let mut cx = VimTestContext::new(cx, true).await;
  44
  45    cx.simulate_keystrokes("i");
  46    assert_eq!(cx.mode(), Mode::Insert);
  47
  48    // Editor acts as though vim is disabled
  49    cx.disable_vim();
  50    cx.simulate_keystrokes("h j k l");
  51    cx.assert_editor_state("hjklˇ");
  52
  53    // Selections aren't changed if editor is blurred but vim-mode is still disabled.
  54    cx.cx.set_state("«hjklˇ»");
  55    cx.assert_editor_state("«hjklˇ»");
  56    cx.update_editor(|_, cx| cx.blur());
  57    cx.assert_editor_state("«hjklˇ»");
  58    cx.update_editor(|_, cx| cx.focus_self());
  59    cx.assert_editor_state("«hjklˇ»");
  60
  61    // Enabling dynamically sets vim mode again and restores normal mode
  62    cx.enable_vim();
  63    assert_eq!(cx.mode(), Mode::Normal);
  64    cx.simulate_keystrokes("h h h l");
  65    assert_eq!(cx.buffer_text(), "hjkl".to_owned());
  66    cx.assert_editor_state("hˇjkl");
  67    cx.simulate_keystrokes("i T e s t");
  68    cx.assert_editor_state("hTestˇjkl");
  69
  70    // Disabling and enabling resets to normal mode
  71    assert_eq!(cx.mode(), Mode::Insert);
  72    cx.disable_vim();
  73    cx.enable_vim();
  74    assert_eq!(cx.mode(), Mode::Normal);
  75}
  76
  77#[gpui::test]
  78async fn test_cancel_selection(cx: &mut gpui::TestAppContext) {
  79    let mut cx = VimTestContext::new(cx, true).await;
  80
  81    cx.set_state(
  82        indoc! {"The quick brown fox juˇmps over the lazy dog"},
  83        Mode::Normal,
  84    );
  85    // jumps
  86    cx.simulate_keystrokes("v l l");
  87    cx.assert_editor_state("The quick brown fox ju«mpsˇ» over the lazy dog");
  88
  89    cx.simulate_keystrokes("escape");
  90    cx.assert_editor_state("The quick brown fox jumpˇs over the lazy dog");
  91
  92    // go back to the same selection state
  93    cx.simulate_keystrokes("v h h");
  94    cx.assert_editor_state("The quick brown fox ju«ˇmps» over the lazy dog");
  95
  96    // Ctrl-[ should behave like Esc
  97    cx.simulate_keystrokes("ctrl-[");
  98    cx.assert_editor_state("The quick brown fox juˇmps over the lazy dog");
  99}
 100
 101#[gpui::test]
 102async fn test_buffer_search(cx: &mut gpui::TestAppContext) {
 103    let mut cx = VimTestContext::new(cx, true).await;
 104
 105    cx.set_state(
 106        indoc! {"
 107            The quick brown
 108            fox juˇmps over
 109            the lazy dog"},
 110        Mode::Normal,
 111    );
 112    cx.simulate_keystrokes("/");
 113
 114    let search_bar = cx.workspace(|workspace, cx| {
 115        workspace
 116            .active_pane()
 117            .read(cx)
 118            .toolbar()
 119            .read(cx)
 120            .item_of_type::<BufferSearchBar>()
 121            .expect("Buffer search bar should be deployed")
 122    });
 123
 124    cx.update_view(search_bar, |bar, cx| {
 125        assert_eq!(bar.query(cx), "");
 126    })
 127}
 128
 129#[gpui::test]
 130async fn test_count_down(cx: &mut gpui::TestAppContext) {
 131    let mut cx = VimTestContext::new(cx, true).await;
 132
 133    cx.set_state(indoc! {"aˇa\nbb\ncc\ndd\nee"}, Mode::Normal);
 134    cx.simulate_keystrokes("2 down");
 135    cx.assert_editor_state("aa\nbb\ncˇc\ndd\nee");
 136    cx.simulate_keystrokes("9 down");
 137    cx.assert_editor_state("aa\nbb\ncc\ndd\neˇe");
 138}
 139
 140#[gpui::test]
 141async fn test_end_of_document_710(cx: &mut gpui::TestAppContext) {
 142    let mut cx = VimTestContext::new(cx, true).await;
 143
 144    // goes to end by default
 145    cx.set_state(indoc! {"aˇa\nbb\ncc"}, Mode::Normal);
 146    cx.simulate_keystrokes("shift-g");
 147    cx.assert_editor_state("aa\nbb\ncˇc");
 148
 149    // can go to line 1 (https://github.com/zed-industries/zed/issues/5812)
 150    cx.simulate_keystrokes("1 shift-g");
 151    cx.assert_editor_state("aˇa\nbb\ncc");
 152}
 153
 154#[gpui::test]
 155async fn test_end_of_line_with_times(cx: &mut gpui::TestAppContext) {
 156    let mut cx = VimTestContext::new(cx, true).await;
 157
 158    // goes to current line end
 159    cx.set_state(indoc! {"ˇaa\nbb\ncc"}, Mode::Normal);
 160    cx.simulate_keystrokes("$");
 161    cx.assert_editor_state("aˇa\nbb\ncc");
 162
 163    // goes to next line end
 164    cx.simulate_keystrokes("2 $");
 165    cx.assert_editor_state("aa\nbˇb\ncc");
 166
 167    // try to exceed the final line.
 168    cx.simulate_keystrokes("4 $");
 169    cx.assert_editor_state("aa\nbb\ncˇc");
 170}
 171
 172#[gpui::test]
 173async fn test_indent_outdent(cx: &mut gpui::TestAppContext) {
 174    let mut cx = VimTestContext::new(cx, true).await;
 175
 176    // works in normal mode
 177    cx.set_state(indoc! {"aa\nbˇb\ncc"}, Mode::Normal);
 178    cx.simulate_keystrokes("> >");
 179    cx.assert_editor_state("aa\n    bˇb\ncc");
 180    cx.simulate_keystrokes("< <");
 181    cx.assert_editor_state("aa\nbˇb\ncc");
 182
 183    // works in visual mode
 184    cx.simulate_keystrokes("shift-v down >");
 185    cx.assert_editor_state("aa\n    bˇb\n    cc");
 186
 187    // works as operator
 188    cx.set_state("aa\nbˇb\ncc\n", Mode::Normal);
 189    cx.simulate_keystrokes("> j");
 190    cx.assert_editor_state("aa\n    bˇb\n    cc\n");
 191    cx.simulate_keystrokes("< k");
 192    cx.assert_editor_state("aa\nbˇb\n    cc\n");
 193    cx.simulate_keystrokes("> i p");
 194    cx.assert_editor_state("    aa\n    bˇb\n        cc\n");
 195    cx.simulate_keystrokes("< i p");
 196    cx.assert_editor_state("aa\nbˇb\n    cc\n");
 197    cx.simulate_keystrokes("< i p");
 198    cx.assert_editor_state("aa\nbˇb\ncc\n");
 199
 200    cx.set_state("ˇaa\nbb\ncc\n", Mode::Normal);
 201    cx.simulate_keystrokes("> 2 j");
 202    cx.assert_editor_state("    ˇaa\n    bb\n    cc\n");
 203
 204    cx.set_state("aa\nbb\nˇcc\n", Mode::Normal);
 205    cx.simulate_keystrokes("> 2 k");
 206    cx.assert_editor_state("    aa\n    bb\n    ˇcc\n");
 207
 208    // works with repeat
 209    cx.set_state("a\nb\nccˇc\n", Mode::Normal);
 210    cx.simulate_keystrokes("> 2 k");
 211    cx.assert_editor_state("    a\n    b\n    ccˇc\n");
 212    cx.simulate_keystrokes(".");
 213    cx.assert_editor_state("        a\n        b\n        ccˇc\n");
 214    cx.simulate_keystrokes("v k <");
 215    cx.assert_editor_state("        a\n\n    ccc\n");
 216    cx.simulate_keystrokes(".");
 217    cx.assert_editor_state("        a\n\nccc\n");
 218}
 219
 220#[gpui::test]
 221async fn test_escape_command_palette(cx: &mut gpui::TestAppContext) {
 222    let mut cx = VimTestContext::new(cx, true).await;
 223
 224    cx.set_state("aˇbc\n", Mode::Normal);
 225    cx.simulate_keystrokes("i cmd-shift-p");
 226
 227    assert!(cx.workspace(|workspace, cx| workspace.active_modal::<CommandPalette>(cx).is_some()));
 228    cx.simulate_keystrokes("escape");
 229    cx.run_until_parked();
 230    assert!(!cx.workspace(|workspace, cx| workspace.active_modal::<CommandPalette>(cx).is_some()));
 231    cx.assert_state("aˇbc\n", Mode::Insert);
 232}
 233
 234#[gpui::test]
 235async fn test_escape_cancels(cx: &mut gpui::TestAppContext) {
 236    let mut cx = VimTestContext::new(cx, true).await;
 237
 238    cx.set_state("aˇbˇc", Mode::Normal);
 239    cx.simulate_keystrokes("escape");
 240
 241    cx.assert_state("aˇbc", Mode::Normal);
 242}
 243
 244#[gpui::test]
 245async fn test_selection_on_search(cx: &mut gpui::TestAppContext) {
 246    let mut cx = VimTestContext::new(cx, true).await;
 247
 248    cx.set_state(indoc! {"aa\nbˇb\ncc\ncc\ncc\n"}, Mode::Normal);
 249    cx.simulate_keystrokes("/ c c");
 250
 251    let search_bar = cx.workspace(|workspace, cx| {
 252        workspace
 253            .active_pane()
 254            .read(cx)
 255            .toolbar()
 256            .read(cx)
 257            .item_of_type::<BufferSearchBar>()
 258            .expect("Buffer search bar should be deployed")
 259    });
 260
 261    cx.update_view(search_bar, |bar, cx| {
 262        assert_eq!(bar.query(cx), "cc");
 263    });
 264
 265    cx.update_editor(|editor, cx| {
 266        let highlights = editor.all_text_background_highlights(cx);
 267        assert_eq!(3, highlights.len());
 268        assert_eq!(
 269            DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 2),
 270            highlights[0].0
 271        )
 272    });
 273    cx.simulate_keystrokes("enter");
 274
 275    cx.assert_state(indoc! {"aa\nbb\nˇcc\ncc\ncc\n"}, Mode::Normal);
 276    cx.simulate_keystrokes("n");
 277    cx.assert_state(indoc! {"aa\nbb\ncc\nˇcc\ncc\n"}, Mode::Normal);
 278    cx.simulate_keystrokes("shift-n");
 279    cx.assert_state(indoc! {"aa\nbb\nˇcc\ncc\ncc\n"}, Mode::Normal);
 280}
 281
 282#[gpui::test]
 283async fn test_word_characters(cx: &mut gpui::TestAppContext) {
 284    let mut cx = VimTestContext::new_typescript(cx).await;
 285    cx.set_state(
 286        indoc! { "
 287        class A {
 288            #ˇgoop = 99;
 289            $ˇgoop () { return this.#gˇoop };
 290        };
 291        console.log(new A().$gooˇp())
 292    "},
 293        Mode::Normal,
 294    );
 295    cx.simulate_keystrokes("v i w");
 296    cx.assert_state(
 297        indoc! {"
 298        class A {
 299            «#goopˇ» = 99;
 300            «$goopˇ» () { return this.«#goopˇ» };
 301        };
 302        console.log(new A().«$goopˇ»())
 303    "},
 304        Mode::Visual,
 305    )
 306}
 307
 308#[gpui::test]
 309async fn test_kebab_case(cx: &mut gpui::TestAppContext) {
 310    let mut cx = VimTestContext::new_html(cx).await;
 311    cx.set_state(
 312        indoc! { r#"
 313            <div><a class="bg-rˇed"></a></div>
 314            "#},
 315        Mode::Normal,
 316    );
 317    cx.simulate_keystrokes("v i w");
 318    cx.assert_state(
 319        indoc! { r#"
 320        <div><a class="bg-«redˇ»"></a></div>
 321        "#
 322        },
 323        Mode::Visual,
 324    )
 325}
 326
 327#[gpui::test]
 328async fn test_join_lines(cx: &mut gpui::TestAppContext) {
 329    let mut cx = NeovimBackedTestContext::new(cx).await;
 330
 331    cx.set_shared_state(indoc! {"
 332      ˇone
 333      two
 334      three
 335      four
 336      five
 337      six
 338      "})
 339        .await;
 340    cx.simulate_shared_keystrokes("shift-j").await;
 341    cx.shared_state().await.assert_eq(indoc! {"
 342          oneˇ two
 343          three
 344          four
 345          five
 346          six
 347          "});
 348    cx.simulate_shared_keystrokes("3 shift-j").await;
 349    cx.shared_state().await.assert_eq(indoc! {"
 350          one two threeˇ four
 351          five
 352          six
 353          "});
 354
 355    cx.set_shared_state(indoc! {"
 356      ˇone
 357      two
 358      three
 359      four
 360      five
 361      six
 362      "})
 363        .await;
 364    cx.simulate_shared_keystrokes("j v 3 j shift-j").await;
 365    cx.shared_state().await.assert_eq(indoc! {"
 366      one
 367      two three fourˇ five
 368      six
 369      "});
 370}
 371
 372#[cfg(target_os = "macos")]
 373#[gpui::test]
 374async fn test_wrapped_lines(cx: &mut gpui::TestAppContext) {
 375    let mut cx = NeovimBackedTestContext::new(cx).await;
 376
 377    cx.set_shared_wrap(12).await;
 378    // tests line wrap as follows:
 379    //  1: twelve char
 380    //     twelve char
 381    //  2: twelve char
 382    cx.set_shared_state(indoc! { "
 383        tˇwelve char twelve char
 384        twelve char
 385    "})
 386        .await;
 387    cx.simulate_shared_keystrokes("j").await;
 388    cx.shared_state().await.assert_eq(indoc! {"
 389        twelve char twelve char
 390        tˇwelve char
 391    "});
 392    cx.simulate_shared_keystrokes("k").await;
 393    cx.shared_state().await.assert_eq(indoc! {"
 394        tˇwelve char twelve char
 395        twelve char
 396    "});
 397    cx.simulate_shared_keystrokes("g j").await;
 398    cx.shared_state().await.assert_eq(indoc! {"
 399        twelve char tˇwelve char
 400        twelve char
 401    "});
 402    cx.simulate_shared_keystrokes("g j").await;
 403    cx.shared_state().await.assert_eq(indoc! {"
 404        twelve char twelve char
 405        tˇwelve char
 406    "});
 407
 408    cx.simulate_shared_keystrokes("g k").await;
 409    cx.shared_state().await.assert_eq(indoc! {"
 410        twelve char tˇwelve char
 411        twelve char
 412    "});
 413
 414    cx.simulate_shared_keystrokes("g ^").await;
 415    cx.shared_state().await.assert_eq(indoc! {"
 416        twelve char ˇtwelve char
 417        twelve char
 418    "});
 419
 420    cx.simulate_shared_keystrokes("^").await;
 421    cx.shared_state().await.assert_eq(indoc! {"
 422        ˇtwelve char twelve char
 423        twelve char
 424    "});
 425
 426    cx.simulate_shared_keystrokes("g $").await;
 427    cx.shared_state().await.assert_eq(indoc! {"
 428        twelve charˇ twelve char
 429        twelve char
 430    "});
 431    cx.simulate_shared_keystrokes("$").await;
 432    cx.shared_state().await.assert_eq(indoc! {"
 433        twelve char twelve chaˇr
 434        twelve char
 435    "});
 436
 437    cx.set_shared_state(indoc! { "
 438        tˇwelve char twelve char
 439        twelve char
 440    "})
 441        .await;
 442    cx.simulate_shared_keystrokes("enter").await;
 443    cx.shared_state().await.assert_eq(indoc! {"
 444            twelve char twelve char
 445            ˇtwelve char
 446        "});
 447
 448    cx.set_shared_state(indoc! { "
 449        twelve char
 450        tˇwelve char twelve char
 451        twelve char
 452    "})
 453        .await;
 454    cx.simulate_shared_keystrokes("o o escape").await;
 455    cx.shared_state().await.assert_eq(indoc! {"
 456        twelve char
 457        twelve char twelve char
 458        ˇo
 459        twelve char
 460    "});
 461
 462    cx.set_shared_state(indoc! { "
 463        twelve char
 464        tˇwelve char twelve char
 465        twelve char
 466    "})
 467        .await;
 468    cx.simulate_shared_keystrokes("shift-a a escape").await;
 469    cx.shared_state().await.assert_eq(indoc! {"
 470        twelve char
 471        twelve char twelve charˇa
 472        twelve char
 473    "});
 474    cx.simulate_shared_keystrokes("shift-i i escape").await;
 475    cx.shared_state().await.assert_eq(indoc! {"
 476        twelve char
 477        ˇitwelve char twelve chara
 478        twelve char
 479    "});
 480    cx.simulate_shared_keystrokes("shift-d").await;
 481    cx.shared_state().await.assert_eq(indoc! {"
 482        twelve char
 483        ˇ
 484        twelve char
 485    "});
 486
 487    cx.set_shared_state(indoc! { "
 488        twelve char
 489        twelve char tˇwelve char
 490        twelve char
 491    "})
 492        .await;
 493    cx.simulate_shared_keystrokes("shift-o o escape").await;
 494    cx.shared_state().await.assert_eq(indoc! {"
 495        twelve char
 496        ˇo
 497        twelve char twelve char
 498        twelve char
 499    "});
 500
 501    // line wraps as:
 502    // fourteen ch
 503    // ar
 504    // fourteen ch
 505    // ar
 506    cx.set_shared_state(indoc! { "
 507        fourteen chaˇr
 508        fourteen char
 509    "})
 510        .await;
 511
 512    cx.simulate_shared_keystrokes("d i w").await;
 513    cx.shared_state().await.assert_eq(indoc! {"
 514        fourteenˇ•
 515        fourteen char
 516    "});
 517    cx.simulate_shared_keystrokes("j shift-f e f r").await;
 518    cx.shared_state().await.assert_eq(indoc! {"
 519        fourteen•
 520        fourteen chaˇr
 521    "});
 522}
 523
 524#[gpui::test]
 525async fn test_folds(cx: &mut gpui::TestAppContext) {
 526    let mut cx = NeovimBackedTestContext::new(cx).await;
 527    cx.set_neovim_option("foldmethod=manual").await;
 528
 529    cx.set_shared_state(indoc! { "
 530        fn boop() {
 531          ˇbarp()
 532          bazp()
 533        }
 534    "})
 535        .await;
 536    cx.simulate_shared_keystrokes("shift-v j z f").await;
 537
 538    // visual display is now:
 539    // fn boop () {
 540    //  [FOLDED]
 541    // }
 542
 543    // TODO: this should not be needed but currently zf does not
 544    // return to normal mode.
 545    cx.simulate_shared_keystrokes("escape").await;
 546
 547    // skip over fold downward
 548    cx.simulate_shared_keystrokes("g g").await;
 549    cx.shared_state().await.assert_eq(indoc! {"
 550        ˇfn boop() {
 551          barp()
 552          bazp()
 553        }
 554    "});
 555
 556    cx.simulate_shared_keystrokes("j j").await;
 557    cx.shared_state().await.assert_eq(indoc! {"
 558        fn boop() {
 559          barp()
 560          bazp()
 561        ˇ}
 562    "});
 563
 564    // skip over fold upward
 565    cx.simulate_shared_keystrokes("2 k").await;
 566    cx.shared_state().await.assert_eq(indoc! {"
 567        ˇfn boop() {
 568          barp()
 569          bazp()
 570        }
 571    "});
 572
 573    // yank the fold
 574    cx.simulate_shared_keystrokes("down y y").await;
 575    cx.shared_clipboard()
 576        .await
 577        .assert_eq("  barp()\n  bazp()\n");
 578
 579    // re-open
 580    cx.simulate_shared_keystrokes("z o").await;
 581    cx.shared_state().await.assert_eq(indoc! {"
 582        fn boop() {
 583        ˇ  barp()
 584          bazp()
 585        }
 586    "});
 587}
 588
 589#[gpui::test]
 590async fn test_folds_panic(cx: &mut gpui::TestAppContext) {
 591    let mut cx = NeovimBackedTestContext::new(cx).await;
 592    cx.set_neovim_option("foldmethod=manual").await;
 593
 594    cx.set_shared_state(indoc! { "
 595        fn boop() {
 596          ˇbarp()
 597          bazp()
 598        }
 599    "})
 600        .await;
 601    cx.simulate_shared_keystrokes("shift-v j z f").await;
 602    cx.simulate_shared_keystrokes("escape").await;
 603    cx.simulate_shared_keystrokes("g g").await;
 604    cx.simulate_shared_keystrokes("5 d j").await;
 605    cx.shared_state().await.assert_eq("ˇ");
 606    cx.set_shared_state(indoc! {"
 607        fn boop() {
 608          ˇbarp()
 609          bazp()
 610        }
 611    "})
 612        .await;
 613    cx.simulate_shared_keystrokes("shift-v j j z f").await;
 614    cx.simulate_shared_keystrokes("escape").await;
 615    cx.simulate_shared_keystrokes("shift-g shift-v").await;
 616    cx.shared_state().await.assert_eq(indoc! {"
 617        fn boop() {
 618          barp()
 619          bazp()
 620        }
 621        ˇ"});
 622}
 623
 624#[gpui::test]
 625async fn test_clear_counts(cx: &mut gpui::TestAppContext) {
 626    let mut cx = NeovimBackedTestContext::new(cx).await;
 627
 628    cx.set_shared_state(indoc! {"
 629        The quick brown
 630        fox juˇmps over
 631        the lazy dog"})
 632        .await;
 633
 634    cx.simulate_shared_keystrokes("4 escape 3 d l").await;
 635    cx.shared_state().await.assert_eq(indoc! {"
 636        The quick brown
 637        fox juˇ over
 638        the lazy dog"});
 639}
 640
 641#[gpui::test]
 642async fn test_zero(cx: &mut gpui::TestAppContext) {
 643    let mut cx = NeovimBackedTestContext::new(cx).await;
 644
 645    cx.set_shared_state(indoc! {"
 646        The quˇick brown
 647        fox jumps over
 648        the lazy dog"})
 649        .await;
 650
 651    cx.simulate_shared_keystrokes("0").await;
 652    cx.shared_state().await.assert_eq(indoc! {"
 653        ˇThe quick brown
 654        fox jumps over
 655        the lazy dog"});
 656
 657    cx.simulate_shared_keystrokes("1 0 l").await;
 658    cx.shared_state().await.assert_eq(indoc! {"
 659        The quick ˇbrown
 660        fox jumps over
 661        the lazy dog"});
 662}
 663
 664#[gpui::test]
 665async fn test_selection_goal(cx: &mut gpui::TestAppContext) {
 666    let mut cx = NeovimBackedTestContext::new(cx).await;
 667
 668    cx.set_shared_state(indoc! {"
 669        ;;ˇ;
 670        Lorem Ipsum"})
 671        .await;
 672
 673    cx.simulate_shared_keystrokes("a down up ; down up").await;
 674    cx.shared_state().await.assert_eq(indoc! {"
 675        ;;;;ˇ
 676        Lorem Ipsum"});
 677}
 678
 679#[cfg(target_os = "macos")]
 680#[gpui::test]
 681async fn test_wrapped_motions(cx: &mut gpui::TestAppContext) {
 682    let mut cx = NeovimBackedTestContext::new(cx).await;
 683
 684    cx.set_shared_wrap(12).await;
 685
 686    cx.set_shared_state(indoc! {"
 687                aaˇaa
 688                😃😃"
 689    })
 690    .await;
 691    cx.simulate_shared_keystrokes("j").await;
 692    cx.shared_state().await.assert_eq(indoc! {"
 693                aaaa
 694                😃ˇ😃"
 695    });
 696
 697    cx.set_shared_state(indoc! {"
 698                123456789012aaˇaa
 699                123456789012😃😃"
 700    })
 701    .await;
 702    cx.simulate_shared_keystrokes("j").await;
 703    cx.shared_state().await.assert_eq(indoc! {"
 704        123456789012aaaa
 705        123456789012😃ˇ😃"
 706    });
 707
 708    cx.set_shared_state(indoc! {"
 709                123456789012aaˇaa
 710                123456789012😃😃"
 711    })
 712    .await;
 713    cx.simulate_shared_keystrokes("j").await;
 714    cx.shared_state().await.assert_eq(indoc! {"
 715        123456789012aaaa
 716        123456789012😃ˇ😃"
 717    });
 718
 719    cx.set_shared_state(indoc! {"
 720        123456789012aaaaˇaaaaaaaa123456789012
 721        wow
 722        123456789012😃😃😃😃😃😃123456789012"
 723    })
 724    .await;
 725    cx.simulate_shared_keystrokes("j j").await;
 726    cx.shared_state().await.assert_eq(indoc! {"
 727        123456789012aaaaaaaaaaaa123456789012
 728        wow
 729        123456789012😃😃ˇ😃😃😃😃123456789012"
 730    });
 731}
 732
 733#[gpui::test]
 734async fn test_paragraphs_dont_wrap(cx: &mut gpui::TestAppContext) {
 735    let mut cx = NeovimBackedTestContext::new(cx).await;
 736
 737    cx.set_shared_state(indoc! {"
 738        one
 739        ˇ
 740        two"})
 741        .await;
 742
 743    cx.simulate_shared_keystrokes("} }").await;
 744    cx.shared_state().await.assert_eq(indoc! {"
 745        one
 746
 747        twˇo"});
 748
 749    cx.simulate_shared_keystrokes("{ { {").await;
 750    cx.shared_state().await.assert_eq(indoc! {"
 751        ˇone
 752
 753        two"});
 754}
 755
 756#[gpui::test]
 757async fn test_select_all_issue_2170(cx: &mut gpui::TestAppContext) {
 758    let mut cx = VimTestContext::new(cx, true).await;
 759
 760    cx.set_state(
 761        indoc! {"
 762        defmodule Test do
 763            def test(a, ˇ[_, _] = b), do: IO.puts('hi')
 764        end
 765    "},
 766        Mode::Normal,
 767    );
 768    cx.simulate_keystrokes("g a");
 769    cx.assert_state(
 770        indoc! {"
 771        defmodule Test do
 772            def test(a, «[ˇ»_, _] = b), do: IO.puts('hi')
 773        end
 774    "},
 775        Mode::Visual,
 776    );
 777}
 778
 779#[gpui::test]
 780async fn test_jk(cx: &mut gpui::TestAppContext) {
 781    let mut cx = NeovimBackedTestContext::new(cx).await;
 782
 783    cx.update(|cx| {
 784        cx.bind_keys([KeyBinding::new(
 785            "j k",
 786            NormalBefore,
 787            Some("vim_mode == insert"),
 788        )])
 789    });
 790    cx.neovim.exec("imap jk <esc>").await;
 791
 792    cx.set_shared_state("ˇhello").await;
 793    cx.simulate_shared_keystrokes("i j o j k").await;
 794    cx.shared_state().await.assert_eq("jˇohello");
 795}
 796
 797#[gpui::test]
 798async fn test_jk_delay(cx: &mut gpui::TestAppContext) {
 799    let mut cx = VimTestContext::new(cx, true).await;
 800
 801    cx.update(|cx| {
 802        cx.bind_keys([KeyBinding::new(
 803            "j k",
 804            NormalBefore,
 805            Some("vim_mode == insert"),
 806        )])
 807    });
 808
 809    cx.set_state("ˇhello", Mode::Normal);
 810    cx.simulate_keystrokes("i j");
 811    cx.executor().advance_clock(Duration::from_millis(500));
 812    cx.run_until_parked();
 813    cx.assert_state("ˇhello", Mode::Insert);
 814    cx.executor().advance_clock(Duration::from_millis(500));
 815    cx.run_until_parked();
 816    cx.assert_state("jˇhello", Mode::Insert);
 817    cx.simulate_keystrokes("k j k");
 818    cx.assert_state("jˇkhello", Mode::Normal);
 819}
 820
 821#[gpui::test]
 822async fn test_comma_w(cx: &mut gpui::TestAppContext) {
 823    let mut cx = NeovimBackedTestContext::new(cx).await;
 824
 825    cx.update(|cx| {
 826        cx.bind_keys([KeyBinding::new(
 827            ", w",
 828            motion::Down {
 829                display_lines: false,
 830            },
 831            Some("vim_mode == normal"),
 832        )])
 833    });
 834    cx.neovim.exec("map ,w j").await;
 835
 836    cx.set_shared_state("ˇhello hello\nhello hello").await;
 837    cx.simulate_shared_keystrokes("f o ; , w").await;
 838    cx.shared_state()
 839        .await
 840        .assert_eq("hello hello\nhello hellˇo");
 841
 842    cx.set_shared_state("ˇhello hello\nhello hello").await;
 843    cx.simulate_shared_keystrokes("f o ; , i").await;
 844    cx.shared_state()
 845        .await
 846        .assert_eq("hellˇo hello\nhello hello");
 847}
 848
 849#[gpui::test]
 850async fn test_rename(cx: &mut gpui::TestAppContext) {
 851    let mut cx = VimTestContext::new_typescript(cx).await;
 852
 853    cx.set_state("const beˇfore = 2; console.log(before)", Mode::Normal);
 854    let def_range = cx.lsp_range("const «beforeˇ» = 2; console.log(before)");
 855    let tgt_range = cx.lsp_range("const before = 2; console.log(«beforeˇ»)");
 856    let mut prepare_request =
 857        cx.handle_request::<lsp::request::PrepareRenameRequest, _, _>(move |_, _, _| async move {
 858            Ok(Some(lsp::PrepareRenameResponse::Range(def_range)))
 859        });
 860    let mut rename_request =
 861        cx.handle_request::<lsp::request::Rename, _, _>(move |url, params, _| async move {
 862            Ok(Some(lsp::WorkspaceEdit {
 863                changes: Some(
 864                    [(
 865                        url.clone(),
 866                        vec![
 867                            lsp::TextEdit::new(def_range, params.new_name.clone()),
 868                            lsp::TextEdit::new(tgt_range, params.new_name),
 869                        ],
 870                    )]
 871                    .into(),
 872                ),
 873                ..Default::default()
 874            }))
 875        });
 876
 877    cx.simulate_keystrokes("c d");
 878    prepare_request.next().await.unwrap();
 879    cx.simulate_input("after");
 880    cx.simulate_keystrokes("enter");
 881    rename_request.next().await.unwrap();
 882    cx.assert_state("const afterˇ = 2; console.log(after)", Mode::Normal)
 883}
 884
 885// TODO: this test is flaky on our linux CI machines
 886#[cfg(target_os = "macos")]
 887#[gpui::test]
 888async fn test_remap(cx: &mut gpui::TestAppContext) {
 889    let mut cx = VimTestContext::new(cx, true).await;
 890
 891    // test moving the cursor
 892    cx.update(|cx| {
 893        cx.bind_keys([KeyBinding::new(
 894            "g z",
 895            workspace::SendKeystrokes("l l l l".to_string()),
 896            None,
 897        )])
 898    });
 899    cx.set_state("ˇ123456789", Mode::Normal);
 900    cx.simulate_keystrokes("g z");
 901    cx.assert_state("1234ˇ56789", Mode::Normal);
 902
 903    // test switching modes
 904    cx.update(|cx| {
 905        cx.bind_keys([KeyBinding::new(
 906            "g y",
 907            workspace::SendKeystrokes("i f o o escape l".to_string()),
 908            None,
 909        )])
 910    });
 911    cx.set_state("ˇ123456789", Mode::Normal);
 912    cx.simulate_keystrokes("g y");
 913    cx.assert_state("fooˇ123456789", Mode::Normal);
 914
 915    // test recursion
 916    cx.update(|cx| {
 917        cx.bind_keys([KeyBinding::new(
 918            "g x",
 919            workspace::SendKeystrokes("g z g y".to_string()),
 920            None,
 921        )])
 922    });
 923    cx.set_state("ˇ123456789", Mode::Normal);
 924    cx.simulate_keystrokes("g x");
 925    cx.assert_state("1234fooˇ56789", Mode::Normal);
 926
 927    cx.executor().allow_parking();
 928
 929    // test command
 930    cx.update(|cx| {
 931        cx.bind_keys([KeyBinding::new(
 932            "g w",
 933            workspace::SendKeystrokes(": j enter".to_string()),
 934            None,
 935        )])
 936    });
 937    cx.set_state("ˇ1234\n56789", Mode::Normal);
 938    cx.simulate_keystrokes("g w");
 939    cx.assert_state("1234ˇ 56789", Mode::Normal);
 940
 941    // test leaving command
 942    cx.update(|cx| {
 943        cx.bind_keys([KeyBinding::new(
 944            "g u",
 945            workspace::SendKeystrokes("g w g z".to_string()),
 946            None,
 947        )])
 948    });
 949    cx.set_state("ˇ1234\n56789", Mode::Normal);
 950    cx.simulate_keystrokes("g u");
 951    cx.assert_state("1234 567ˇ89", Mode::Normal);
 952
 953    // test leaving command
 954    cx.update(|cx| {
 955        cx.bind_keys([KeyBinding::new(
 956            "g t",
 957            workspace::SendKeystrokes("i space escape".to_string()),
 958            None,
 959        )])
 960    });
 961    cx.set_state("12ˇ34", Mode::Normal);
 962    cx.simulate_keystrokes("g t");
 963    cx.assert_state("12ˇ 34", Mode::Normal);
 964}
 965
 966#[gpui::test]
 967async fn test_undo(cx: &mut gpui::TestAppContext) {
 968    let mut cx = NeovimBackedTestContext::new(cx).await;
 969
 970    cx.set_shared_state("hello quˇoel world").await;
 971    cx.simulate_shared_keystrokes("v i w s c o escape u").await;
 972    cx.shared_state().await.assert_eq("hello ˇquoel world");
 973    cx.simulate_shared_keystrokes("ctrl-r").await;
 974    cx.shared_state().await.assert_eq("hello ˇco world");
 975    cx.simulate_shared_keystrokes("a o right l escape").await;
 976    cx.shared_state().await.assert_eq("hello cooˇl world");
 977    cx.simulate_shared_keystrokes("u").await;
 978    cx.shared_state().await.assert_eq("hello cooˇ world");
 979    cx.simulate_shared_keystrokes("u").await;
 980    cx.shared_state().await.assert_eq("hello cˇo world");
 981    cx.simulate_shared_keystrokes("u").await;
 982    cx.shared_state().await.assert_eq("hello ˇquoel world");
 983
 984    cx.set_shared_state("hello quˇoel world").await;
 985    cx.simulate_shared_keystrokes("v i w ~ u").await;
 986    cx.shared_state().await.assert_eq("hello ˇquoel world");
 987
 988    cx.set_shared_state("\nhello quˇoel world\n").await;
 989    cx.simulate_shared_keystrokes("shift-v s c escape u").await;
 990    cx.shared_state().await.assert_eq("\nˇhello quoel world\n");
 991
 992    cx.set_shared_state(indoc! {"
 993        ˇ1
 994        2
 995        3"})
 996        .await;
 997
 998    cx.simulate_shared_keystrokes("ctrl-v shift-g ctrl-a").await;
 999    cx.shared_state().await.assert_eq(indoc! {"
1000        ˇ2
1001        3
1002        4"});
1003
1004    cx.simulate_shared_keystrokes("u").await;
1005    cx.shared_state().await.assert_eq(indoc! {"
1006        ˇ1
1007        2
1008        3"});
1009}
1010
1011#[gpui::test]
1012async fn test_mouse_selection(cx: &mut TestAppContext) {
1013    let mut cx = VimTestContext::new(cx, true).await;
1014
1015    cx.set_state("ˇone two three", Mode::Normal);
1016
1017    let start_point = cx.pixel_position("one twˇo three");
1018    let end_point = cx.pixel_position("one ˇtwo three");
1019
1020    cx.simulate_mouse_down(start_point, MouseButton::Left, Modifiers::none());
1021    cx.simulate_mouse_move(end_point, MouseButton::Left, Modifiers::none());
1022    cx.simulate_mouse_up(end_point, MouseButton::Left, Modifiers::none());
1023
1024    cx.assert_state("one «ˇtwo» three", Mode::Visual)
1025}
1026
1027#[gpui::test]
1028async fn test_lowercase_marks(cx: &mut TestAppContext) {
1029    let mut cx = NeovimBackedTestContext::new(cx).await;
1030
1031    cx.set_shared_state("line one\nline ˇtwo\nline three").await;
1032    cx.simulate_shared_keystrokes("m a l ' a").await;
1033    cx.shared_state()
1034        .await
1035        .assert_eq("line one\nˇline two\nline three");
1036    cx.simulate_shared_keystrokes("` a").await;
1037    cx.shared_state()
1038        .await
1039        .assert_eq("line one\nline ˇtwo\nline three");
1040
1041    cx.simulate_shared_keystrokes("^ d ` a").await;
1042    cx.shared_state()
1043        .await
1044        .assert_eq("line one\nˇtwo\nline three");
1045}
1046
1047#[gpui::test]
1048async fn test_lt_gt_marks(cx: &mut TestAppContext) {
1049    let mut cx = NeovimBackedTestContext::new(cx).await;
1050
1051    cx.set_shared_state(indoc!(
1052        "
1053        Line one
1054        Line two
1055        Line ˇthree
1056        Line four
1057        Line five
1058    "
1059    ))
1060    .await;
1061
1062    cx.simulate_shared_keystrokes("v j escape k k").await;
1063
1064    cx.simulate_shared_keystrokes("' <").await;
1065    cx.shared_state().await.assert_eq(indoc! {"
1066        Line one
1067        Line two
1068        ˇLine three
1069        Line four
1070        Line five
1071    "});
1072
1073    cx.simulate_shared_keystrokes("` <").await;
1074    cx.shared_state().await.assert_eq(indoc! {"
1075        Line one
1076        Line two
1077        Line ˇthree
1078        Line four
1079        Line five
1080    "});
1081
1082    cx.simulate_shared_keystrokes("' >").await;
1083    cx.shared_state().await.assert_eq(indoc! {"
1084        Line one
1085        Line two
1086        Line three
1087        ˇLine four
1088        Line five
1089    "
1090    });
1091
1092    cx.simulate_shared_keystrokes("` >").await;
1093    cx.shared_state().await.assert_eq(indoc! {"
1094        Line one
1095        Line two
1096        Line three
1097        Line ˇfour
1098        Line five
1099    "
1100    });
1101
1102    cx.simulate_shared_keystrokes("v i w o escape").await;
1103    cx.simulate_shared_keystrokes("` >").await;
1104    cx.shared_state().await.assert_eq(indoc! {"
1105        Line one
1106        Line two
1107        Line three
1108        Line fouˇr
1109        Line five
1110    "
1111    });
1112    cx.simulate_shared_keystrokes("` <").await;
1113    cx.shared_state().await.assert_eq(indoc! {"
1114        Line one
1115        Line two
1116        Line three
1117        Line ˇfour
1118        Line five
1119    "
1120    });
1121}
1122
1123#[gpui::test]
1124async fn test_caret_mark(cx: &mut TestAppContext) {
1125    let mut cx = NeovimBackedTestContext::new(cx).await;
1126
1127    cx.set_shared_state(indoc!(
1128        "
1129        Line one
1130        Line two
1131        Line three
1132        ˇLine four
1133        Line five
1134    "
1135    ))
1136    .await;
1137
1138    cx.simulate_shared_keystrokes("c w shift-s t r a i g h t space t h i n g escape j j")
1139        .await;
1140
1141    cx.simulate_shared_keystrokes("' ^").await;
1142    cx.shared_state().await.assert_eq(indoc! {"
1143        Line one
1144        Line two
1145        Line three
1146        ˇStraight thing four
1147        Line five
1148    "
1149    });
1150
1151    cx.simulate_shared_keystrokes("` ^").await;
1152    cx.shared_state().await.assert_eq(indoc! {"
1153        Line one
1154        Line two
1155        Line three
1156        Straight thingˇ four
1157        Line five
1158    "
1159    });
1160
1161    cx.simulate_shared_keystrokes("k a ! escape k g i ?").await;
1162    cx.shared_state().await.assert_eq(indoc! {"
1163        Line one
1164        Line two
1165        Line three!?ˇ
1166        Straight thing four
1167        Line five
1168    "
1169    });
1170}
1171
1172#[cfg(target_os = "macos")]
1173#[gpui::test]
1174async fn test_dw_eol(cx: &mut gpui::TestAppContext) {
1175    let mut cx = NeovimBackedTestContext::new(cx).await;
1176
1177    cx.set_shared_wrap(12).await;
1178    cx.set_shared_state("twelve ˇchar twelve char\ntwelve char")
1179        .await;
1180    cx.simulate_shared_keystrokes("d w").await;
1181    cx.shared_state()
1182        .await
1183        .assert_eq("twelve ˇtwelve char\ntwelve char");
1184}
1185
1186#[gpui::test]
1187async fn test_toggle_comments(cx: &mut gpui::TestAppContext) {
1188    let mut cx = VimTestContext::new(cx, true).await;
1189
1190    let language = std::sync::Arc::new(language::Language::new(
1191        language::LanguageConfig {
1192            line_comments: vec!["// ".into(), "//! ".into(), "/// ".into()],
1193            ..Default::default()
1194        },
1195        Some(language::tree_sitter_rust::LANGUAGE.into()),
1196    ));
1197    cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
1198
1199    // works in normal model
1200    cx.set_state(
1201        indoc! {"
1202      ˇone
1203      two
1204      three
1205      "},
1206        Mode::Normal,
1207    );
1208    cx.simulate_keystrokes("g c c");
1209    cx.assert_state(
1210        indoc! {"
1211          // ˇone
1212          two
1213          three
1214          "},
1215        Mode::Normal,
1216    );
1217
1218    // works in visual mode
1219    cx.simulate_keystrokes("v j g c");
1220    cx.assert_state(
1221        indoc! {"
1222          // // ˇone
1223          // two
1224          three
1225          "},
1226        Mode::Normal,
1227    );
1228
1229    // works in visual line mode
1230    cx.simulate_keystrokes("shift-v j g c");
1231    cx.assert_state(
1232        indoc! {"
1233          // ˇone
1234          two
1235          three
1236          "},
1237        Mode::Normal,
1238    );
1239
1240    // works with count
1241    cx.simulate_keystrokes("g c 2 j");
1242    cx.assert_state(
1243        indoc! {"
1244            // // ˇone
1245            // two
1246            // three
1247            "},
1248        Mode::Normal,
1249    );
1250
1251    // works with motion object
1252    cx.simulate_keystrokes("shift-g");
1253    cx.simulate_keystrokes("g c g g");
1254    cx.assert_state(
1255        indoc! {"
1256            // one
1257            two
1258            three
1259            ˇ"},
1260        Mode::Normal,
1261    );
1262}
1263
1264#[gpui::test]
1265async fn test_find_multibyte(cx: &mut gpui::TestAppContext) {
1266    let mut cx = NeovimBackedTestContext::new(cx).await;
1267
1268    cx.set_shared_state(r#"<label for="guests">ˇPočet hostů</label>"#)
1269        .await;
1270
1271    cx.simulate_shared_keystrokes("c t < o escape").await;
1272    cx.shared_state()
1273        .await
1274        .assert_eq(r#"<label for="guests">ˇo</label>"#);
1275}
1276
1277#[gpui::test]
1278async fn test_plus_minus(cx: &mut gpui::TestAppContext) {
1279    let mut cx = NeovimBackedTestContext::new(cx).await;
1280
1281    cx.set_shared_state(indoc! {
1282        "one
1283           two
1284        thrˇee
1285    "})
1286        .await;
1287
1288    cx.simulate_shared_keystrokes("-").await;
1289    cx.shared_state().await.assert_matches();
1290    cx.simulate_shared_keystrokes("-").await;
1291    cx.shared_state().await.assert_matches();
1292    cx.simulate_shared_keystrokes("+").await;
1293    cx.shared_state().await.assert_matches();
1294}
1295
1296#[gpui::test]
1297async fn test_command_alias(cx: &mut gpui::TestAppContext) {
1298    let mut cx = VimTestContext::new(cx, true).await;
1299    cx.update_global(|store: &mut SettingsStore, cx| {
1300        store.update_user_settings::<WorkspaceSettings>(cx, |s| {
1301            let mut aliases = HashMap::default();
1302            aliases.insert("Q".to_string(), "upper".to_string());
1303            s.command_aliases = Some(aliases)
1304        });
1305    });
1306
1307    cx.set_state("ˇhello world", Mode::Normal);
1308    cx.simulate_keystrokes(": Q");
1309    cx.set_state("ˇHello world", Mode::Normal);
1310}
1311
1312#[gpui::test]
1313async fn test_remap_adjacent_dog_cat(cx: &mut gpui::TestAppContext) {
1314    let mut cx = NeovimBackedTestContext::new(cx).await;
1315    cx.update(|cx| {
1316        cx.bind_keys([
1317            KeyBinding::new(
1318                "d o g",
1319                workspace::SendKeystrokes("🐶".to_string()),
1320                Some("vim_mode == insert"),
1321            ),
1322            KeyBinding::new(
1323                "c a t",
1324                workspace::SendKeystrokes("🐱".to_string()),
1325                Some("vim_mode == insert"),
1326            ),
1327        ])
1328    });
1329    cx.neovim.exec("imap dog 🐶").await;
1330    cx.neovim.exec("imap cat 🐱").await;
1331
1332    cx.set_shared_state("ˇ").await;
1333    cx.simulate_shared_keystrokes("i d o g").await;
1334    cx.shared_state().await.assert_eq("🐶ˇ");
1335
1336    cx.set_shared_state("ˇ").await;
1337    cx.simulate_shared_keystrokes("i d o d o g").await;
1338    cx.shared_state().await.assert_eq("do🐶ˇ");
1339
1340    cx.set_shared_state("ˇ").await;
1341    cx.simulate_shared_keystrokes("i d o c a t").await;
1342    cx.shared_state().await.assert_eq("do🐱ˇ");
1343}
1344
1345#[gpui::test]
1346async fn test_remap_nested_pineapple(cx: &mut gpui::TestAppContext) {
1347    let mut cx = NeovimBackedTestContext::new(cx).await;
1348    cx.update(|cx| {
1349        cx.bind_keys([
1350            KeyBinding::new(
1351                "p i n",
1352                workspace::SendKeystrokes("📌".to_string()),
1353                Some("vim_mode == insert"),
1354            ),
1355            KeyBinding::new(
1356                "p i n e",
1357                workspace::SendKeystrokes("🌲".to_string()),
1358                Some("vim_mode == insert"),
1359            ),
1360            KeyBinding::new(
1361                "p i n e a p p l e",
1362                workspace::SendKeystrokes("🍍".to_string()),
1363                Some("vim_mode == insert"),
1364            ),
1365        ])
1366    });
1367    cx.neovim.exec("imap pin 📌").await;
1368    cx.neovim.exec("imap pine 🌲").await;
1369    cx.neovim.exec("imap pineapple 🍍").await;
1370
1371    cx.set_shared_state("ˇ").await;
1372    cx.simulate_shared_keystrokes("i p i n").await;
1373    cx.executor().advance_clock(Duration::from_millis(1000));
1374    cx.run_until_parked();
1375    cx.shared_state().await.assert_eq("📌ˇ");
1376
1377    cx.set_shared_state("ˇ").await;
1378    cx.simulate_shared_keystrokes("i p i n e").await;
1379    cx.executor().advance_clock(Duration::from_millis(1000));
1380    cx.run_until_parked();
1381    cx.shared_state().await.assert_eq("🌲ˇ");
1382
1383    cx.set_shared_state("ˇ").await;
1384    cx.simulate_shared_keystrokes("i p i n e a p p l e").await;
1385    cx.shared_state().await.assert_eq("🍍ˇ");
1386}
1387
1388#[gpui::test]
1389async fn test_escape_while_waiting(cx: &mut gpui::TestAppContext) {
1390    let mut cx = NeovimBackedTestContext::new(cx).await;
1391    cx.set_shared_state("ˇhi").await;
1392    cx.simulate_shared_keystrokes("\" + escape x").await;
1393    cx.shared_state().await.assert_eq("ˇi");
1394}
1395
1396#[gpui::test]
1397async fn test_ctrl_w_override(cx: &mut gpui::TestAppContext) {
1398    let mut cx = NeovimBackedTestContext::new(cx).await;
1399    cx.update(|cx| {
1400        cx.bind_keys([KeyBinding::new("ctrl-w", DeleteLine, None)]);
1401    });
1402    cx.neovim.exec("map <c-w> D").await;
1403    cx.set_shared_state("ˇhi").await;
1404    cx.simulate_shared_keystrokes("ctrl-w").await;
1405    cx.shared_state().await.assert_eq("ˇ");
1406}
1407
1408#[gpui::test]
1409async fn test_visual_indent_count(cx: &mut gpui::TestAppContext) {
1410    let mut cx = VimTestContext::new(cx, true).await;
1411    cx.set_state("ˇhi", Mode::Normal);
1412    cx.simulate_keystrokes("shift-v 3 >");
1413    cx.assert_state("            ˇhi", Mode::Normal);
1414    cx.simulate_keystrokes("shift-v 2 <");
1415    cx.assert_state("    ˇhi", Mode::Normal);
1416}
1417
1418#[gpui::test]
1419async fn test_record_replay_recursion(cx: &mut gpui::TestAppContext) {
1420    let mut cx = NeovimBackedTestContext::new(cx).await;
1421
1422    cx.set_shared_state("ˇhello world").await;
1423    cx.simulate_shared_keystrokes(">").await;
1424    cx.simulate_shared_keystrokes(".").await;
1425    cx.simulate_shared_keystrokes(".").await;
1426    cx.simulate_shared_keystrokes(".").await;
1427    cx.shared_state().await.assert_eq("ˇhello world");
1428}
1429
1430#[gpui::test]
1431async fn test_blackhole_register(cx: &mut gpui::TestAppContext) {
1432    let mut cx = NeovimBackedTestContext::new(cx).await;
1433
1434    cx.set_shared_state("ˇhello world").await;
1435    cx.simulate_shared_keystrokes("d i w \" _ d a w").await;
1436    cx.simulate_shared_keystrokes("p").await;
1437    cx.shared_state().await.assert_eq("hellˇo");
1438}
1439
1440#[gpui::test]
1441async fn test_sentence_backwards(cx: &mut gpui::TestAppContext) {
1442    let mut cx = NeovimBackedTestContext::new(cx).await;
1443
1444    cx.set_shared_state("one\n\ntwo\nthree\nˇ\nfour").await;
1445    cx.simulate_shared_keystrokes("(").await;
1446    cx.shared_state()
1447        .await
1448        .assert_eq("one\n\nˇtwo\nthree\n\nfour");
1449
1450    cx.set_shared_state("hello.\n\n\nworˇld.").await;
1451    cx.simulate_shared_keystrokes("(").await;
1452    cx.shared_state().await.assert_eq("hello.\n\n\nˇworld.");
1453    cx.simulate_shared_keystrokes("(").await;
1454    cx.shared_state().await.assert_eq("hello.\n\nˇ\nworld.");
1455    cx.simulate_shared_keystrokes("(").await;
1456    cx.shared_state().await.assert_eq("ˇhello.\n\n\nworld.");
1457
1458    cx.set_shared_state("hello. worlˇd.").await;
1459    cx.simulate_shared_keystrokes("(").await;
1460    cx.shared_state().await.assert_eq("hello. ˇworld.");
1461    cx.simulate_shared_keystrokes("(").await;
1462    cx.shared_state().await.assert_eq("ˇhello. world.");
1463
1464    cx.set_shared_state(". helˇlo.").await;
1465    cx.simulate_shared_keystrokes("(").await;
1466    cx.shared_state().await.assert_eq(". ˇhello.");
1467    cx.simulate_shared_keystrokes("(").await;
1468    cx.shared_state().await.assert_eq(". ˇhello.");
1469
1470    cx.set_shared_state(indoc! {
1471        "{
1472            hello_world();
1473        ˇ}"
1474    })
1475    .await;
1476    cx.simulate_shared_keystrokes("(").await;
1477    cx.shared_state().await.assert_eq(indoc! {
1478        "ˇ{
1479            hello_world();
1480        }"
1481    });
1482
1483    cx.set_shared_state(indoc! {
1484        "Hello! World..?
1485
1486        \tHello! World... ˇ"
1487    })
1488    .await;
1489    cx.simulate_shared_keystrokes("(").await;
1490    cx.shared_state().await.assert_eq(indoc! {
1491        "Hello! World..?
1492
1493        \tHello! ˇWorld... "
1494    });
1495    cx.simulate_shared_keystrokes("(").await;
1496    cx.shared_state().await.assert_eq(indoc! {
1497        "Hello! World..?
1498
1499        \tˇHello! World... "
1500    });
1501    cx.simulate_shared_keystrokes("(").await;
1502    cx.shared_state().await.assert_eq(indoc! {
1503        "Hello! World..?
1504        ˇ
1505        \tHello! World... "
1506    });
1507    cx.simulate_shared_keystrokes("(").await;
1508    cx.shared_state().await.assert_eq(indoc! {
1509        "Hello! ˇWorld..?
1510
1511        \tHello! World... "
1512    });
1513}
1514
1515#[gpui::test]
1516async fn test_sentence_forwards(cx: &mut gpui::TestAppContext) {
1517    let mut cx = NeovimBackedTestContext::new(cx).await;
1518
1519    cx.set_shared_state("helˇlo.\n\n\nworld.").await;
1520    cx.simulate_shared_keystrokes(")").await;
1521    cx.shared_state().await.assert_eq("hello.\nˇ\n\nworld.");
1522    cx.simulate_shared_keystrokes(")").await;
1523    cx.shared_state().await.assert_eq("hello.\n\n\nˇworld.");
1524    cx.simulate_shared_keystrokes(")").await;
1525    cx.shared_state().await.assert_eq("hello.\n\n\nworldˇ.");
1526
1527    cx.set_shared_state("helˇlo.\n\n\nworld.").await;
1528}