1use crossterm::event::{KeyCode, KeyModifiers};
6use std::cell::RefCell;
7use std::collections::HashMap;
8use std::rc::Rc;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct KeyBinding {
13 pub code: KeyCode,
14 pub modifiers: KeyModifiers,
15}
16
17impl KeyBinding {
18 pub fn new(code: KeyCode, modifiers: KeyModifiers) -> Self {
20 Self { code, modifiers }
21 }
22
23 pub fn key(code: KeyCode) -> Self {
25 Self::new(code, KeyModifiers::NONE)
26 }
27
28 pub fn ctrl(c: char) -> Self {
30 Self::new(KeyCode::Char(c), KeyModifiers::CONTROL)
31 }
32
33 pub fn alt(c: char) -> Self {
35 Self::new(KeyCode::Char(c), KeyModifiers::ALT)
36 }
37
38 pub fn shift(c: char) -> Self {
40 Self::new(KeyCode::Char(c), KeyModifiers::SHIFT)
41 }
42
43 pub fn matches(&self, code: KeyCode, modifiers: KeyModifiers) -> bool {
45 self.code == code && self.modifiers == modifiers
46 }
47}
48
49pub type CommandCallback = Rc<dyn Fn()>;
51
52#[derive(Default)]
54pub struct CommandRegistry {
55 commands: RefCell<HashMap<KeyBinding, CommandCallback>>,
56}
57
58impl CommandRegistry {
59 pub fn new() -> Self {
60 Self::default()
61 }
62
63 pub fn register(&self, binding: KeyBinding, callback: CommandCallback) {
65 self.commands.borrow_mut().insert(binding, callback);
66 }
67
68 pub fn clear(&self) {
70 self.commands.borrow_mut().clear();
71 }
72
73 pub fn execute(&self, code: KeyCode, modifiers: KeyModifiers) -> bool {
76 let commands = self.commands.borrow();
77 for (binding, callback) in commands.iter() {
78 if binding.matches(code, modifiers) {
79 callback();
80 return true;
81 }
82 }
83 false
84 }
85
86 pub fn has_binding(&self, code: KeyCode, modifiers: KeyModifiers) -> bool {
88 let commands = self.commands.borrow();
89 commands.keys().any(|b| b.matches(code, modifiers))
90 }
91}