Fully disable vim mode on start unless it's enabled

Also: Make some structural adjustments to remove the need for defer. Instead of accessing the global in associated VimState functions, have a single method that allows us to call update instance methods.
This commit is contained in:
Nathan Sobo 2022-03-26 14:30:55 -06:00
parent 30e31f6561
commit daf999c3be
5 changed files with 99 additions and 83 deletions

View File

@ -782,7 +782,7 @@ type GlobalActionCallback = dyn FnMut(&dyn AnyAction, &mut MutableAppContext);
type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext) -> bool>; type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext) -> bool>;
type GlobalSubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>; type GlobalSubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
type ObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>; type ObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
type GlobalObservationCallback = Box<dyn FnMut(&mut MutableAppContext)>; type GlobalObservationCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
type ReleaseObservationCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>; type ReleaseObservationCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
pub struct MutableAppContext { pub struct MutableAppContext {
@ -1222,10 +1222,10 @@ impl MutableAppContext {
} }
} }
pub fn observe_global<G, F>(&mut self, observe: F) -> Subscription pub fn observe_global<G, F>(&mut self, mut observe: F) -> Subscription
where where
G: Any, G: Any,
F: 'static + FnMut(&mut MutableAppContext), F: 'static + FnMut(&G, &mut MutableAppContext),
{ {
let type_id = TypeId::of::<G>(); let type_id = TypeId::of::<G>();
let id = post_inc(&mut self.next_subscription_id); let id = post_inc(&mut self.next_subscription_id);
@ -1234,7 +1234,14 @@ impl MutableAppContext {
.lock() .lock()
.entry(type_id) .entry(type_id)
.or_default() .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 { Subscription::GlobalObservation {
id, id,
@ -2075,10 +2082,10 @@ impl MutableAppContext {
fn notify_global_observers(&mut self, observed_type_id: TypeId) { fn notify_global_observers(&mut self, observed_type_id: TypeId) {
let callbacks = self.global_observations.lock().remove(&observed_type_id); let callbacks = self.global_observations.lock().remove(&observed_type_id);
if let Some(callbacks) = callbacks { 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 { for (id, callback) in callbacks {
if let Some(mut callback) = callback { if let Some(mut callback) = callback {
callback(self); callback(global.as_ref(), self);
match self match self
.global_observations .global_observations
.lock() .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 observation_count = Rc::new(RefCell::new(0));
let subscription = cx.observe_global::<Global, _>({ let subscription = cx.observe_global::<Global, _>({
let observation_count = observation_count.clone(); let observation_count = observation_count.clone();
move |_| { move |_, _| {
*observation_count.borrow_mut() += 1; *observation_count.borrow_mut() += 1;
} }
}); });
@ -5262,7 +5270,7 @@ mod tests {
let observation_count = Rc::new(RefCell::new(0)); let observation_count = Rc::new(RefCell::new(0));
cx.observe_global::<OtherGlobal, _>({ cx.observe_global::<OtherGlobal, _>({
let observation_count = observation_count.clone(); let observation_count = observation_count.clone();
move |_| { move |_, _| {
*observation_count.borrow_mut() += 1; *observation_count.borrow_mut() += 1;
} }
}) })
@ -5636,7 +5644,7 @@ mod tests {
*subscription.borrow_mut() = Some(cx.observe_global::<(), _>({ *subscription.borrow_mut() = Some(cx.observe_global::<(), _>({
let observation_count = observation_count.clone(); let observation_count = observation_count.clone();
let subscription = subscription.clone(); let subscription = subscription.clone();
move |_| { move |_, _| {
subscription.borrow_mut().take(); subscription.borrow_mut().take();
*observation_count.borrow_mut() += 1; *observation_count.borrow_mut() += 1;
} }

View File

@ -13,7 +13,7 @@ pub fn init(cx: &mut MutableAppContext) {
fn editor_created(EditorCreated(editor): &EditorCreated, cx: &mut MutableAppContext) { fn editor_created(EditorCreated(editor): &EditorCreated, cx: &mut MutableAppContext) {
cx.update_default_global(|vim_state: &mut VimState, cx| { cx.update_default_global(|vim_state: &mut VimState, cx| {
vim_state.editors.insert(editor.id(), editor.downgrade()); 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 Mode::Normal
}; };
cx.update_default_global(|vim_state: &mut VimState, _| { VimState::update_global(cx, |state, cx| {
vim_state.active_editor = Some(editor.downgrade()); 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) { fn editor_blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut MutableAppContext) {
cx.update_default_global(|vim_state: &mut VimState, _| { VimState::update_global(cx, |state, cx| {
if let Some(previous_editor) = vim_state.active_editor.clone() { if let Some(previous_editor) = state.active_editor.clone() {
if previous_editor == editor.clone() { if previous_editor == editor.clone() {
vim_state.active_editor = None; state.active_editor = None;
} }
} }
}); state.sync_editor_options(cx);
VimState::sync_editor_options(cx); })
} }
fn editor_released(EditorReleased(editor): &EditorReleased, cx: &mut MutableAppContext) { fn editor_released(EditorReleased(editor): &EditorReleased, cx: &mut MutableAppContext) {

View File

@ -18,11 +18,13 @@ pub fn init(cx: &mut MutableAppContext) {
} }
fn normal_before(_: &mut Workspace, _: &NormalBefore, cx: &mut ViewContext<Workspace>) { fn normal_before(_: &mut Workspace, _: &NormalBefore, cx: &mut ViewContext<Workspace>) {
VimState::update_active_editor(cx, |editor, cx| { VimState::update_global(cx, |state, cx| {
state.update_active_editor(cx, |editor, cx| {
editor.move_cursors(cx, |map, mut cursor, _| { editor.move_cursors(cx, |map, mut cursor, _| {
*cursor.column_mut() = cursor.column().saturating_sub(1); *cursor.column_mut() = cursor.column().saturating_sub(1);
(map.clip_point(cursor, Bias::Left), SelectionGoal::None) (map.clip_point(cursor, Bias::Left), SelectionGoal::None)
}); });
}); });
VimState::switch_mode(&SwitchMode(Mode::Normal), cx); state.switch_mode(&SwitchMode(Mode::Normal), cx);
})
} }

View File

@ -28,31 +28,39 @@ pub fn init(cx: &mut MutableAppContext) {
} }
fn move_left(_: &mut Workspace, _: &MoveLeft, cx: &mut ViewContext<Workspace>) { fn move_left(_: &mut Workspace, _: &MoveLeft, cx: &mut ViewContext<Workspace>) {
VimState::update_active_editor(cx, |editor, cx| { VimState::update_global(cx, |state, cx| {
state.update_active_editor(cx, |editor, cx| {
editor.move_cursors(cx, |map, mut cursor, _| { editor.move_cursors(cx, |map, mut cursor, _| {
*cursor.column_mut() = cursor.column().saturating_sub(1); *cursor.column_mut() = cursor.column().saturating_sub(1);
(map.clip_point(cursor, Bias::Left), SelectionGoal::None) (map.clip_point(cursor, Bias::Left), SelectionGoal::None)
}); });
}); });
})
} }
fn move_down(_: &mut Workspace, _: &MoveDown, cx: &mut ViewContext<Workspace>) { fn move_down(_: &mut Workspace, _: &MoveDown, cx: &mut ViewContext<Workspace>) {
VimState::update_active_editor(cx, |editor, cx| { VimState::update_global(cx, |state, cx| {
state.update_active_editor(cx, |editor, cx| {
editor.move_cursors(cx, movement::down); editor.move_cursors(cx, movement::down);
}); });
});
} }
fn move_up(_: &mut Workspace, _: &MoveUp, cx: &mut ViewContext<Workspace>) { fn move_up(_: &mut Workspace, _: &MoveUp, cx: &mut ViewContext<Workspace>) {
VimState::update_active_editor(cx, |editor, cx| { VimState::update_global(cx, |state, cx| {
state.update_active_editor(cx, |editor, cx| {
editor.move_cursors(cx, movement::up); editor.move_cursors(cx, movement::up);
}); });
});
} }
fn move_right(_: &mut Workspace, _: &MoveRight, cx: &mut ViewContext<Workspace>) { fn move_right(_: &mut Workspace, _: &MoveRight, cx: &mut ViewContext<Workspace>) {
VimState::update_active_editor(cx, |editor, cx| { VimState::update_global(cx, |state, cx| {
state.update_active_editor(cx, |editor, cx| {
editor.move_cursors(cx, |map, mut cursor, _| { editor.move_cursors(cx, |map, mut cursor, _| {
*cursor.column_mut() += 1; *cursor.column_mut() += 1;
(map.clip_point(cursor, Bias::Right), SelectionGoal::None) (map.clip_point(cursor, Bias::Right), SelectionGoal::None)
}); });
}); });
});
} }

View File

@ -19,9 +19,13 @@ pub fn init(cx: &mut MutableAppContext) {
insert::init(cx); insert::init(cx);
normal::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::<Settings, _>(VimState::settings_changed) cx.observe_global::<Settings, _>(|settings, cx| {
VimState::update_global(cx, |state, cx| state.set_enabled(settings.vim_mode, cx))
})
.detach(); .detach();
} }
@ -35,62 +39,56 @@ pub struct VimState {
} }
impl VimState { impl VimState {
fn update_global<F, S>(cx: &mut MutableAppContext, update: F) -> S
where
F: FnOnce(&mut Self, &mut MutableAppContext) -> S,
{
cx.update_default_global(update)
}
fn update_active_editor<S>( fn update_active_editor<S>(
&self,
cx: &mut MutableAppContext, cx: &mut MutableAppContext,
update: impl FnOnce(&mut Editor, &mut ViewContext<Editor>) -> S, update: impl FnOnce(&mut Editor, &mut ViewContext<Editor>) -> S,
) -> Option<S> { ) -> Option<S> {
cx.global::<Self>() self.active_editor
.active_editor
.clone() .clone()
.and_then(|ae| ae.upgrade(cx)) .and_then(|ae| ae.upgrade(cx))
.map(|ae| ae.update(cx, update)) .map(|ae| ae.update(cx, update))
} }
fn switch_mode(SwitchMode(mode): &SwitchMode, cx: &mut MutableAppContext) { fn switch_mode(&mut self, SwitchMode(mode): &SwitchMode, cx: &mut MutableAppContext) {
cx.update_default_global(|this: &mut Self, _| { self.mode = *mode;
this.mode = *mode; self.sync_editor_options(cx);
});
VimState::sync_editor_options(cx);
} }
fn settings_changed(cx: &mut MutableAppContext) { fn set_enabled(&mut self, enabled: bool, cx: &mut MutableAppContext) {
cx.update_default_global(|this: &mut Self, cx| { if self.enabled != enabled {
let settings = cx.global::<Settings>(); self.enabled = enabled;
if this.enabled != settings.vim_mode { self.sync_editor_options(cx);
this.enabled = settings.vim_mode;
this.mode = if settings.vim_mode {
Mode::Normal
} else {
Mode::Insert
};
Self::sync_editor_options(cx);
} }
});
} }
fn sync_editor_options(cx: &mut MutableAppContext) { fn sync_editor_options(&self, cx: &mut MutableAppContext) {
cx.defer(move |cx| { let mode = self.mode;
cx.update_default_global(|this: &mut VimState, cx| {
let mode = this.mode;
let cursor_shape = mode.cursor_shape(); let cursor_shape = mode.cursor_shape();
let keymap_layer_active = this.enabled; for editor in self.editors.values() {
for editor in this.editors.values() {
if let Some(editor) = editor.upgrade(cx) { if let Some(editor) = editor.upgrade(cx) {
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
if self.enabled {
editor.set_cursor_shape(cursor_shape, cx); editor.set_cursor_shape(cursor_shape, cx);
editor.set_clip_at_line_ends(cursor_shape == CursorShape::Block, cx); editor.set_clip_at_line_ends(cursor_shape == CursorShape::Block, cx);
editor.set_input_enabled(mode == Mode::Insert); editor.set_input_enabled(mode == Mode::Insert);
if keymap_layer_active {
let context_layer = mode.keymap_context_layer(); let context_layer = mode.keymap_context_layer();
editor.set_keymap_context_layer::<Self>(context_layer); editor.set_keymap_context_layer::<Self>(context_layer);
} else { } 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::<Self>(); editor.remove_keymap_context_layer::<Self>();
} }
}); });
} }
} }
});
});
} }
} }