#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Key {
Char(char),
ArrowUp,
ArrowDown,
ArrowLeft,
ArrowRight,
F(u8),
Enter,
Escape,
Tab,
BackTab,
Backspace,
Delete,
Home,
End,
PageUp,
PageDown,
}
use crossterm::event::KeyCode;
impl TryFrom<KeyCode> for Key {
type Error = ();
fn try_from(code: KeyCode) -> Result<Self, Self::Error> {
Ok(match code {
KeyCode::Char(c) => Key::Char(c),
KeyCode::Up => Key::ArrowUp,
KeyCode::Down => Key::ArrowDown,
KeyCode::Left => Key::ArrowLeft,
KeyCode::Right => Key::ArrowRight,
KeyCode::Enter => Key::Enter,
KeyCode::Esc => Key::Escape,
KeyCode::Tab => Key::Tab,
KeyCode::BackTab => Key::BackTab,
KeyCode::Backspace => Key::Backspace,
KeyCode::Delete => Key::Delete,
KeyCode::Home => Key::Home,
KeyCode::End => Key::End,
KeyCode::PageUp => Key::PageUp,
KeyCode::PageDown => Key::PageDown,
KeyCode::F(n) => Key::F(n),
_ => return Err(()),
})
}
}
use std::fmt;
impl fmt::Display for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Key::Char(c) => write!(f, "{}", c.to_ascii_lowercase()),
Key::ArrowUp => write!(f, "ArrowUp"),
Key::ArrowDown => write!(f, "ArrowDown"),
Key::ArrowLeft => write!(f, "ArrowLeft"),
Key::ArrowRight => write!(f, "ArrowRight"),
Key::F(n) => write!(f, "F{}", n),
Key::Enter => write!(f, "Enter"),
Key::Escape => write!(f, "Escape"),
Key::Tab => write!(f, "Tab"),
Key::BackTab => write!(f, "BackTab"),
Key::Backspace => write!(f, "Backspace"),
Key::Delete => write!(f, "Delete"),
Key::Home => write!(f, "Home"),
Key::End => write!(f, "End"),
Key::PageUp => write!(f, "PageUp"),
Key::PageDown => write!(f, "PageDown"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn try_from_char() {
assert_eq!(Key::try_from(KeyCode::Char('a')), Ok(Key::Char('a')));
}
#[test]
fn try_from_up() {
assert_eq!(Key::try_from(KeyCode::Up), Ok(Key::ArrowUp));
}
#[test]
fn try_from_down() {
assert_eq!(Key::try_from(KeyCode::Down), Ok(Key::ArrowDown));
}
#[test]
fn try_from_left() {
assert_eq!(Key::try_from(KeyCode::Left), Ok(Key::ArrowLeft));
}
#[test]
fn try_from_right() {
assert_eq!(Key::try_from(KeyCode::Right), Ok(Key::ArrowRight));
}
#[test]
fn try_from_enter() {
assert_eq!(Key::try_from(KeyCode::Enter), Ok(Key::Enter));
}
#[test]
fn try_from_escape() {
assert_eq!(Key::try_from(KeyCode::Esc), Ok(Key::Escape));
}
#[test]
fn try_from_tab() {
assert_eq!(Key::try_from(KeyCode::Tab), Ok(Key::Tab));
}
#[test]
fn try_from_backtab() {
assert_eq!(Key::try_from(KeyCode::BackTab), Ok(Key::BackTab));
}
#[test]
fn try_from_backspace() {
assert_eq!(Key::try_from(KeyCode::Backspace), Ok(Key::Backspace));
}
#[test]
fn try_from_delete() {
assert_eq!(Key::try_from(KeyCode::Delete), Ok(Key::Delete));
}
#[test]
fn try_from_home() {
assert_eq!(Key::try_from(KeyCode::Home), Ok(Key::Home));
}
#[test]
fn try_from_end() {
assert_eq!(Key::try_from(KeyCode::End), Ok(Key::End));
}
#[test]
fn try_from_page_up() {
assert_eq!(Key::try_from(KeyCode::PageUp), Ok(Key::PageUp));
}
#[test]
fn try_from_page_down() {
assert_eq!(Key::try_from(KeyCode::PageDown), Ok(Key::PageDown));
}
#[test]
fn try_from_f_key() {
assert_eq!(Key::try_from(KeyCode::F(1)), Ok(Key::F(1)));
}
#[test]
fn try_from_f_key_12() {
assert_eq!(Key::try_from(KeyCode::F(12)), Ok(Key::F(12)));
}
#[test]
fn try_from_null_is_err() {
assert!(Key::try_from(KeyCode::Null).is_err());
}
#[test]
fn display_char_uppercase_lowercased() {
assert_eq!(Key::Char('A').to_string(), "a");
}
#[test]
fn display_char_already_lower() {
assert_eq!(Key::Char('z').to_string(), "z");
}
#[test]
fn display_char_digit() {
assert_eq!(Key::Char('5').to_string(), "5");
}
#[test]
fn display_arrow_up() {
assert_eq!(Key::ArrowUp.to_string(), "ArrowUp");
}
#[test]
fn display_arrow_down() {
assert_eq!(Key::ArrowDown.to_string(), "ArrowDown");
}
#[test]
fn display_arrow_left() {
assert_eq!(Key::ArrowLeft.to_string(), "ArrowLeft");
}
#[test]
fn display_arrow_right() {
assert_eq!(Key::ArrowRight.to_string(), "ArrowRight");
}
#[test]
fn display_enter() {
assert_eq!(Key::Enter.to_string(), "Enter");
}
#[test]
fn display_escape() {
assert_eq!(Key::Escape.to_string(), "Escape");
}
#[test]
fn display_tab() {
assert_eq!(Key::Tab.to_string(), "Tab");
}
#[test]
fn display_backtab() {
assert_eq!(Key::BackTab.to_string(), "BackTab");
}
#[test]
fn display_backspace() {
assert_eq!(Key::Backspace.to_string(), "Backspace");
}
#[test]
fn display_delete() {
assert_eq!(Key::Delete.to_string(), "Delete");
}
#[test]
fn display_home() {
assert_eq!(Key::Home.to_string(), "Home");
}
#[test]
fn display_end() {
assert_eq!(Key::End.to_string(), "End");
}
#[test]
fn display_page_up() {
assert_eq!(Key::PageUp.to_string(), "PageUp");
}
#[test]
fn display_page_down() {
assert_eq!(Key::PageDown.to_string(), "PageDown");
}
#[test]
fn display_f_key() {
assert_eq!(Key::F(12).to_string(), "F12");
}
#[test]
fn key_clone_eq() {
assert_eq!(Key::Enter.clone(), Key::Enter);
}
#[test]
fn key_ne() {
assert_ne!(Key::Enter, Key::Escape);
}
#[test]
fn key_hash() {
use std::collections::HashSet;
let mut s = HashSet::new();
s.insert(Key::Char('a'));
assert!(s.contains(&Key::Char('a')));
assert!(!s.contains(&Key::Char('b')));
}
}