1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use {
crossterm::event::{KeyCode::*, KeyEvent, KeyModifiers},
std::fmt,
};
#[derive(Debug)]
pub struct ParseKeyError {
pub raw: String,
}
impl ParseKeyError {
pub fn new<S: Into<String>>(s: S) -> Self {
Self { raw: s.into() }
}
}
impl fmt::Display for ParseKeyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?} can't be parsed as a key", self.raw)
}
}
impl std::error::Error for ParseKeyError {}
pub fn parse(raw: &str) -> Result<KeyEvent, ParseKeyError> {
let tokens: Vec<&str> = raw.split('-').collect();
let last = tokens[tokens.len() - 1].to_ascii_lowercase();
let mut code = match last.as_ref() {
"esc" => Esc,
"enter" => Enter,
"left" => Left,
"right" => Right,
"up" => Up,
"down" => Down,
"home" => Home,
"end" => End,
"pageup" => PageUp,
"pagedown" => PageDown,
"backtab" => BackTab,
"backspace" => Backspace,
"del" => Delete,
"delete" => Delete,
"insert" => Insert,
"ins" => Insert,
"f1" => F(1),
"f2" => F(2),
"f3" => F(3),
"f4" => F(4),
"f5" => F(5),
"f6" => F(6),
"f7" => F(7),
"f8" => F(8),
"f9" => F(9),
"f10" => F(10),
"f11" => F(11),
"f12" => F(12),
"space" => Char(' '),
"tab" => Tab,
c if c.len() == 1 => Char(c.chars().next().unwrap()),
_ => {
return Err(ParseKeyError::new(raw));
}
};
let mut modifiers = KeyModifiers::empty();
if code == BackTab {
modifiers.insert(KeyModifiers::SHIFT);
}
for token in tokens.iter().take(tokens.len() - 1) {
match token.to_ascii_lowercase().as_ref() {
"ctrl" => {
modifiers.insert(KeyModifiers::CONTROL);
}
"alt" => {
modifiers.insert(KeyModifiers::ALT);
}
"shift" => {
modifiers.insert(KeyModifiers::SHIFT);
if let Char(c) = code {
if c.is_ascii_lowercase() {
code = Char(c.to_ascii_uppercase());
}
}
}
_ => {
return Err(ParseKeyError::new(raw));
}
}
}
Ok(KeyEvent { code, modifiers })
}
#[test]
fn check_key_parsing() {
use crate::*;
fn check_ok(raw: &str, key: KeyEvent) {
let parsed = parse(raw);
assert!(parsed.is_ok(), "failed to parse {:?} as key", raw);
assert_eq!(parsed.unwrap(), key);
}
check_ok("left", key!(left));
check_ok("RIGHT", key!(right));
check_ok("Home", key!(HOME));
check_ok("f1", KeyEvent::from(F(1)));
check_ok("F2", KeyEvent::from(F(2)));
check_ok("Enter", KeyEvent::from(Enter));
check_ok("alt-enter", KeyEvent::new(Enter, KeyModifiers::ALT));
check_ok("insert", KeyEvent::from(Insert));
check_ok("ctrl-q", KeyEvent::new(Char('q'), KeyModifiers::CONTROL));
check_ok("shift-q", KeyEvent::new(Char('Q'), KeyModifiers::SHIFT));
check_ok("ctrl-Q", KeyEvent::new(Char('q'), KeyModifiers::CONTROL));
check_ok("shift-Q", KeyEvent::new(Char('Q'), KeyModifiers::SHIFT));
}