vim.rs

 1mod editor_events;
 2mod insert;
 3mod mode;
 4mod normal;
 5#[cfg(test)]
 6mod vim_tests;
 7
 8use collections::HashMap;
 9use editor::{CursorShape, Editor};
10use gpui::{action, MutableAppContext, ViewContext, WeakViewHandle};
11
12use mode::Mode;
13use workspace::{self, Settings, Workspace};
14
15action!(SwitchMode, Mode);
16
17pub fn init(cx: &mut MutableAppContext) {
18    editor_events::init(cx);
19    insert::init(cx);
20    normal::init(cx);
21
22    cx.add_action(|_: &mut Workspace, action: &SwitchMode, cx| VimState::switch_mode(action, cx));
23
24    cx.observe_global::<Settings, _>(VimState::settings_changed)
25        .detach();
26}
27
28#[derive(Default)]
29pub struct VimState {
30    editors: HashMap<usize, WeakViewHandle<Editor>>,
31    active_editor: Option<WeakViewHandle<Editor>>,
32
33    enabled: bool,
34    mode: Mode,
35}
36
37impl VimState {
38    fn update_active_editor<S>(
39        cx: &mut MutableAppContext,
40        update: impl FnOnce(&mut Editor, &mut ViewContext<Editor>) -> S,
41    ) -> Option<S> {
42        cx.global::<Self>()
43            .active_editor
44            .clone()
45            .and_then(|ae| ae.upgrade(cx))
46            .map(|ae| ae.update(cx, update))
47    }
48
49    fn switch_mode(SwitchMode(mode): &SwitchMode, cx: &mut MutableAppContext) {
50        cx.update_default_global(|this: &mut Self, _| {
51            this.mode = *mode;
52        });
53
54        VimState::sync_editor_options(cx);
55    }
56
57    fn settings_changed(cx: &mut MutableAppContext) {
58        cx.update_default_global(|this: &mut Self, cx| {
59            let settings = cx.global::<Settings>();
60            if this.enabled != settings.vim_mode {
61                this.enabled = settings.vim_mode;
62                this.mode = if settings.vim_mode {
63                    Mode::Normal
64                } else {
65                    Mode::Insert
66                };
67                Self::sync_editor_options(cx);
68            }
69        });
70    }
71
72    fn sync_editor_options(cx: &mut MutableAppContext) {
73        cx.defer(move |cx| {
74            cx.update_default_global(|this: &mut VimState, cx| {
75                let mode = this.mode;
76                let cursor_shape = mode.cursor_shape();
77                let keymap_layer_active = this.enabled;
78                for editor in this.editors.values() {
79                    if let Some(editor) = editor.upgrade(cx) {
80                        editor.update(cx, |editor, cx| {
81                            editor.set_cursor_shape(cursor_shape, cx);
82                            editor.set_clip_at_line_ends(cursor_shape == CursorShape::Block, cx);
83                            editor.set_input_enabled(mode == Mode::Insert);
84                            if keymap_layer_active {
85                                let context_layer = mode.keymap_context_layer();
86                                editor.set_keymap_context_layer::<Self>(context_layer);
87                            } else {
88                                editor.remove_keymap_context_layer::<Self>();
89                            }
90                        });
91                    }
92                }
93            });
94        });
95    }
96}