diff --git a/crates/gpui/src/action.rs b/crates/gpui/src/action.rs index 81b392087a..04e6ccdbfa 100644 --- a/crates/gpui/src/action.rs +++ b/crates/gpui/src/action.rs @@ -114,14 +114,26 @@ impl ActionRegistry { pub(crate) fn load_actions(&mut self) { for builder in __GPUI_ACTIONS { let action = builder(); - //todo(remove) - let name: SharedString = action.name.into(); - self.builders_by_name.insert(name.clone(), action.build); - self.names_by_type_id.insert(action.type_id, name.clone()); - self.all_names.push(name); + self.insert_action(action); } } + #[cfg(test)] + pub(crate) fn load_action(&mut self) { + self.insert_action(ActionData { + name: A::debug_name(), + type_id: TypeId::of::(), + build: A::build, + }); + } + + fn insert_action(&mut self, action: ActionData) { + let name: SharedString = action.name.into(); + self.builders_by_name.insert(name.clone(), action.build); + self.names_by_type_id.insert(action.type_id, name.clone()); + self.all_names.push(name); + } + /// Construct an action based on its name and optional JSON parameters sourced from the keymap. pub fn build_action_type(&self, type_id: &TypeId) -> Result> { let name = self diff --git a/crates/gpui/src/key_dispatch.rs b/crates/gpui/src/key_dispatch.rs index 81f66746c5..cc4af6d7e3 100644 --- a/crates/gpui/src/key_dispatch.rs +++ b/crates/gpui/src/key_dispatch.rs @@ -283,3 +283,76 @@ impl DispatchTree { *self.node_stack.last().unwrap() } } + +#[cfg(test)] +mod tests { + use std::{rc::Rc, sync::Arc}; + + use parking_lot::Mutex; + + use crate::{Action, ActionRegistry, DispatchTree, KeyBinding, KeyContext, Keymap}; + + #[derive(PartialEq, Eq)] + struct TestAction; + + impl Action for TestAction { + fn name(&self) -> &'static str { + "test::TestAction" + } + + fn debug_name() -> &'static str + where + Self: ::std::marker::Sized, + { + "test::TestAction" + } + + fn partial_eq(&self, action: &dyn Action) -> bool { + action + .as_any() + .downcast_ref::() + .map_or(false, |a| self == a) + } + + fn boxed_clone(&self) -> std::boxed::Box { + Box::new(TestAction) + } + + fn as_any(&self) -> &dyn ::std::any::Any { + self + } + + fn build(_value: serde_json::Value) -> anyhow::Result> + where + Self: Sized, + { + Ok(Box::new(TestAction)) + } + } + + #[test] + fn test_keybinding_for_action_bounds() { + let keymap = Keymap::new(vec![KeyBinding::new( + "cmd-n", + TestAction, + Some("ProjectPanel"), + )]); + + let mut registry = ActionRegistry::default(); + + registry.load_action::(); + + let keymap = Arc::new(Mutex::new(keymap)); + + let tree = DispatchTree::new(keymap, Rc::new(registry)); + + let contexts = vec![ + KeyContext::parse("Workspace").unwrap(), + KeyContext::parse("ProjectPanel").unwrap(), + ]; + + let keybinding = tree.bindings_for_action(&TestAction, &contexts); + + assert!(keybinding[0].action.partial_eq(&TestAction)) + } +}