1use std::ops::{Deref, DerefMut};
2
3use editor::test::{
4 editor_lsp_test_context::EditorLspTestContext, editor_test_context::EditorTestContext,
5};
6use gpui::ContextHandle;
7use search::{BufferSearchBar, ProjectSearchBar};
8
9use crate::{state::Operator, *};
10
11use super::VimBindingTestContext;
12
13pub struct VimTestContext<'a> {
14 cx: EditorLspTestContext<'a>,
15}
16
17impl<'a> VimTestContext<'a> {
18 pub async fn new(cx: &'a mut gpui::TestAppContext, enabled: bool) -> VimTestContext<'a> {
19 let mut cx = EditorLspTestContext::new_rust(Default::default(), cx).await;
20 cx.update(|cx| {
21 cx.update_global(|settings: &mut Settings, _| {
22 settings.vim_mode = enabled;
23 });
24 search::init(cx);
25 crate::init(cx);
26
27 settings::KeymapFileContent::load("keymaps/vim.json", cx).unwrap();
28 });
29
30 // Setup search toolbars and keypress hook
31 cx.update_workspace(|workspace, cx| {
32 observe_keystrokes(cx);
33 workspace.active_pane().update(cx, |pane, cx| {
34 pane.toolbar().update(cx, |toolbar, cx| {
35 let buffer_search_bar = cx.add_view(BufferSearchBar::new);
36 toolbar.add_item(buffer_search_bar, cx);
37 let project_search_bar = cx.add_view(|_| ProjectSearchBar::new());
38 toolbar.add_item(project_search_bar, cx);
39 })
40 });
41 });
42
43 Self { cx }
44 }
45
46 pub fn workspace<F, T>(&mut self, read: F) -> T
47 where
48 F: FnOnce(&Workspace, &ViewContext<Workspace>) -> T,
49 {
50 self.cx.workspace.read_with(self.cx.cx.cx, read)
51 }
52
53 pub fn enable_vim(&mut self) {
54 self.cx.update(|cx| {
55 cx.update_global(|settings: &mut Settings, _| {
56 settings.vim_mode = true;
57 });
58 })
59 }
60
61 pub fn disable_vim(&mut self) {
62 self.cx.update(|cx| {
63 cx.update_global(|settings: &mut Settings, _| {
64 settings.vim_mode = false;
65 });
66 })
67 }
68
69 pub fn mode(&mut self) -> Mode {
70 self.cx.read(|cx| cx.global::<Vim>().state.mode)
71 }
72
73 pub fn active_operator(&mut self) -> Option<Operator> {
74 self.cx
75 .read(|cx| cx.global::<Vim>().state.operator_stack.last().copied())
76 }
77
78 pub fn set_state(&mut self, text: &str, mode: Mode) -> ContextHandle {
79 let window_id = self.window_id;
80 self.update_window(window_id, |cx| {
81 Vim::update(cx, |vim, cx| {
82 vim.switch_mode(mode, false, cx);
83 })
84 });
85 self.cx.set_state(text)
86 }
87
88 pub fn assert_state(&mut self, text: &str, mode: Mode) {
89 self.assert_editor_state(text);
90 assert_eq!(self.mode(), mode, "{}", self.assertion_context());
91 }
92
93 pub fn assert_binding<const COUNT: usize>(
94 &mut self,
95 keystrokes: [&str; COUNT],
96 initial_state: &str,
97 initial_mode: Mode,
98 state_after: &str,
99 mode_after: Mode,
100 ) {
101 self.set_state(initial_state, initial_mode);
102 self.cx.simulate_keystrokes(keystrokes);
103 self.cx.assert_editor_state(state_after);
104 assert_eq!(self.mode(), mode_after, "{}", self.assertion_context());
105 assert_eq!(self.active_operator(), None, "{}", self.assertion_context());
106 }
107
108 pub fn binding<const COUNT: usize>(
109 mut self,
110 keystrokes: [&'static str; COUNT],
111 ) -> VimBindingTestContext<'a, COUNT> {
112 let mode = self.mode();
113 VimBindingTestContext::new(keystrokes, mode, mode, self)
114 }
115}
116
117impl<'a> Deref for VimTestContext<'a> {
118 type Target = EditorTestContext<'a>;
119
120 fn deref(&self) -> &Self::Target {
121 &self.cx
122 }
123}
124
125impl<'a> DerefMut for VimTestContext<'a> {
126 fn deref_mut(&mut self) -> &mut Self::Target {
127 &mut self.cx
128 }
129}