diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index a291ad3c4b..7f0c3ffcde 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -782,7 +782,7 @@ type GlobalActionCallback = dyn FnMut(&dyn AnyAction, &mut MutableAppContext); type SubscriptionCallback = Box bool>; type GlobalSubscriptionCallback = Box; type ObservationCallback = Box bool>; -type GlobalObservationCallback = Box; +type GlobalObservationCallback = Box; type ReleaseObservationCallback = Box; pub struct MutableAppContext { @@ -1222,10 +1222,10 @@ impl MutableAppContext { } } - pub fn observe_global(&mut self, observe: F) -> Subscription + pub fn observe_global(&mut self, mut observe: F) -> Subscription where G: Any, - F: 'static + FnMut(&mut MutableAppContext), + F: 'static + FnMut(&G, &mut MutableAppContext), { let type_id = TypeId::of::(); let id = post_inc(&mut self.next_subscription_id); @@ -1234,7 +1234,14 @@ impl MutableAppContext { .lock() .entry(type_id) .or_default() - .insert(id, Some(Box::new(observe))); + .insert( + id, + Some( + Box::new(move |global: &dyn Any, cx: &mut MutableAppContext| { + observe(global.downcast_ref().unwrap(), cx) + }) as GlobalObservationCallback, + ), + ); Subscription::GlobalObservation { id, @@ -2075,10 +2082,10 @@ impl MutableAppContext { fn notify_global_observers(&mut self, observed_type_id: TypeId) { let callbacks = self.global_observations.lock().remove(&observed_type_id); if let Some(callbacks) = callbacks { - if self.cx.globals.contains_key(&observed_type_id) { + if let Some(global) = self.cx.globals.remove(&observed_type_id) { for (id, callback) in callbacks { if let Some(mut callback) = callback { - callback(self); + callback(global.as_ref(), self); match self .global_observations .lock() @@ -2095,6 +2102,7 @@ impl MutableAppContext { } } } + self.cx.globals.insert(observed_type_id, global); } } } @@ -5232,7 +5240,7 @@ mod tests { let observation_count = Rc::new(RefCell::new(0)); let subscription = cx.observe_global::({ let observation_count = observation_count.clone(); - move |_| { + move |_, _| { *observation_count.borrow_mut() += 1; } }); @@ -5262,7 +5270,7 @@ mod tests { let observation_count = Rc::new(RefCell::new(0)); cx.observe_global::({ let observation_count = observation_count.clone(); - move |_| { + move |_, _| { *observation_count.borrow_mut() += 1; } }) @@ -5636,7 +5644,7 @@ mod tests { *subscription.borrow_mut() = Some(cx.observe_global::<(), _>({ let observation_count = observation_count.clone(); let subscription = subscription.clone(); - move |_| { + move |_, _| { subscription.borrow_mut().take(); *observation_count.borrow_mut() += 1; } diff --git a/crates/vim/src/editor_events.rs b/crates/vim/src/editor_events.rs index 2f8a60ef33..7e49b473f9 100644 --- a/crates/vim/src/editor_events.rs +++ b/crates/vim/src/editor_events.rs @@ -13,7 +13,7 @@ pub fn init(cx: &mut MutableAppContext) { fn editor_created(EditorCreated(editor): &EditorCreated, cx: &mut MutableAppContext) { cx.update_default_global(|vim_state: &mut VimState, cx| { vim_state.editors.insert(editor.id(), editor.downgrade()); - VimState::sync_editor_options(cx); + vim_state.sync_editor_options(cx); }) } @@ -24,21 +24,21 @@ fn editor_focused(EditorFocused(editor): &EditorFocused, cx: &mut MutableAppCont Mode::Normal }; - cx.update_default_global(|vim_state: &mut VimState, _| { - vim_state.active_editor = Some(editor.downgrade()); + VimState::update_global(cx, |state, cx| { + state.active_editor = Some(editor.downgrade()); + state.switch_mode(&SwitchMode(mode), cx); }); - VimState::switch_mode(&SwitchMode(mode), cx); } fn editor_blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut MutableAppContext) { - cx.update_default_global(|vim_state: &mut VimState, _| { - if let Some(previous_editor) = vim_state.active_editor.clone() { + VimState::update_global(cx, |state, cx| { + if let Some(previous_editor) = state.active_editor.clone() { if previous_editor == editor.clone() { - vim_state.active_editor = None; + state.active_editor = None; } } - }); - VimState::sync_editor_options(cx); + state.sync_editor_options(cx); + }) } fn editor_released(EditorReleased(editor): &EditorReleased, cx: &mut MutableAppContext) { diff --git a/crates/vim/src/insert.rs b/crates/vim/src/insert.rs index 50fd53b37b..c027ff2c1f 100644 --- a/crates/vim/src/insert.rs +++ b/crates/vim/src/insert.rs @@ -18,11 +18,13 @@ pub fn init(cx: &mut MutableAppContext) { } fn normal_before(_: &mut Workspace, _: &NormalBefore, cx: &mut ViewContext) { - VimState::update_active_editor(cx, |editor, cx| { - editor.move_cursors(cx, |map, mut cursor, _| { - *cursor.column_mut() = cursor.column().saturating_sub(1); - (map.clip_point(cursor, Bias::Left), SelectionGoal::None) + VimState::update_global(cx, |state, cx| { + state.update_active_editor(cx, |editor, cx| { + editor.move_cursors(cx, |map, mut cursor, _| { + *cursor.column_mut() = cursor.column().saturating_sub(1); + (map.clip_point(cursor, Bias::Left), SelectionGoal::None) + }); }); - }); - VimState::switch_mode(&SwitchMode(Mode::Normal), cx); + state.switch_mode(&SwitchMode(Mode::Normal), cx); + }) } diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs index 87218b3f5f..232a76a030 100644 --- a/crates/vim/src/normal.rs +++ b/crates/vim/src/normal.rs @@ -28,31 +28,39 @@ pub fn init(cx: &mut MutableAppContext) { } fn move_left(_: &mut Workspace, _: &MoveLeft, cx: &mut ViewContext) { - VimState::update_active_editor(cx, |editor, cx| { - editor.move_cursors(cx, |map, mut cursor, _| { - *cursor.column_mut() = cursor.column().saturating_sub(1); - (map.clip_point(cursor, Bias::Left), SelectionGoal::None) + VimState::update_global(cx, |state, cx| { + state.update_active_editor(cx, |editor, cx| { + editor.move_cursors(cx, |map, mut cursor, _| { + *cursor.column_mut() = cursor.column().saturating_sub(1); + (map.clip_point(cursor, Bias::Left), SelectionGoal::None) + }); }); - }); + }) } fn move_down(_: &mut Workspace, _: &MoveDown, cx: &mut ViewContext) { - VimState::update_active_editor(cx, |editor, cx| { - editor.move_cursors(cx, movement::down); + VimState::update_global(cx, |state, cx| { + state.update_active_editor(cx, |editor, cx| { + editor.move_cursors(cx, movement::down); + }); }); } fn move_up(_: &mut Workspace, _: &MoveUp, cx: &mut ViewContext) { - VimState::update_active_editor(cx, |editor, cx| { - editor.move_cursors(cx, movement::up); + VimState::update_global(cx, |state, cx| { + state.update_active_editor(cx, |editor, cx| { + editor.move_cursors(cx, movement::up); + }); }); } fn move_right(_: &mut Workspace, _: &MoveRight, cx: &mut ViewContext) { - VimState::update_active_editor(cx, |editor, cx| { - editor.move_cursors(cx, |map, mut cursor, _| { - *cursor.column_mut() += 1; - (map.clip_point(cursor, Bias::Right), SelectionGoal::None) + VimState::update_global(cx, |state, cx| { + state.update_active_editor(cx, |editor, cx| { + editor.move_cursors(cx, |map, mut cursor, _| { + *cursor.column_mut() += 1; + (map.clip_point(cursor, Bias::Right), SelectionGoal::None) + }); }); }); } diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index 68ecd4e003..c6905a9c7a 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -19,10 +19,14 @@ pub fn init(cx: &mut MutableAppContext) { insert::init(cx); normal::init(cx); - cx.add_action(|_: &mut Workspace, action: &SwitchMode, cx| VimState::switch_mode(action, cx)); + cx.add_action(|_: &mut Workspace, action: &SwitchMode, cx| { + VimState::update_global(cx, |state, cx| state.switch_mode(action, cx)) + }); - cx.observe_global::(VimState::settings_changed) - .detach(); + cx.observe_global::(|settings, cx| { + VimState::update_global(cx, |state, cx| state.set_enabled(settings.vim_mode, cx)) + }) + .detach(); } #[derive(Default)] @@ -35,62 +39,56 @@ pub struct VimState { } impl VimState { + fn update_global(cx: &mut MutableAppContext, update: F) -> S + where + F: FnOnce(&mut Self, &mut MutableAppContext) -> S, + { + cx.update_default_global(update) + } + fn update_active_editor( + &self, cx: &mut MutableAppContext, update: impl FnOnce(&mut Editor, &mut ViewContext) -> S, ) -> Option { - cx.global::() - .active_editor + self.active_editor .clone() .and_then(|ae| ae.upgrade(cx)) .map(|ae| ae.update(cx, update)) } - fn switch_mode(SwitchMode(mode): &SwitchMode, cx: &mut MutableAppContext) { - cx.update_default_global(|this: &mut Self, _| { - this.mode = *mode; - }); - - VimState::sync_editor_options(cx); + fn switch_mode(&mut self, SwitchMode(mode): &SwitchMode, cx: &mut MutableAppContext) { + self.mode = *mode; + self.sync_editor_options(cx); } - fn settings_changed(cx: &mut MutableAppContext) { - cx.update_default_global(|this: &mut Self, cx| { - let settings = cx.global::(); - if this.enabled != settings.vim_mode { - this.enabled = settings.vim_mode; - this.mode = if settings.vim_mode { - Mode::Normal - } else { - Mode::Insert - }; - Self::sync_editor_options(cx); - } - }); + fn set_enabled(&mut self, enabled: bool, cx: &mut MutableAppContext) { + if self.enabled != enabled { + self.enabled = enabled; + self.sync_editor_options(cx); + } } - fn sync_editor_options(cx: &mut MutableAppContext) { - cx.defer(move |cx| { - cx.update_default_global(|this: &mut VimState, cx| { - let mode = this.mode; - let cursor_shape = mode.cursor_shape(); - let keymap_layer_active = this.enabled; - for editor in this.editors.values() { - if let Some(editor) = editor.upgrade(cx) { - editor.update(cx, |editor, cx| { - editor.set_cursor_shape(cursor_shape, cx); - editor.set_clip_at_line_ends(cursor_shape == CursorShape::Block, cx); - editor.set_input_enabled(mode == Mode::Insert); - if keymap_layer_active { - let context_layer = mode.keymap_context_layer(); - editor.set_keymap_context_layer::(context_layer); - } else { - editor.remove_keymap_context_layer::(); - } - }); + fn sync_editor_options(&self, cx: &mut MutableAppContext) { + let mode = self.mode; + let cursor_shape = mode.cursor_shape(); + for editor in self.editors.values() { + if let Some(editor) = editor.upgrade(cx) { + editor.update(cx, |editor, cx| { + if self.enabled { + editor.set_cursor_shape(cursor_shape, cx); + editor.set_clip_at_line_ends(cursor_shape == CursorShape::Block, cx); + editor.set_input_enabled(mode == Mode::Insert); + let context_layer = mode.keymap_context_layer(); + editor.set_keymap_context_layer::(context_layer); + } else { + editor.set_cursor_shape(CursorShape::Bar, cx); + editor.set_clip_at_line_ends(false, cx); + editor.set_input_enabled(true); + editor.remove_keymap_context_layer::(); } - } - }); - }); + }); + } + } } }