@@ -4,16 +4,17 @@ use crate::{
Context, Corners, CursorStyle, Decorations, DevicePixels, DispatchActionListener,
DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter,
FileDropEvent, Flatten, FontId, GPUSpecs, Global, GlobalElementId, GlyphId, Hsla, InputHandler,
- IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke, KeystrokeEvent, LayoutId,
- LineLayoutIndex, Model, ModelContext, Modifiers, ModifiersChangedEvent, MonochromeSprite,
- MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,
- PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,
- PromptLevel, Quad, Render, RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams,
- Replay, ResizeEdge, ScaledPixels, Scene, Shadow, SharedString, Size, StrikethroughStyle, Style,
- SubscriberSet, Subscription, TaffyLayoutEngine, Task, TextStyle, TextStyleRefinement,
- TransformationMatrix, Underline, UnderlineStyle, View, VisualContext, WeakView,
- WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControls, WindowDecorations,
- WindowOptions, WindowParams, WindowTextSystem, SUBPIXEL_VARIANTS,
+ IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke, KeystrokeEvent,
+ KeystrokeObserver, LayoutId, LineLayoutIndex, Model, ModelContext, Modifiers,
+ ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent,
+ Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler,
+ PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams,
+ RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeEdge, ScaledPixels, Scene,
+ Shadow, SharedString, Size, StrikethroughStyle, Style, SubscriberSet, Subscription,
+ TaffyLayoutEngine, Task, TextStyle, TextStyleRefinement, TransformationMatrix, Underline,
+ UnderlineStyle, View, VisualContext, WeakView, WindowAppearance, WindowBackgroundAppearance,
+ WindowBounds, WindowControls, WindowDecorations, WindowOptions, WindowParams, WindowTextSystem,
+ SUBPIXEL_VARIANTS,
};
use anyhow::{anyhow, Context as _, Result};
use collections::{FxHashMap, FxHashSet};
@@ -1043,8 +1044,7 @@ impl<'a> WindowContext<'a> {
action: action.as_ref().map(|action| action.boxed_clone()),
},
self,
- );
- true
+ )
});
}
@@ -4251,6 +4251,36 @@ impl<'a, V: 'static> ViewContext<'a, V> {
subscription
}
+ /// Register a callback to be invoked when a keystroke is received by the application
+ /// in any window. Note that this fires after all other action and event mechanisms have resolved
+ /// and that this API will not be invoked if the event's propagation is stopped.
+ pub fn observe_keystrokes(
+ &mut self,
+ mut f: impl FnMut(&mut V, &KeystrokeEvent, &mut ViewContext<V>) + 'static,
+ ) -> Subscription {
+ fn inner(
+ keystroke_observers: &mut SubscriberSet<(), KeystrokeObserver>,
+ handler: KeystrokeObserver,
+ ) -> Subscription {
+ let (subscription, activate) = keystroke_observers.insert((), handler);
+ activate();
+ subscription
+ }
+
+ let view = self.view.downgrade();
+ inner(
+ &mut self.keystroke_observers,
+ Box::new(move |event, cx| {
+ if let Some(view) = view.upgrade() {
+ view.update(cx, |view, cx| f(view, event, cx));
+ true
+ } else {
+ false
+ }
+ }),
+ )
+ }
+
/// Register a callback to be invoked when the window's pending input changes.
pub fn observe_pending_input(
&mut self,
@@ -24,7 +24,7 @@ use editor::{
};
use gpui::{
actions, impl_actions, Action, AppContext, Entity, EventEmitter, KeyContext, KeystrokeEvent,
- Render, View, ViewContext, WeakView,
+ Render, Subscription, View, ViewContext, WeakView,
};
use insert::NormalBefore;
use language::{CursorShape, Point, Selection, SelectionGoal, TransactionId};
@@ -166,6 +166,8 @@ pub(crate) struct Vim {
pub search: SearchState,
editor: WeakView<Editor>,
+
+ _subscriptions: Vec<Subscription>,
}
// Hack: Vim intercepts events dispatched to a window and updates the view in response.
@@ -189,36 +191,32 @@ impl Vim {
pub fn new(cx: &mut ViewContext<Editor>) -> View<Self> {
let editor = cx.view().clone();
- cx.new_view(|cx: &mut ViewContext<Vim>| {
- cx.subscribe(&editor, |vim, _, event, cx| {
- vim.handle_editor_event(event, cx)
- })
- .detach();
-
- let listener = cx.listener(Vim::observe_keystrokes);
- cx.observe_keystrokes(listener).detach();
-
- Vim {
- mode: Mode::Normal,
- last_mode: Mode::Normal,
- pre_count: None,
- post_count: None,
- operator_stack: Vec::new(),
- replacements: Vec::new(),
-
- marks: HashMap::default(),
- stored_visual_mode: None,
- change_list: Vec::new(),
- change_list_position: None,
- current_tx: None,
- current_anchor: None,
- undo_modes: HashMap::default(),
-
- selected_register: None,
- search: SearchState::default(),
-
- editor: editor.downgrade(),
- }
+ cx.new_view(|cx| Vim {
+ mode: Mode::Normal,
+ last_mode: Mode::Normal,
+ pre_count: None,
+ post_count: None,
+ operator_stack: Vec::new(),
+ replacements: Vec::new(),
+
+ marks: HashMap::default(),
+ stored_visual_mode: None,
+ change_list: Vec::new(),
+ change_list_position: None,
+ current_tx: None,
+ current_anchor: None,
+ undo_modes: HashMap::default(),
+
+ selected_register: None,
+ search: SearchState::default(),
+
+ editor: editor.downgrade(),
+ _subscriptions: vec![
+ cx.observe_keystrokes(Self::observe_keystrokes),
+ cx.subscribe(&editor, |this, _, event, cx| {
+ this.handle_editor_event(event, cx)
+ }),
+ ],
})
}