1use bitflags::bitflags;
2use std::{
3 fmt::{self, Display, Formatter},
4 hash::Hash,
5 str::FromStr,
6};
7use winnow::{
8 ascii::{multispace0, till_line_ending},
9 combinator::{alt, cut_err, delimited, fail, opt, preceded, repeat, terminated},
10 error::StrContext,
11 prelude::*,
12 token::one_of,
13};
14
15#[cfg(feature = "arbitrary")]
16use arbitrary::Arbitrary;
17
18#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
19#[derive(Clone, Debug)]
20pub struct Keys<K = Vec<Key>>(pub K);
21
22impl FromStr for Keys {
23 type Err = anyhow::Error;
24 fn from_str(s: &str) -> Result<Self, Self::Err> {
25 keys.parse(s).map_err(|e| anyhow::format_err!("{e}"))
26 }
27}
28
29impl<K: AsRef<[Key]>> Display for Keys<K> {
30 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
31 for key in self.0.as_ref() {
32 write!(f, "{key}")?;
33 }
34 Ok(())
35 }
36}
37
38fn comment(input: &mut &str) -> ModalResult<()> {
39 ('#', till_line_ending).void().parse_next(input)
40}
41
42fn not_key(input: &mut &str) -> ModalResult<()> {
43 multispace0.parse_next(input)?;
44 while comment.parse_next(input).is_ok() {
45 multispace0.parse_next(input)?;
46 }
47 Ok(())
48}
49
50fn keys(input: &mut &str) -> ModalResult<Keys> {
51 not_key.parse_next(input)?;
52 repeat(0.., terminated(key, not_key))
53 .map(Keys)
54 .parse_next(input)
55}
56
57#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
58#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
59pub struct Key {
60 pub modifiers: KeyModifiers,
61 pub code: KeyCode,
62}
63
64impl Key {
65 pub fn normalize(&mut self) {
66 if !self.modifiers.contains(KeyModifiers::SHIFT) {
67 return;
68 }
69 if let KeyCode::Char(c @ (b'a'..=b'z' | b'A'..=b'Z')) = self.code {
70 self.modifiers.remove(KeyModifiers::SHIFT);
71 self.code = KeyCode::Char(c.to_ascii_uppercase());
72 }
73 }
74}
75
76impl FromStr for Key {
77 type Err = anyhow::Error;
78 fn from_str(s: &str) -> Result<Self, Self::Err> {
79 key.parse(s).map_err(|e| anyhow::format_err!("{e}"))
80 }
81}
82
83impl Display for Key {
84 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
85 if self.modifiers.is_empty()
86 && let KeyCode::Char(_) = self.code
87 {
88 write!(f, "{}", self.code)?;
89 } else {
90 write!(f, "<{}{}>", self.modifiers, self.code)?;
91 }
92 Ok(())
93 }
94}
95
96fn key(input: &mut &str) -> ModalResult<Key> {
97 alt((key_wrapped, key_bare_unmodified)).parse_next(input)
98}
99
100fn key_wrapped(input: &mut &str) -> ModalResult<Key> {
101 let k = |input: &mut &str| {
102 let modifiers = key_modifiers
103 .context(StrContext::Label("key modifiers"))
104 .parse_next(input)?;
105 let allow_bare = !modifiers.is_empty();
106 let code = alt((key_code_wrapped, key_code_bare.verify(|_| allow_bare)))
107 .context(StrContext::Label("key code"))
108 .parse_next(input)?;
109 Ok(Key { modifiers, code })
110 };
111 delimited("<", cut_err(k), ">").parse_next(input)
112}
113
114fn key_bare_unmodified(input: &mut &str) -> ModalResult<Key> {
115 let modifiers = KeyModifiers::empty();
116 let code = key_code_bare.parse_next(input)?;
117 Ok(Key { modifiers, code })
118}
119
120bitflags! {
121 #[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
122 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
123 pub struct KeyModifiers: u8 {
124 const CONTROL = 1 << 0;
125 const ALT = 1 << 1;
126 const SHIFT = 1 << 2;
127 }
128}
129
130impl FromStr for KeyModifiers {
131 type Err = anyhow::Error;
132 fn from_str(s: &str) -> Result<Self, Self::Err> {
133 key_modifiers
134 .parse(s)
135 .map_err(|e| anyhow::format_err!("{e}"))
136 }
137}
138
139impl Display for KeyModifiers {
140 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
141 if self.contains(Self::CONTROL) {
142 write!(f, "c-")?;
143 }
144 if self.contains(Self::ALT) {
145 write!(f, "a-")?;
146 }
147 if self.contains(Self::SHIFT) {
148 write!(f, "s-")?;
149 }
150 Ok(())
151 }
152}
153
154fn key_modifiers(input: &mut &str) -> ModalResult<KeyModifiers> {
155 let mut modifiers = KeyModifiers::empty();
156 while !modifiers.is_all() {
157 let Some(modifier) = opt(alt((
158 "c-".value(KeyModifiers::CONTROL),
159 "a-".value(KeyModifiers::ALT),
160 "s-".value(KeyModifiers::SHIFT),
161 )))
162 .parse_next(input)?
163 else {
164 break;
165 };
166 if modifiers.contains(modifier) {
167 return fail.parse_next(input);
168 }
169 modifiers.insert(modifier);
170 }
171 Ok(modifiers)
172}
173
174#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
175pub enum KeyCode {
176 Backspace,
177 Delete,
178 Return,
179 Left,
180 Right,
181 Up,
182 Down,
183 Tab,
184 Escape,
185 Char(u8),
188}
189
190#[cfg(feature = "arbitrary")]
191impl<'a> Arbitrary<'a> for KeyCode {
192 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
193 if u.ratio(8, 10)? {
194 loop {
195 let c = u.int_in_range(b' '..=b'~')?;
196 if !b" #<>\\".contains(&c) {
197 return Ok(Self::Char(c));
198 }
199 }
200 }
201 Ok(*u.choose(&[
202 Self::Backspace,
203 Self::Delete,
204 Self::Return,
205 Self::Left,
206 Self::Right,
207 Self::Up,
208 Self::Down,
209 Self::Tab,
210 Self::Escape,
211 ])?)
212 }
213}
214
215impl FromStr for KeyCode {
216 type Err = anyhow::Error;
217 fn from_str(s: &str) -> Result<Self, Self::Err> {
218 key_code.parse(s).map_err(|e| anyhow::format_err!("{e}"))
219 }
220}
221
222impl Display for KeyCode {
223 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
224 match self {
225 Self::Backspace => write!(f, "bs")?,
226 Self::Delete => write!(f, "del")?,
227 Self::Return => write!(f, "ret")?,
228 Self::Left => write!(f, "left")?,
229 Self::Right => write!(f, "right")?,
230 Self::Up => write!(f, "up")?,
231 Self::Down => write!(f, "down")?,
232 Self::Tab => write!(f, "tab")?,
233 Self::Escape => write!(f, "esc")?,
234 Self::Char(b' ') => write!(f, "\\ ")?,
235 Self::Char(b'#') => write!(f, "\\#")?,
236 Self::Char(b'<') => write!(f, "\\<")?,
237 Self::Char(b'>') => write!(f, "\\>")?,
238 Self::Char(b'\\') => write!(f, "\\\\")?,
239 Self::Char(b'\t') => write!(f, "\\t")?,
240 Self::Char(b'\n') => write!(f, "\\n")?,
241 Self::Char(b'\r') => write!(f, "\\r")?,
242 Self::Char(c) => write!(f, "{}", char::from(*c))?,
243 }
244 Ok(())
245 }
246}
247
248fn key_code(input: &mut &str) -> ModalResult<KeyCode> {
249 alt((key_code_wrapped, key_code_bare)).parse_next(input)
250}
251
252fn key_code_wrapped(input: &mut &str) -> ModalResult<KeyCode> {
253 alt((
254 "bs".value(KeyCode::Backspace),
255 "del".value(KeyCode::Delete),
256 "ret".value(KeyCode::Return),
257 "left".value(KeyCode::Left),
258 "right".value(KeyCode::Right),
259 "up".value(KeyCode::Up),
260 "down".value(KeyCode::Down),
261 "tab".value(KeyCode::Tab),
262 "esc".value(KeyCode::Escape),
263 ))
264 .parse_next(input)
265}
266
267fn key_code_bare(input: &mut &str) -> ModalResult<KeyCode> {
268 alt((
269 one_of(b' '..=b'~')
270 .verify(|c| !" #<>\\".contains(*c))
271 .map(|c| KeyCode::Char(u8::try_from(c).expect("Only parsing ASCII"))),
272 key_code_escaped,
273 ))
274 .parse_next(input)
275}
276
277fn key_code_escaped(input: &mut &str) -> ModalResult<KeyCode> {
278 preceded(
279 '\\',
280 cut_err(alt((
281 ' '.value(KeyCode::Char(b' ')),
282 '#'.value(KeyCode::Char(b'#')),
283 '<'.value(KeyCode::Char(b'<')),
284 '>'.value(KeyCode::Char(b'>')),
285 '\\'.value(KeyCode::Char(b'\\')),
286 't'.value(KeyCode::Char(b'\t')),
287 'n'.value(KeyCode::Char(b'\n')),
288 'r'.value(KeyCode::Char(b'\r')),
289 ))),
290 )
291 .parse_next(input)
292}
293
294#[must_use]
295pub fn is(x: &Key, y: &str) -> bool {
296 let mut x = *x;
297 let mut y = y.parse::<Key>().unwrap();
298 x.normalize();
299 y.normalize();
300 x == y
301}
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306
307 #[test]
308 fn random() {
309 let input = "
310 # comment
311 # comment
312 abc a b c # comment
313
314 \\t \\n <s-\\n> <c-->
315
316 # comment
317 <c-a-del> <a-a> <tab> <s-tab> <a-esc>
318 ";
319 let expected = "abcabc\\t\\n<s-\\n><c--><c-a-del><a-a><tab><s-tab><a-esc>";
320 let actual = input.parse::<Keys>().unwrap().to_string();
321 assert_eq!(expected, actual);
322 }
323
324 #[test]
325 fn weird() {
326 assert_eq!("<c-->".parse::<Key>().unwrap().to_string(), "<c-->");
327 assert_eq!("<c-\\>>".parse::<Key>().unwrap().to_string(), "<c-\\>>");
328 }
329
330 #[test]
331 fn escaped() {
332 assert_eq!("\\n".parse::<Key>().unwrap().to_string(), "\\n");
333 assert_eq!("\\t".parse::<Key>().unwrap().to_string(), "\\t");
334 assert_eq!("\\\\".parse::<Key>().unwrap().to_string(), "\\\\");
335 }
336
337 #[test]
338 fn no_wrapped_bare() {
339 assert_eq!("a".parse::<Key>().unwrap().to_string(), "a");
340 assert!("<a>".parse::<Key>().is_err());
341 }
342
343 #[test]
344 fn modifier_ordering() {
345 assert_eq!("<c-a-s-a>".parse::<Key>().unwrap().to_string(), "<c-a-s-a>");
346 assert_eq!("<s-c-a>".parse::<Key>().unwrap().to_string(), "<c-s-a>");
347 assert_eq!("<s-c-a-a>".parse::<Key>().unwrap().to_string(), "<c-a-s-a>");
348 assert_eq!("<a-s-c-a>".parse::<Key>().unwrap().to_string(), "<c-a-s-a>");
349 }
350
351 #[test]
352 fn no_duplicate_modifiers() {
353 assert!("<c-c-a>".parse::<Key>().is_err());
354 assert!("<s-c-a-c-a>".parse::<Key>().is_err());
355 }
356
357 #[test]
358 fn key_roundtrip() {
359 let mut codes: Vec<KeyCode> = (b' '..=b'~')
360 .filter(|c| !b" #<>\\".contains(c))
361 .map(KeyCode::Char)
362 .collect();
363 codes.extend([
364 KeyCode::Backspace,
365 KeyCode::Delete,
366 KeyCode::Return,
367 KeyCode::Left,
368 KeyCode::Right,
369 KeyCode::Up,
370 KeyCode::Down,
371 KeyCode::Tab,
372 KeyCode::Escape,
373 ]);
374 for bits in 0..=KeyModifiers::all().bits() {
375 let modifiers = KeyModifiers::from_bits_truncate(bits);
376 for &code in &codes {
377 let key = Key { modifiers, code };
378 match key.to_string().parse::<Key>() {
379 Ok(parsed_key) => assert_eq!(key, parsed_key),
380 Err(e) => panic!("Failed to parse `{key:?}` printed as `{key}`:\n{e}"),
381 }
382 }
383 }
384 }
385
386 #[test]
387 fn normalize() {
388 let cases = [
389 (KeyModifiers::SHIFT, b'a', KeyModifiers::empty(), b'A'),
390 (KeyModifiers::SHIFT, b'Z', KeyModifiers::empty(), b'Z'),
391 (KeyModifiers::empty(), b'a', KeyModifiers::empty(), b'a'),
392 (KeyModifiers::SHIFT, b'1', KeyModifiers::SHIFT, b'1'),
393 ];
394
395 for (input_modifiers, input_code, expected_modifiers, expected_code) in cases {
396 let mut key = Key {
397 modifiers: input_modifiers,
398 code: KeyCode::Char(input_code),
399 };
400 key.normalize();
401 assert_eq!(key.modifiers, expected_modifiers);
402 assert_eq!(key.code, KeyCode::Char(expected_code));
403 }
404 }
405}