test.rs

  1mod neovim_backed_binding_test_context;
  2mod neovim_backed_test_context;
  3mod neovim_connection;
  4mod vim_binding_test_context;
  5mod vim_test_context;
  6
  7use std::sync::Arc;
  8
  9use command_palette::CommandPalette;
 10use editor::DisplayPoint;
 11pub use neovim_backed_binding_test_context::*;
 12pub use neovim_backed_test_context::*;
 13pub use vim_binding_test_context::*;
 14pub use vim_test_context::*;
 15
 16use indoc::indoc;
 17use search::BufferSearchBar;
 18
 19use crate::{state::Mode, ModeIndicator};
 20
 21#[gpui::test]
 22async fn test_initially_disabled(cx: &mut gpui::TestAppContext) {
 23    let mut cx = VimTestContext::new(cx, false).await;
 24    cx.simulate_keystrokes(["h", "j", "k", "l"]);
 25    cx.assert_editor_state("hjklˇ");
 26}
 27
 28#[gpui::test]
 29async fn test_neovim(cx: &mut gpui::TestAppContext) {
 30    let mut cx = NeovimBackedTestContext::new(cx).await;
 31
 32    cx.simulate_shared_keystroke("i").await;
 33    cx.assert_state_matches().await;
 34    cx.simulate_shared_keystrokes([
 35        "shift-T", "e", "s", "t", " ", "t", "e", "s", "t", "escape", "0", "d", "w",
 36    ])
 37    .await;
 38    cx.assert_state_matches().await;
 39    cx.assert_editor_state("ˇtest");
 40}
 41
 42#[gpui::test]
 43async fn test_toggle_through_settings(cx: &mut gpui::TestAppContext) {
 44    let mut cx = VimTestContext::new(cx, true).await;
 45
 46    cx.simulate_keystroke("i");
 47    assert_eq!(cx.mode(), Mode::Insert);
 48
 49    // Editor acts as though vim is disabled
 50    cx.disable_vim();
 51    cx.simulate_keystrokes(["h", "j", "k", "l"]);
 52    cx.assert_editor_state("hjklˇ");
 53
 54    // Selections aren't changed if editor is blurred but vim-mode is still disabled.
 55    cx.set_state("«hjklˇ»", Mode::Normal);
 56    cx.assert_editor_state("«hjklˇ»");
 57    cx.update_editor(|_, cx| cx.blur());
 58    cx.assert_editor_state("«hjklˇ»");
 59    cx.update_editor(|_, cx| cx.focus_self());
 60    cx.assert_editor_state("«hjklˇ»");
 61
 62    // Enabling dynamically sets vim mode again and restores normal mode
 63    cx.enable_vim();
 64    assert_eq!(cx.mode(), Mode::Normal);
 65    cx.simulate_keystrokes(["h", "h", "h", "l"]);
 66    assert_eq!(cx.buffer_text(), "hjkl".to_owned());
 67    cx.assert_editor_state("hˇjkl");
 68    cx.simulate_keystrokes(["i", "T", "e", "s", "t"]);
 69    cx.assert_editor_state("hTestˇjkl");
 70
 71    // Disabling and enabling resets to normal mode
 72    assert_eq!(cx.mode(), Mode::Insert);
 73    cx.disable_vim();
 74    cx.enable_vim();
 75    assert_eq!(cx.mode(), Mode::Normal);
 76}
 77
 78#[gpui::test]
 79async fn test_buffer_search(cx: &mut gpui::TestAppContext) {
 80    let mut cx = VimTestContext::new(cx, true).await;
 81
 82    cx.set_state(
 83        indoc! {"
 84            The quick brown
 85            fox juˇmps over
 86            the lazy dog"},
 87        Mode::Normal,
 88    );
 89    cx.simulate_keystroke("/");
 90
 91    let search_bar = cx.workspace(|workspace, cx| {
 92        workspace
 93            .active_pane()
 94            .read(cx)
 95            .toolbar()
 96            .read(cx)
 97            .item_of_type::<BufferSearchBar>()
 98            .expect("Buffer search bar should be deployed")
 99    });
100
101    search_bar.read_with(cx.cx, |bar, cx| {
102        assert_eq!(bar.query(cx), "");
103    })
104}
105
106#[gpui::test]
107async fn test_count_down(cx: &mut gpui::TestAppContext) {
108    let mut cx = VimTestContext::new(cx, true).await;
109
110    cx.set_state(indoc! {"aˇa\nbb\ncc\ndd\nee"}, Mode::Normal);
111    cx.simulate_keystrokes(["2", "down"]);
112    cx.assert_editor_state("aa\nbb\ncˇc\ndd\nee");
113    cx.simulate_keystrokes(["9", "down"]);
114    cx.assert_editor_state("aa\nbb\ncc\ndd\neˇe");
115}
116
117#[gpui::test]
118async fn test_end_of_document_710(cx: &mut gpui::TestAppContext) {
119    let mut cx = VimTestContext::new(cx, true).await;
120
121    // goes to end by default
122    cx.set_state(indoc! {"aˇa\nbb\ncc"}, Mode::Normal);
123    cx.simulate_keystrokes(["shift-g"]);
124    cx.assert_editor_state("aa\nbb\ncˇc");
125
126    // can go to line 1 (https://github.com/zed-industries/community/issues/710)
127    cx.simulate_keystrokes(["1", "shift-g"]);
128    cx.assert_editor_state("aˇa\nbb\ncc");
129}
130
131#[gpui::test]
132async fn test_indent_outdent(cx: &mut gpui::TestAppContext) {
133    let mut cx = VimTestContext::new(cx, true).await;
134
135    // works in normal mode
136    cx.set_state(indoc! {"aa\nbˇb\ncc"}, Mode::Normal);
137    cx.simulate_keystrokes([">", ">"]);
138    cx.assert_editor_state("aa\n    bˇb\ncc");
139    cx.simulate_keystrokes(["<", "<"]);
140    cx.assert_editor_state("aa\nbˇb\ncc");
141
142    // works in visuial mode
143    cx.simulate_keystrokes(["shift-v", "down", ">"]);
144    cx.assert_editor_state("aa\n    b«b\n    ccˇ»");
145}
146
147#[gpui::test]
148async fn test_escape_command_palette(cx: &mut gpui::TestAppContext) {
149    let mut cx = VimTestContext::new(cx, true).await;
150
151    cx.set_state("aˇbc\n", Mode::Normal);
152    cx.simulate_keystrokes(["i", "cmd-shift-p"]);
153
154    assert!(cx.workspace(|workspace, _| workspace.modal::<CommandPalette>().is_some()));
155    cx.simulate_keystroke("escape");
156    assert!(!cx.workspace(|workspace, _| workspace.modal::<CommandPalette>().is_some()));
157    cx.assert_state("aˇbc\n", Mode::Insert);
158}
159
160#[gpui::test]
161async fn test_selection_on_search(cx: &mut gpui::TestAppContext) {
162    let mut cx = VimTestContext::new(cx, true).await;
163
164    cx.set_state(indoc! {"aa\nbˇb\ncc\ncc\ncc\n"}, Mode::Normal);
165    cx.simulate_keystrokes(["/", "c", "c"]);
166
167    let search_bar = cx.workspace(|workspace, cx| {
168        workspace
169            .active_pane()
170            .read(cx)
171            .toolbar()
172            .read(cx)
173            .item_of_type::<BufferSearchBar>()
174            .expect("Buffer search bar should be deployed")
175    });
176
177    search_bar.read_with(cx.cx, |bar, cx| {
178        assert_eq!(bar.query(cx), "cc");
179    });
180
181    // wait for the query editor change event to fire.
182    search_bar.next_notification(&cx).await;
183
184    cx.update_editor(|editor, cx| {
185        let highlights = editor.all_background_highlights(cx);
186        assert_eq!(3, highlights.len());
187        assert_eq!(
188            DisplayPoint::new(2, 0)..DisplayPoint::new(2, 2),
189            highlights[0].0
190        )
191    });
192    cx.simulate_keystrokes(["enter"]);
193
194    cx.assert_state(indoc! {"aa\nbb\nˇcc\ncc\ncc\n"}, Mode::Normal);
195    cx.simulate_keystrokes(["n"]);
196    cx.assert_state(indoc! {"aa\nbb\ncc\nˇcc\ncc\n"}, Mode::Normal);
197    cx.simulate_keystrokes(["shift-n"]);
198    cx.assert_state(indoc! {"aa\nbb\nˇcc\ncc\ncc\n"}, Mode::Normal);
199}
200
201#[gpui::test]
202async fn test_status_indicator(
203    cx: &mut gpui::TestAppContext,
204    deterministic: Arc<gpui::executor::Deterministic>,
205) {
206    let mut cx = VimTestContext::new(cx, true).await;
207    deterministic.run_until_parked();
208
209    let mode_indicator = cx.workspace(|workspace, cx| {
210        let status_bar = workspace.status_bar().read(cx);
211        let mode_indicator = status_bar.item_of_type::<ModeIndicator>();
212        assert!(mode_indicator.is_some());
213        mode_indicator.unwrap()
214    });
215
216    assert_eq!(
217        cx.workspace(|_, cx| mode_indicator.read(cx).mode),
218        Some(Mode::Normal)
219    );
220
221    // shows the correct mode
222    cx.simulate_keystrokes(["i"]);
223    deterministic.run_until_parked();
224    assert_eq!(
225        cx.workspace(|_, cx| mode_indicator.read(cx).mode),
226        Some(Mode::Insert)
227    );
228
229    // shows even in search
230    cx.simulate_keystrokes(["escape", "v", "/"]);
231    deterministic.run_until_parked();
232    assert_eq!(
233        cx.workspace(|_, cx| mode_indicator.read(cx).mode),
234        Some(Mode::Visual { line: false })
235    );
236
237    // hides if vim mode is disabled
238    cx.disable_vim();
239    deterministic.run_until_parked();
240    cx.workspace(|workspace, cx| {
241        let status_bar = workspace.status_bar().read(cx);
242        let mode_indicator = status_bar.item_of_type::<ModeIndicator>().unwrap();
243        assert!(mode_indicator.read(cx).mode.is_none());
244    });
245
246    cx.enable_vim();
247    deterministic.run_until_parked();
248    cx.workspace(|workspace, cx| {
249        let status_bar = workspace.status_bar().read(cx);
250        let mode_indicator = status_bar.item_of_type::<ModeIndicator>().unwrap();
251        assert!(mode_indicator.read(cx).mode.is_some());
252    });
253}