insert.rs

  1use crate::{state::Mode, Vim};
  2use editor::{scroll::Autoscroll, Bias, Editor};
  3use gpui::{actions, Action, ViewContext};
  4use language::SelectionGoal;
  5
  6actions!(vim, [NormalBefore, TemporaryNormal]);
  7
  8pub fn register(editor: &mut Editor, cx: &mut ViewContext<Vim>) {
  9    Vim::action(editor, cx, Vim::normal_before);
 10    Vim::action(editor, cx, Vim::temporary_normal);
 11}
 12
 13impl Vim {
 14    fn normal_before(&mut self, action: &NormalBefore, cx: &mut ViewContext<Self>) {
 15        if self.active_operator().is_some() {
 16            self.operator_stack.clear();
 17            self.sync_vim_settings(cx);
 18            return;
 19        }
 20        let count = Vim::take_count(cx).unwrap_or(1);
 21        self.stop_recording_immediately(action.boxed_clone(), cx);
 22        if count <= 1 || Vim::globals(cx).dot_replaying {
 23            self.create_mark("^".into(), false, cx);
 24            self.update_editor(cx, |_, editor, cx| {
 25                editor.dismiss_menus_and_popups(false, cx);
 26                editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 27                    s.move_cursors_with(|map, mut cursor, _| {
 28                        *cursor.column_mut() = cursor.column().saturating_sub(1);
 29                        (map.clip_point(cursor, Bias::Left), SelectionGoal::None)
 30                    });
 31                });
 32            });
 33            self.switch_mode(Mode::Normal, false, cx);
 34            return;
 35        }
 36
 37        self.repeat(true, cx)
 38    }
 39
 40    fn temporary_normal(&mut self, _: &TemporaryNormal, cx: &mut ViewContext<Self>) {
 41        self.switch_mode(Mode::Normal, true, cx);
 42        self.temp_mode = true;
 43    }
 44}
 45
 46#[cfg(test)]
 47mod test {
 48    use crate::{
 49        state::Mode,
 50        test::{NeovimBackedTestContext, VimTestContext},
 51    };
 52
 53    #[gpui::test]
 54    async fn test_enter_and_exit_insert_mode(cx: &mut gpui::TestAppContext) {
 55        let mut cx = VimTestContext::new(cx, true).await;
 56        cx.simulate_keystrokes("i");
 57        assert_eq!(cx.mode(), Mode::Insert);
 58        cx.simulate_keystrokes("T e s t");
 59        cx.assert_editor_state("Testˇ");
 60        cx.simulate_keystrokes("escape");
 61        assert_eq!(cx.mode(), Mode::Normal);
 62        cx.assert_editor_state("Tesˇt");
 63    }
 64
 65    #[gpui::test]
 66    async fn test_insert_with_counts(cx: &mut gpui::TestAppContext) {
 67        let mut cx = NeovimBackedTestContext::new(cx).await;
 68
 69        cx.set_shared_state("ˇhello\n").await;
 70        cx.simulate_shared_keystrokes("5 i - escape").await;
 71        cx.shared_state().await.assert_eq("----ˇ-hello\n");
 72
 73        cx.set_shared_state("ˇhello\n").await;
 74        cx.simulate_shared_keystrokes("5 a - escape").await;
 75        cx.shared_state().await.assert_eq("h----ˇ-ello\n");
 76
 77        cx.simulate_shared_keystrokes("4 shift-i - escape").await;
 78        cx.shared_state().await.assert_eq("---ˇ-h-----ello\n");
 79
 80        cx.simulate_shared_keystrokes("3 shift-a - escape").await;
 81        cx.shared_state().await.assert_eq("----h-----ello--ˇ-\n");
 82
 83        cx.set_shared_state("ˇhello\n").await;
 84        cx.simulate_shared_keystrokes("3 o o i escape").await;
 85        cx.shared_state().await.assert_eq("hello\noi\noi\noˇi\n");
 86
 87        cx.set_shared_state("ˇhello\n").await;
 88        cx.simulate_shared_keystrokes("3 shift-o o i escape").await;
 89        cx.shared_state().await.assert_eq("oi\noi\noˇi\nhello\n");
 90    }
 91
 92    #[gpui::test]
 93    async fn test_insert_with_repeat(cx: &mut gpui::TestAppContext) {
 94        let mut cx = NeovimBackedTestContext::new(cx).await;
 95
 96        cx.set_shared_state("ˇhello\n").await;
 97        cx.simulate_shared_keystrokes("3 i - escape").await;
 98        cx.shared_state().await.assert_eq("--ˇ-hello\n");
 99        cx.simulate_shared_keystrokes(".").await;
100        cx.shared_state().await.assert_eq("----ˇ--hello\n");
101        cx.simulate_shared_keystrokes("2 .").await;
102        cx.shared_state().await.assert_eq("-----ˇ---hello\n");
103
104        cx.set_shared_state("ˇhello\n").await;
105        cx.simulate_shared_keystrokes("2 o k k escape").await;
106        cx.shared_state().await.assert_eq("hello\nkk\nkˇk\n");
107        cx.simulate_shared_keystrokes(".").await;
108        cx.shared_state()
109            .await
110            .assert_eq("hello\nkk\nkk\nkk\nkˇk\n");
111        cx.simulate_shared_keystrokes("1 .").await;
112        cx.shared_state()
113            .await
114            .assert_eq("hello\nkk\nkk\nkk\nkk\nkˇk\n");
115    }
116
117    #[gpui::test]
118    async fn test_insert_ctrl_r(cx: &mut gpui::TestAppContext) {
119        let mut cx = NeovimBackedTestContext::new(cx).await;
120
121        cx.set_shared_state("heˇllo\n").await;
122        cx.simulate_shared_keystrokes("y y i ctrl-r \"").await;
123        cx.shared_state().await.assert_eq("hehello\nˇllo\n");
124
125        cx.simulate_shared_keystrokes("ctrl-r x ctrl-r escape")
126            .await;
127        cx.shared_state().await.assert_eq("hehello\nˇllo\n");
128    }
129}