use crate::error::{Result, SaorsaAgentError};
use std::collections::HashMap;
use std::sync::Arc;
pub type KeybindingHandler = Arc<dyn Fn() -> Result<()> + Send + Sync>;
pub struct KeybindingDefinition {
pub key: String,
pub description: String,
pub handler: KeybindingHandler,
}
impl KeybindingDefinition {
pub fn new(key: String, description: String, handler: KeybindingHandler) -> Self {
Self {
key,
description,
handler,
}
}
}
pub struct KeybindingRegistry {
keybindings: HashMap<String, KeybindingDefinition>,
}
impl KeybindingRegistry {
pub fn new() -> Self {
Self {
keybindings: HashMap::new(),
}
}
pub fn register_keybinding(&mut self, def: KeybindingDefinition) -> Result<()> {
if self.keybindings.contains_key(&def.key) {
return Err(SaorsaAgentError::Extension(format!(
"keybinding '{}' is already registered",
def.key
)));
}
self.keybindings.insert(def.key.clone(), def);
Ok(())
}
pub fn unregister_keybinding(&mut self, key: &str) -> Result<()> {
self.keybindings.remove(key).ok_or_else(|| {
SaorsaAgentError::Extension(format!("keybinding '{}' not found", key))
})?;
Ok(())
}
pub fn get_keybinding(&self, key: &str) -> Option<&KeybindingDefinition> {
self.keybindings.get(key)
}
pub fn list_keybindings(&self) -> Vec<&KeybindingDefinition> {
self.keybindings.values().collect()
}
pub fn execute_keybinding(&self, key: &str) -> Result<()> {
let def = self.keybindings.get(key).ok_or_else(|| {
SaorsaAgentError::Extension(format!("keybinding '{}' not found", key))
})?;
(def.handler)()
}
}
impl Default for KeybindingRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_handler() -> Result<()> {
Ok(())
}
#[test]
fn register_keybinding() {
let mut registry = KeybindingRegistry::new();
let def = KeybindingDefinition::new(
"ctrl+k".to_string(),
"Test keybinding".to_string(),
Arc::new(test_handler),
);
let result = registry.register_keybinding(def);
assert!(result.is_ok());
assert!(registry.get_keybinding("ctrl+k").is_some());
}
#[test]
fn duplicate_keybinding_fails() {
let mut registry = KeybindingRegistry::new();
let def1 = KeybindingDefinition::new(
"ctrl+k".to_string(),
"Test 1".to_string(),
Arc::new(test_handler),
);
let def2 = KeybindingDefinition::new(
"ctrl+k".to_string(),
"Test 2".to_string(),
Arc::new(test_handler),
);
assert!(registry.register_keybinding(def1).is_ok());
let result = registry.register_keybinding(def2);
assert!(result.is_err());
match result {
Err(SaorsaAgentError::Extension(msg)) => {
assert!(msg.contains("already registered"));
}
_ => unreachable!(),
}
}
#[test]
fn unregister_keybinding() {
let mut registry = KeybindingRegistry::new();
let def = KeybindingDefinition::new(
"ctrl+k".to_string(),
"Test".to_string(),
Arc::new(test_handler),
);
assert!(registry.register_keybinding(def).is_ok());
assert!(registry.unregister_keybinding("ctrl+k").is_ok());
assert!(registry.get_keybinding("ctrl+k").is_none());
}
#[test]
fn unregister_nonexistent_fails() {
let mut registry = KeybindingRegistry::new();
let result = registry.unregister_keybinding("nonexistent");
assert!(result.is_err());
match result {
Err(SaorsaAgentError::Extension(msg)) => {
assert!(msg.contains("not found"));
}
_ => unreachable!(),
}
}
#[test]
fn list_keybindings() {
let mut registry = KeybindingRegistry::new();
let def1 = KeybindingDefinition::new(
"ctrl+k".to_string(),
"Test 1".to_string(),
Arc::new(test_handler),
);
let def2 = KeybindingDefinition::new(
"alt+p".to_string(),
"Test 2".to_string(),
Arc::new(test_handler),
);
assert!(registry.register_keybinding(def1).is_ok());
assert!(registry.register_keybinding(def2).is_ok());
let list = registry.list_keybindings();
assert_eq!(list.len(), 2);
}
#[test]
fn execute_keybinding() {
let mut registry = KeybindingRegistry::new();
let def = KeybindingDefinition::new(
"ctrl+k".to_string(),
"Test".to_string(),
Arc::new(test_handler),
);
assert!(registry.register_keybinding(def).is_ok());
let result = registry.execute_keybinding("ctrl+k");
assert!(result.is_ok());
}
#[test]
fn execute_nonexistent_fails() {
let registry = KeybindingRegistry::new();
let result = registry.execute_keybinding("nonexistent");
assert!(result.is_err());
match result {
Err(SaorsaAgentError::Extension(msg)) => {
assert!(msg.contains("not found"));
}
_ => unreachable!(),
}
}
}