2024-01-22 16:51:21 +00:00
/// KeyDispatch is where GPUI deals with binding actions to key events.
///
/// The key pieces to making a key binding work are to define an action,
/// implement a method that takes that action as a type paramater,
/// and then to register the action during render on a focused node
/// with a keymap context:
///
/// ```rust
/// actions!(editor,[Undo, Redo]);;
///
/// impl Editor {
/// fn undo(&mut self, _: &Undo, _cx: &mut ViewContext<Self>) { ... }
/// fn redo(&mut self, _: &Redo, _cx: &mut ViewContext<Self>) { ... }
/// }
///
/// impl Render for Editor {
/// fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
/// div()
/// .track_focus(&self.focus_handle)
/// .keymap_context("Editor")
/// .on_action(cx.listener(Editor::undo))
/// .on_action(cx.listener(Editor::redo))
/// ...
/// }
/// }
///```
///
/// The keybindings themselves are managed independently by calling cx.bind_keys().
/// (Though mostly when developing Zed itself, you just need to add a new line to
/// assets/keymaps/default.json).
///
/// ```rust
/// cx.bind_keys([
/// KeyBinding::new("cmd-z", Editor::undo, Some("Editor")),
/// KeyBinding::new("cmd-shift-z", Editor::redo, Some("Editor")),
/// ])
/// ```
///
/// With all of this in place, GPUI will ensure that if you have an Editor that contains
/// the focus, hitting cmd-z will Undo.
///
/// In real apps, it is a little more complicated than this, because typically you have
/// several nested views that each register keyboard handlers. In this case action matching
/// bubbles up from the bottom. For example in Zed, the Workspace is the top-level view, which contains Pane's, which contain Editors. If there are conflicting keybindings defined
/// then the Editor's bindings take precedence over the Pane's bindings, which take precedence over the Workspace.
///
/// In GPUI, keybindings are not limited to just single keystrokes, you can define
/// sequences by separating the keys with a space:
///
/// KeyBinding::new("cmd-k left", pane::SplitLeft, Some("Pane"))
///
2023-11-10 21:47:45 +00:00
use crate ::{
2024-01-22 03:43:35 +00:00
Action , ActionRegistry , DispatchPhase , ElementContext , EntityId , FocusId , KeyBinding ,
2024-01-22 05:03:24 +00:00
KeyContext , Keymap , KeymatchResult , Keystroke , KeystrokeMatcher , WindowContext ,
2023-11-10 21:47:45 +00:00
} ;
2024-01-09 11:37:24 +00:00
use collections ::FxHashMap ;
2023-11-10 21:47:45 +00:00
use parking_lot ::Mutex ;
2024-01-09 14:12:23 +00:00
use smallvec ::{ smallvec , SmallVec } ;
2023-11-10 21:47:45 +00:00
use std ::{
any ::{ Any , TypeId } ,
2024-01-09 11:37:24 +00:00
mem ,
2023-11-13 17:29:18 +00:00
rc ::Rc ,
2023-11-10 21:47:45 +00:00
sync ::Arc ,
} ;
#[ derive(Clone, Copy, Debug, Eq, PartialEq, Hash) ]
2024-01-21 22:26:45 +00:00
pub ( crate ) struct DispatchNodeId ( usize ) ;
2023-11-10 21:47:45 +00:00
2023-11-13 17:29:18 +00:00
pub ( crate ) struct DispatchTree {
2023-11-10 21:47:45 +00:00
node_stack : Vec < DispatchNodeId > ,
2023-12-04 21:28:37 +00:00
pub ( crate ) context_stack : Vec < KeyContext > ,
2023-11-10 21:47:45 +00:00
nodes : Vec < DispatchNode > ,
2024-01-09 11:37:24 +00:00
focusable_node_ids : FxHashMap < FocusId , DispatchNodeId > ,
view_node_ids : FxHashMap < EntityId , DispatchNodeId > ,
keystroke_matchers : FxHashMap < SmallVec < [ KeyContext ; 4 ] > , KeystrokeMatcher > ,
2023-11-10 21:47:45 +00:00
keymap : Arc < Mutex < Keymap > > ,
2023-11-17 01:32:02 +00:00
action_registry : Rc < ActionRegistry > ,
2023-11-10 21:47:45 +00:00
}
#[ derive(Default) ]
2023-11-13 17:29:18 +00:00
pub ( crate ) struct DispatchNode {
2023-12-12 12:16:09 +00:00
pub key_listeners : Vec < KeyListener > ,
pub action_listeners : Vec < DispatchActionListener > ,
2023-12-06 17:02:45 +00:00
pub context : Option < KeyContext > ,
2023-12-13 17:16:39 +00:00
focus_id : Option < FocusId > ,
2024-01-09 11:37:24 +00:00
view_id : Option < EntityId > ,
2023-11-10 21:47:45 +00:00
parent : Option < DispatchNodeId > ,
}
2024-01-22 03:43:35 +00:00
type KeyListener = Rc < dyn Fn ( & dyn Any , DispatchPhase , & mut ElementContext ) > ;
2023-11-13 17:29:18 +00:00
2023-12-21 08:41:48 +00:00
#[ derive(Clone) ]
2023-11-13 19:48:36 +00:00
pub ( crate ) struct DispatchActionListener {
2023-11-13 17:29:18 +00:00
pub ( crate ) action_type : TypeId ,
2024-01-09 11:37:24 +00:00
pub ( crate ) listener : Rc < dyn Fn ( & dyn Any , DispatchPhase , & mut WindowContext ) > ,
2023-11-10 21:47:45 +00:00
}
2023-11-13 17:29:18 +00:00
impl DispatchTree {
2023-11-17 01:32:02 +00:00
pub fn new ( keymap : Arc < Mutex < Keymap > > , action_registry : Rc < ActionRegistry > ) -> Self {
2023-11-10 21:47:45 +00:00
Self {
node_stack : Vec ::new ( ) ,
context_stack : Vec ::new ( ) ,
nodes : Vec ::new ( ) ,
2024-01-09 11:37:24 +00:00
focusable_node_ids : FxHashMap ::default ( ) ,
view_node_ids : FxHashMap ::default ( ) ,
keystroke_matchers : FxHashMap ::default ( ) ,
2023-11-10 21:47:45 +00:00
keymap ,
2023-11-17 01:32:02 +00:00
action_registry ,
2023-11-10 21:47:45 +00:00
}
}
pub fn clear ( & mut self ) {
self . node_stack . clear ( ) ;
2023-11-13 14:31:35 +00:00
self . context_stack . clear ( ) ;
2024-01-09 14:12:23 +00:00
self . nodes . clear ( ) ;
2023-11-13 14:31:35 +00:00
self . focusable_node_ids . clear ( ) ;
2024-01-09 11:37:24 +00:00
self . view_node_ids . clear ( ) ;
2023-11-13 14:31:35 +00:00
self . keystroke_matchers . clear ( ) ;
2023-11-10 21:47:45 +00:00
}
2024-01-09 16:34:57 +00:00
pub fn push_node (
& mut self ,
context : Option < KeyContext > ,
focus_id : Option < FocusId > ,
view_id : Option < EntityId > ,
) {
2023-11-10 21:47:45 +00:00
let parent = self . node_stack . last ( ) . copied ( ) ;
let node_id = DispatchNodeId ( self . nodes . len ( ) ) ;
self . nodes . push ( DispatchNode {
parent ,
2024-01-09 16:34:57 +00:00
focus_id ,
view_id ,
2023-11-10 21:47:45 +00:00
.. Default ::default ( )
} ) ;
self . node_stack . push ( node_id ) ;
2024-01-09 16:34:57 +00:00
2023-12-06 15:15:53 +00:00
if let Some ( context ) = context {
2023-12-06 17:02:45 +00:00
self . active_node ( ) . context = Some ( context . clone ( ) ) ;
2023-11-10 21:47:45 +00:00
self . context_stack . push ( context ) ;
}
2024-01-09 16:34:57 +00:00
if let Some ( focus_id ) = focus_id {
self . focusable_node_ids . insert ( focus_id , node_id ) ;
}
if let Some ( view_id ) = view_id {
self . view_node_ids . insert ( view_id , node_id ) ;
}
2023-11-10 21:47:45 +00:00
}
pub fn pop_node ( & mut self ) {
2024-01-09 14:12:23 +00:00
let node = & self . nodes [ self . active_node_id ( ) . 0 ] ;
if node . context . is_some ( ) {
2023-11-10 21:47:45 +00:00
self . context_stack . pop ( ) ;
}
2024-01-09 14:12:23 +00:00
self . node_stack . pop ( ) ;
2023-11-10 21:47:45 +00:00
}
2024-01-10 14:00:40 +00:00
fn move_node ( & mut self , source : & mut DispatchNode ) {
self . push_node ( source . context . take ( ) , source . focus_id , source . view_id ) ;
let target = self . active_node ( ) ;
target . key_listeners = mem ::take ( & mut source . key_listeners ) ;
target . action_listeners = mem ::take ( & mut source . action_listeners ) ;
2024-01-09 11:37:24 +00:00
}
2024-01-15 18:19:27 +00:00
pub fn reuse_view ( & mut self , view_id : EntityId , source : & mut Self ) -> SmallVec < [ EntityId ; 8 ] > {
2024-01-09 11:37:24 +00:00
let view_source_node_id = source
. view_node_ids
. get ( & view_id )
. expect ( " view should exist in previous dispatch tree " ) ;
let view_source_node = & mut source . nodes [ view_source_node_id . 0 ] ;
self . move_node ( view_source_node ) ;
2024-01-09 14:12:23 +00:00
let mut grafted_view_ids = smallvec! [ view_id ] ;
2024-01-09 11:37:24 +00:00
let mut source_stack = vec! [ * view_source_node_id ] ;
for ( source_node_id , source_node ) in source
. nodes
. iter_mut ( )
. enumerate ( )
. skip ( view_source_node_id . 0 + 1 )
{
let source_node_id = DispatchNodeId ( source_node_id ) ;
while let Some ( source_ancestor ) = source_stack . last ( ) {
if source_node . parent ! = Some ( * source_ancestor ) {
source_stack . pop ( ) ;
self . pop_node ( ) ;
2024-01-10 09:50:16 +00:00
} else {
break ;
2024-01-09 11:37:24 +00:00
}
}
if source_stack . is_empty ( ) {
break ;
} else {
source_stack . push ( source_node_id ) ;
self . move_node ( source_node ) ;
2024-01-09 14:12:23 +00:00
if let Some ( view_id ) = source_node . view_id {
grafted_view_ids . push ( view_id ) ;
}
2024-01-09 11:37:24 +00:00
}
}
while ! source_stack . is_empty ( ) {
2024-01-10 09:50:16 +00:00
source_stack . pop ( ) ;
2024-01-09 11:37:24 +00:00
self . pop_node ( ) ;
}
2024-01-09 14:12:23 +00:00
grafted_view_ids
2024-01-09 11:37:24 +00:00
}
2023-12-05 20:17:59 +00:00
pub fn clear_pending_keystrokes ( & mut self ) {
2023-11-15 19:11:07 +00:00
self . keystroke_matchers . clear ( ) ;
}
/// Preserve keystroke matchers from previous frames to support multi-stroke
/// bindings across multiple frames.
2023-12-05 20:17:59 +00:00
pub fn preserve_pending_keystrokes ( & mut self , old_tree : & mut Self , focus_id : Option < FocusId > ) {
2023-11-15 19:11:07 +00:00
if let Some ( node_id ) = focus_id . and_then ( | focus_id | self . focusable_node_id ( focus_id ) ) {
let dispatch_path = self . dispatch_path ( node_id ) ;
self . context_stack . clear ( ) ;
for node_id in dispatch_path {
let node = self . node ( node_id ) ;
2023-12-06 17:02:45 +00:00
if let Some ( context ) = node . context . clone ( ) {
self . context_stack . push ( context ) ;
2023-11-15 19:11:07 +00:00
}
if let Some ( ( context_stack , matcher ) ) = old_tree
. keystroke_matchers
. remove_entry ( self . context_stack . as_slice ( ) )
{
self . keystroke_matchers . insert ( context_stack , matcher ) ;
}
}
}
}
2023-11-10 21:47:45 +00:00
pub fn on_key_event ( & mut self , listener : KeyListener ) {
self . active_node ( ) . key_listeners . push ( listener ) ;
}
pub fn on_action (
& mut self ,
action_type : TypeId ,
2024-01-09 11:37:24 +00:00
listener : Rc < dyn Fn ( & dyn Any , DispatchPhase , & mut WindowContext ) > ,
2023-11-10 21:47:45 +00:00
) {
2023-11-13 19:48:36 +00:00
self . active_node ( )
. action_listeners
. push ( DispatchActionListener {
action_type ,
listener ,
} ) ;
2023-11-10 21:47:45 +00:00
}
pub fn focus_contains ( & self , parent : FocusId , child : FocusId ) -> bool {
if parent = = child {
return true ;
}
if let Some ( parent_node_id ) = self . focusable_node_ids . get ( & parent ) {
let mut current_node_id = self . focusable_node_ids . get ( & child ) . copied ( ) ;
while let Some ( node_id ) = current_node_id {
if node_id = = * parent_node_id {
return true ;
}
current_node_id = self . nodes [ node_id . 0 ] . parent ;
}
}
false
}
2023-12-06 15:15:53 +00:00
pub fn available_actions ( & self , target : DispatchNodeId ) -> Vec < Box < dyn Action > > {
2023-12-08 21:02:14 +00:00
let mut actions = Vec ::< Box < dyn Action > > ::new ( ) ;
2023-12-06 15:15:53 +00:00
for node_id in self . dispatch_path ( target ) {
let node = & self . nodes [ node_id . 0 ] ;
for DispatchActionListener { action_type , .. } in & node . action_listeners {
2023-12-08 21:02:14 +00:00
if let Err ( ix ) = actions . binary_search_by_key ( action_type , | a | a . as_any ( ) . type_id ( ) )
{
// Intentionally silence these errors without logging.
// If an action cannot be built by default, it's not available.
let action = self . action_registry . build_action_type ( action_type ) . ok ( ) ;
if let Some ( action ) = action {
actions . insert ( ix , action ) ;
}
}
2023-11-10 21:47:45 +00:00
}
}
actions
}
2023-12-06 15:52:52 +00:00
pub fn is_action_available ( & self , action : & dyn Action , target : DispatchNodeId ) -> bool {
for node_id in self . dispatch_path ( target ) {
let node = & self . nodes [ node_id . 0 ] ;
if node
. action_listeners
. iter ( )
. any ( | listener | listener . action_type = = action . as_any ( ) . type_id ( ) )
{
return true ;
2023-12-05 20:17:59 +00:00
}
}
false
}
2023-12-04 21:28:37 +00:00
pub fn bindings_for_action (
& self ,
action : & dyn Action ,
context_stack : & Vec < KeyContext > ,
) -> Vec < KeyBinding > {
2024-01-05 20:07:20 +00:00
let keymap = self . keymap . lock ( ) ;
keymap
. bindings_for_action ( action )
. filter ( | binding | {
2024-01-09 19:52:03 +00:00
for i in 0 .. context_stack . len ( ) {
let context = & context_stack [ 0 ..= i ] ;
2024-01-05 20:07:20 +00:00
if keymap . binding_enabled ( binding , context ) {
2023-12-04 21:28:37 +00:00
return true ;
}
}
2024-01-01 23:09:24 +00:00
false
2023-12-04 20:53:38 +00:00
} )
2023-11-13 22:33:22 +00:00
. cloned ( )
. collect ( )
}
2024-01-22 15:38:20 +00:00
// dispatch_key pushses the next keystroke into any key binding matchers.
// any matching bindings are returned in the order that they should be dispatched:
// * First by length of binding (so if you have a binding for "b" and "ab", the "ab" binding fires first)
// * Secondly by depth in the tree (so if Editor has a binding for "b" and workspace a
// binding for "b", the Editor action fires first).
2023-11-13 17:29:18 +00:00
pub fn dispatch_key (
2023-11-10 21:47:45 +00:00
& mut self ,
2023-11-13 17:29:18 +00:00
keystroke : & Keystroke ,
2024-01-20 21:11:10 +00:00
dispatch_path : & SmallVec < [ DispatchNodeId ; 32 ] > ,
2024-01-21 21:36:59 +00:00
) -> KeymatchResult {
2024-01-22 15:38:20 +00:00
let mut bindings = SmallVec ::< [ KeyBinding ; 1 ] > ::new ( ) ;
2024-01-21 21:36:59 +00:00
let mut pending = false ;
2024-01-20 21:11:10 +00:00
let mut context_stack : SmallVec < [ KeyContext ; 4 ] > = SmallVec ::new ( ) ;
for node_id in dispatch_path {
let node = self . node ( * node_id ) ;
2023-11-10 21:47:45 +00:00
2024-01-20 21:11:10 +00:00
if let Some ( context ) = node . context . clone ( ) {
context_stack . push ( context ) ;
2023-11-10 21:47:45 +00:00
}
2024-01-20 21:11:10 +00:00
}
2023-11-10 21:47:45 +00:00
2024-01-20 21:11:10 +00:00
while ! context_stack . is_empty ( ) {
let keystroke_matcher = self
. keystroke_matchers
. entry ( context_stack . clone ( ) )
. or_insert_with ( | | KeystrokeMatcher ::new ( self . keymap . clone ( ) ) ) ;
2024-01-22 15:38:20 +00:00
let result = keystroke_matcher . match_keystroke ( keystroke , & context_stack ) ;
2024-01-21 21:36:59 +00:00
pending = result . pending | | pending ;
2024-01-22 15:38:20 +00:00
for new_binding in result . bindings {
match bindings
. iter ( )
. position ( | el | el . keystrokes . len ( ) < new_binding . keystrokes . len ( ) )
{
Some ( idx ) = > {
bindings . insert ( idx , new_binding ) ;
}
None = > bindings . push ( new_binding ) ,
}
}
2024-01-20 21:11:10 +00:00
context_stack . pop ( ) ;
2023-11-10 21:47:45 +00:00
}
2024-01-20 21:11:10 +00:00
2024-01-22 04:59:41 +00:00
KeymatchResult { bindings , pending }
2023-11-10 21:47:45 +00:00
}
2023-12-11 22:06:33 +00:00
pub fn has_pending_keystrokes ( & self ) -> bool {
self . keystroke_matchers
. iter ( )
. any ( | ( _ , matcher ) | matcher . has_pending_keystrokes ( ) )
}
2023-11-13 17:29:18 +00:00
pub fn dispatch_path ( & self , target : DispatchNodeId ) -> SmallVec < [ DispatchNodeId ; 32 ] > {
2023-11-10 21:47:45 +00:00
let mut dispatch_path : SmallVec < [ DispatchNodeId ; 32 ] > = SmallVec ::new ( ) ;
let mut current_node_id = Some ( target ) ;
while let Some ( node_id ) = current_node_id {
dispatch_path . push ( node_id ) ;
current_node_id = self . nodes [ node_id . 0 ] . parent ;
}
dispatch_path . reverse ( ) ; // Reverse the path so it goes from the root to the focused node.
dispatch_path
}
2023-11-13 17:29:18 +00:00
2023-12-13 17:16:39 +00:00
pub fn focus_path ( & self , focus_id : FocusId ) -> SmallVec < [ FocusId ; 8 ] > {
let mut focus_path : SmallVec < [ FocusId ; 8 ] > = SmallVec ::new ( ) ;
let mut current_node_id = self . focusable_node_ids . get ( & focus_id ) . copied ( ) ;
while let Some ( node_id ) = current_node_id {
let node = self . node ( node_id ) ;
if let Some ( focus_id ) = node . focus_id {
focus_path . push ( focus_id ) ;
}
current_node_id = node . parent ;
}
focus_path . reverse ( ) ; // Reverse the path so it goes from the root to the focused node.
focus_path
}
2024-01-09 14:12:23 +00:00
pub fn view_path ( & self , view_id : EntityId ) -> SmallVec < [ EntityId ; 8 ] > {
let mut view_path : SmallVec < [ EntityId ; 8 ] > = SmallVec ::new ( ) ;
let mut current_node_id = self . view_node_ids . get ( & view_id ) . copied ( ) ;
while let Some ( node_id ) = current_node_id {
let node = self . node ( node_id ) ;
if let Some ( view_id ) = node . view_id {
view_path . push ( view_id ) ;
}
current_node_id = node . parent ;
}
view_path . reverse ( ) ; // Reverse the path so it goes from the root to the view node.
view_path
}
2023-11-13 17:33:08 +00:00
pub fn node ( & self , node_id : DispatchNodeId ) -> & DispatchNode {
& self . nodes [ node_id . 0 ]
}
fn active_node ( & mut self ) -> & mut DispatchNode {
let active_node_id = self . active_node_id ( ) ;
& mut self . nodes [ active_node_id . 0 ]
}
2023-11-13 17:29:18 +00:00
pub fn focusable_node_id ( & self , target : FocusId ) -> Option < DispatchNodeId > {
self . focusable_node_ids . get ( & target ) . copied ( )
}
2023-11-13 17:33:08 +00:00
2023-12-06 15:15:53 +00:00
pub fn root_node_id ( & self ) -> DispatchNodeId {
debug_assert! ( ! self . nodes . is_empty ( ) ) ;
DispatchNodeId ( 0 )
}
2023-11-13 17:33:08 +00:00
fn active_node_id ( & self ) -> DispatchNodeId {
* self . node_stack . last ( ) . unwrap ( )
}
2023-11-10 21:47:45 +00:00
}
2024-01-09 02:21:54 +00:00
#[ 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 ::< Self > ( )
. map_or ( false , | a | self = = a )
}
fn boxed_clone ( & self ) -> std ::boxed ::Box < dyn Action > {
Box ::new ( TestAction )
}
fn as_any ( & self ) -> & dyn ::std ::any ::Any {
self
}
fn build ( _value : serde_json ::Value ) -> anyhow ::Result < Box < dyn Action > >
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 ::< TestAction > ( ) ;
let keymap = Arc ::new ( Mutex ::new ( keymap ) ) ;
let tree = DispatchTree ::new ( keymap , Rc ::new ( registry ) ) ;
2024-01-09 19:52:03 +00:00
let contexts = vec! [
KeyContext ::parse ( " Workspace " ) . unwrap ( ) ,
KeyContext ::parse ( " ProjectPanel " ) . unwrap ( ) ,
] ;
let keybinding = tree . bindings_for_action ( & TestAction , & contexts ) ;
2024-01-09 02:21:54 +00:00
assert! ( keybinding [ 0 ] . action . partial_eq ( & TestAction ) )
}
}