use crate::{KeyCode, KeyModifiers};
#[derive(Debug, Clone)]
pub struct Binding {
pub key: KeyCode,
pub modifiers: Option<KeyModifiers>,
pub display: String,
pub description: String,
pub visible: bool,
}
#[derive(Debug, Clone, Default)]
pub struct KeyMap {
pub bindings: Vec<Binding>,
}
impl KeyMap {
pub fn new() -> Self {
Self::default()
}
pub fn bind(mut self, key: char, description: &str) -> Self {
self.bindings.push(Binding {
key: KeyCode::Char(key),
modifiers: None,
display: key.to_string(),
description: description.to_string(),
visible: true,
});
self
}
pub fn bind_code(mut self, key: KeyCode, description: &str) -> Self {
self.bindings.push(Binding {
display: display_for_key_code(&key),
key,
modifiers: None,
description: description.to_string(),
visible: true,
});
self
}
pub fn bind_mod(mut self, key: char, mods: KeyModifiers, description: &str) -> Self {
self.bindings.push(Binding {
key: KeyCode::Char(key),
modifiers: Some(mods),
display: display_for_mod_char(mods, key),
description: description.to_string(),
visible: true,
});
self
}
pub fn bind_hidden(mut self, key: char, description: &str) -> Self {
self.bindings.push(Binding {
key: KeyCode::Char(key),
modifiers: None,
display: key.to_string(),
description: description.to_string(),
visible: false,
});
self
}
pub fn visible_bindings(&self) -> impl Iterator<Item = &Binding> {
self.bindings.iter().filter(|binding| binding.visible)
}
}
fn display_for_key_code(key: &KeyCode) -> String {
match key {
KeyCode::Char(c) => c.to_string(),
KeyCode::Enter => "Enter".to_string(),
KeyCode::Backspace => "Backspace".to_string(),
KeyCode::Tab => "Tab".to_string(),
KeyCode::BackTab => "Shift+Tab".to_string(),
KeyCode::Esc => "Esc".to_string(),
KeyCode::Up => "↑".to_string(),
KeyCode::Down => "↓".to_string(),
KeyCode::Left => "←".to_string(),
KeyCode::Right => "→".to_string(),
KeyCode::Home => "Home".to_string(),
KeyCode::End => "End".to_string(),
KeyCode::PageUp => "PgUp".to_string(),
KeyCode::PageDown => "PgDn".to_string(),
KeyCode::Delete => "Del".to_string(),
KeyCode::Insert => "Ins".to_string(),
KeyCode::Null => "Null".to_string(),
KeyCode::CapsLock => "CapsLock".to_string(),
KeyCode::ScrollLock => "ScrollLock".to_string(),
KeyCode::NumLock => "NumLock".to_string(),
KeyCode::PrintScreen => "PrtSc".to_string(),
KeyCode::Pause => "Pause".to_string(),
KeyCode::Menu => "Menu".to_string(),
KeyCode::KeypadBegin => "KP5".to_string(),
KeyCode::F(n) => format!("F{n}"),
}
}
fn display_for_mod_char(mods: KeyModifiers, key: char) -> String {
let mut parts: Vec<&str> = Vec::new();
if mods.contains(KeyModifiers::CONTROL) {
parts.push("Ctrl");
}
if mods.contains(KeyModifiers::ALT) {
parts.push("Alt");
}
if mods.contains(KeyModifiers::SHIFT) {
parts.push("Shift");
}
if mods.contains(KeyModifiers::SUPER) {
parts.push("Super");
}
if mods.contains(KeyModifiers::HYPER) {
parts.push("Hyper");
}
if mods.contains(KeyModifiers::META) {
parts.push("Meta");
}
if parts.is_empty() {
key.to_string()
} else {
format!("{}+{}", parts.join("+"), key.to_ascii_uppercase())
}
}