Skip to main content

saorsa_agent/extension/
keybinding_registry.rs

1//! Keybinding registration system for extensions.
2
3use crate::error::{Result, SaorsaAgentError};
4use std::collections::HashMap;
5use std::sync::Arc;
6
7/// Type alias for keybinding handler functions.
8pub type KeybindingHandler = Arc<dyn Fn() -> Result<()> + Send + Sync>;
9
10/// Keybinding definition registered by an extension.
11pub struct KeybindingDefinition {
12    /// Key combination (e.g., "ctrl+k", "alt+shift+p").
13    pub key: String,
14    /// Human-readable description.
15    pub description: String,
16    /// Keybinding handler function.
17    pub handler: KeybindingHandler,
18}
19
20impl KeybindingDefinition {
21    /// Creates a new keybinding definition.
22    pub fn new(key: String, description: String, handler: KeybindingHandler) -> Self {
23        Self {
24            key,
25            description,
26            handler,
27        }
28    }
29}
30
31/// Registry for extension-provided keybindings.
32pub struct KeybindingRegistry {
33    keybindings: HashMap<String, KeybindingDefinition>,
34}
35
36impl KeybindingRegistry {
37    /// Creates a new empty keybinding registry.
38    pub fn new() -> Self {
39        Self {
40            keybindings: HashMap::new(),
41        }
42    }
43
44    /// Registers a keybinding.
45    ///
46    /// Returns an error if a keybinding with the same key is already registered.
47    pub fn register_keybinding(&mut self, def: KeybindingDefinition) -> Result<()> {
48        if self.keybindings.contains_key(&def.key) {
49            return Err(SaorsaAgentError::Extension(format!(
50                "keybinding '{}' is already registered",
51                def.key
52            )));
53        }
54        self.keybindings.insert(def.key.clone(), def);
55        Ok(())
56    }
57
58    /// Unregisters a keybinding by key.
59    ///
60    /// Returns an error if the keybinding is not found.
61    pub fn unregister_keybinding(&mut self, key: &str) -> Result<()> {
62        self.keybindings.remove(key).ok_or_else(|| {
63            SaorsaAgentError::Extension(format!("keybinding '{}' not found", key))
64        })?;
65        Ok(())
66    }
67
68    /// Gets a keybinding definition by key.
69    pub fn get_keybinding(&self, key: &str) -> Option<&KeybindingDefinition> {
70        self.keybindings.get(key)
71    }
72
73    /// Lists all registered keybindings.
74    pub fn list_keybindings(&self) -> Vec<&KeybindingDefinition> {
75        self.keybindings.values().collect()
76    }
77
78    /// Executes a keybinding handler by key.
79    ///
80    /// Returns an error if the keybinding is not found or execution fails.
81    pub fn execute_keybinding(&self, key: &str) -> Result<()> {
82        let def = self.keybindings.get(key).ok_or_else(|| {
83            SaorsaAgentError::Extension(format!("keybinding '{}' not found", key))
84        })?;
85        (def.handler)()
86    }
87}
88
89impl Default for KeybindingRegistry {
90    fn default() -> Self {
91        Self::new()
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    fn test_handler() -> Result<()> {
100        Ok(())
101    }
102
103    #[test]
104    fn register_keybinding() {
105        let mut registry = KeybindingRegistry::new();
106        let def = KeybindingDefinition::new(
107            "ctrl+k".to_string(),
108            "Test keybinding".to_string(),
109            Arc::new(test_handler),
110        );
111        let result = registry.register_keybinding(def);
112        assert!(result.is_ok());
113        assert!(registry.get_keybinding("ctrl+k").is_some());
114    }
115
116    #[test]
117    fn duplicate_keybinding_fails() {
118        let mut registry = KeybindingRegistry::new();
119        let def1 = KeybindingDefinition::new(
120            "ctrl+k".to_string(),
121            "Test 1".to_string(),
122            Arc::new(test_handler),
123        );
124        let def2 = KeybindingDefinition::new(
125            "ctrl+k".to_string(),
126            "Test 2".to_string(),
127            Arc::new(test_handler),
128        );
129        assert!(registry.register_keybinding(def1).is_ok());
130        let result = registry.register_keybinding(def2);
131        assert!(result.is_err());
132        match result {
133            Err(SaorsaAgentError::Extension(msg)) => {
134                assert!(msg.contains("already registered"));
135            }
136            _ => unreachable!(),
137        }
138    }
139
140    #[test]
141    fn unregister_keybinding() {
142        let mut registry = KeybindingRegistry::new();
143        let def = KeybindingDefinition::new(
144            "ctrl+k".to_string(),
145            "Test".to_string(),
146            Arc::new(test_handler),
147        );
148        assert!(registry.register_keybinding(def).is_ok());
149        assert!(registry.unregister_keybinding("ctrl+k").is_ok());
150        assert!(registry.get_keybinding("ctrl+k").is_none());
151    }
152
153    #[test]
154    fn unregister_nonexistent_fails() {
155        let mut registry = KeybindingRegistry::new();
156        let result = registry.unregister_keybinding("nonexistent");
157        assert!(result.is_err());
158        match result {
159            Err(SaorsaAgentError::Extension(msg)) => {
160                assert!(msg.contains("not found"));
161            }
162            _ => unreachable!(),
163        }
164    }
165
166    #[test]
167    fn list_keybindings() {
168        let mut registry = KeybindingRegistry::new();
169        let def1 = KeybindingDefinition::new(
170            "ctrl+k".to_string(),
171            "Test 1".to_string(),
172            Arc::new(test_handler),
173        );
174        let def2 = KeybindingDefinition::new(
175            "alt+p".to_string(),
176            "Test 2".to_string(),
177            Arc::new(test_handler),
178        );
179        assert!(registry.register_keybinding(def1).is_ok());
180        assert!(registry.register_keybinding(def2).is_ok());
181        let list = registry.list_keybindings();
182        assert_eq!(list.len(), 2);
183    }
184
185    #[test]
186    fn execute_keybinding() {
187        let mut registry = KeybindingRegistry::new();
188        let def = KeybindingDefinition::new(
189            "ctrl+k".to_string(),
190            "Test".to_string(),
191            Arc::new(test_handler),
192        );
193        assert!(registry.register_keybinding(def).is_ok());
194        let result = registry.execute_keybinding("ctrl+k");
195        assert!(result.is_ok());
196    }
197
198    #[test]
199    fn execute_nonexistent_fails() {
200        let registry = KeybindingRegistry::new();
201        let result = registry.execute_keybinding("nonexistent");
202        assert!(result.is_err());
203        match result {
204            Err(SaorsaAgentError::Extension(msg)) => {
205                assert!(msg.contains("not found"));
206            }
207            _ => unreachable!(),
208        }
209    }
210}