Some more woogaloo around action dispatch

Piotr Osiewicz and Conrad created

Co-authored-by: Conrad <conrad@zed.dev>

Change summary

crates/command_palette2/src/command_palette.rs |  3 +
crates/gpui2/src/action.rs                     | 14 +++++
crates/gpui2/src/window.rs                     | 47 +++++++++++++++----
3 files changed, 54 insertions(+), 10 deletions(-)

Detailed changes

crates/command_palette2/src/command_palette.rs 🔗

@@ -33,6 +33,9 @@ pub fn init(cx: &mut AppContext) {
                         return None;
                     };
 
+                    let available_actions = cx.available_actions();
+                    dbg!(&available_actions);
+
                     Some(cx.build_view(|cx| {
                         let delegate =
                             CommandPaletteDelegate::new(cx.view().downgrade(), focus_handle);

crates/gpui2/src/action.rs 🔗

@@ -114,6 +114,7 @@ lazy_static! {
 #[derive(Default)]
 struct ActionRegistry {
     builders_by_name: HashMap<SharedString, ActionBuilder>,
+    builders_by_type_id: HashMap<TypeId, ActionBuilder>,
     all_names: Vec<SharedString>, // So we can return a static slice.
 }
 
@@ -122,9 +123,22 @@ pub fn register_action<A: Action>() {
     let name = A::qualified_name();
     let mut lock = ACTION_REGISTRY.write();
     lock.builders_by_name.insert(name.clone(), A::build);
+    lock.builders_by_type_id.insert(TypeId::of::<A>(), A::build);
     lock.all_names.push(name);
 }
 
+/// Construct an action based on its name and optional JSON parameters sourced from the keymap.
+pub fn build_action_from_type(type_id: &TypeId) -> Result<Box<dyn Action>> {
+    let lock = ACTION_REGISTRY.read();
+
+    let build_action = lock
+        .builders_by_type_id
+        .get(type_id)
+        .ok_or_else(|| anyhow!("no action type registered for {:?}", type_id))?;
+
+    (build_action)(None)
+}
+
 /// Construct an action based on its name and optional JSON parameters sourced from the keymap.
 pub fn build_action(name: &str, params: Option<serde_json::Value>) -> Result<Box<dyn Action>> {
     let lock = ACTION_REGISTRY.read();

crates/gpui2/src/window.rs 🔗

@@ -1,14 +1,15 @@
 use crate::{
-    px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
-    Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels, DispatchContext, DisplayId,
-    Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId,
-    GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch,
-    KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton,
-    MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay,
-    PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render,
-    RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow,
-    SharedString, Size, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline,
-    UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
+    build_action_from_type, px, size, Action, AnyBox, AnyDrag, AnyView, AppContext,
+    AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
+    DevicePixels, DispatchContext, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter,
+    FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla, ImageData, InputEvent,
+    IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers,
+    MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels,
+    PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,
+    PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels,
+    SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet, Subscription,
+    TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakView,
+    WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
 };
 use anyhow::{anyhow, Result};
 use collections::HashMap;
@@ -1295,6 +1296,32 @@ impl<'a> WindowContext<'a> {
         self.window.platform_window.prompt(level, msg, answers)
     }
 
+    pub fn available_actions(&mut self) -> Vec<Box<dyn Action>> {
+        let key_dispatch_stack = &self.window.current_frame.key_dispatch_stack;
+        let mut actions = Vec::new();
+        dbg!(key_dispatch_stack.len());
+        for frame in key_dispatch_stack {
+            match frame {
+                // todo!factor out a KeyDispatchStackFrame::Action
+                KeyDispatchStackFrame::Listener {
+                    event_type,
+                    listener: _,
+                } => {
+                    match build_action_from_type(event_type) {
+                        Ok(action) => {
+                            actions.push(action);
+                        }
+                        Err(err) => {
+                            dbg!(err);
+                        } // we'll hit his if TypeId == KeyDown
+                    }
+                }
+                KeyDispatchStackFrame::Context(_) => {}
+            }
+        }
+        actions
+    }
+
     fn dispatch_action(
         &mut self,
         action: Box<dyn Action>,