@@ -254,6 +254,43 @@ impl From<KeyEvent> for crossterm::event::KeyEvent {
257+pub fn parse_macro(keys_str: &str) -> anyhow::Result<Vec<KeyEvent>> {
258+ use anyhow::Context;
259+ let mut keys_res: anyhow::Result<_> = Ok(Vec::new());
261+ while let Ok(keys) = &mut keys_res {
262+ if i >= keys_str.len() {
265+ if !keys_str.is_char_boundary(i) {
270+ let s = &keys_str[i..];
272+ while !s.is_char_boundary(end_i) {
275+ let c = &s[..end_i];
277+ keys_res = Err(anyhow!("Unmatched '>'"));
278+ } else if c != "<" {
282+ match s.find('>').context("'>' expected") {
284+ keys.push(&s[1..end_i]);
287+ Err(err) => keys_res = Err(err),
291+ keys_res.and_then(|keys| keys.into_iter().map(str::parse).collect())
257#[cfg(test)]
294#[cfg(test)]
258mod test {
295mod test {
259 use super::*;
296 use super::*;
@@ -339,4 +376,120 @@ mod test {
339 assert!(str::parse::<KeyEvent>("123").is_err());
376 assert!(str::parse::<KeyEvent>("123").is_err());
340 assert!(str::parse::<KeyEvent>("S--").is_err());
377 assert!(str::parse::<KeyEvent>("S--").is_err());
381+ fn parsing_valid_macros() {
383+ parse_macro("xdo").ok(),
386+ code: KeyCode::Char('x'),
387+ modifiers: KeyModifiers::NONE,
390+ code: KeyCode::Char('d'),
391+ modifiers: KeyModifiers::NONE,
394+ code: KeyCode::Char('o'),
395+ modifiers: KeyModifiers::NONE,
401+ parse_macro("<C-w>v<C-w>h<C-o>xx<A-s>").ok(),
404+ code: KeyCode::Char('w'),
405+ modifiers: KeyModifiers::CONTROL,
408+ code: KeyCode::Char('v'),
409+ modifiers: KeyModifiers::NONE,
412+ code: KeyCode::Char('w'),
413+ modifiers: KeyModifiers::CONTROL,
416+ code: KeyCode::Char('h'),
417+ modifiers: KeyModifiers::NONE,
420+ code: KeyCode::Char('o'),
421+ modifiers: KeyModifiers::CONTROL,
424+ code: KeyCode::Char('x'),
425+ modifiers: KeyModifiers::NONE,
428+ code: KeyCode::Char('x'),
429+ modifiers: KeyModifiers::NONE,
432+ code: KeyCode::Char('s'),
433+ modifiers: KeyModifiers::ALT,
439+ parse_macro(":o foo.bar<ret>").ok(),
442+ code: KeyCode::Char(':'),
443+ modifiers: KeyModifiers::NONE,
446+ code: KeyCode::Char('o'),
447+ modifiers: KeyModifiers::NONE,
450+ code: KeyCode::Char(' '),
451+ modifiers: KeyModifiers::NONE,
454+ code: KeyCode::Char('f'),
455+ modifiers: KeyModifiers::NONE,
458+ code: KeyCode::Char('o'),
459+ modifiers: KeyModifiers::NONE,
462+ code: KeyCode::Char('o'),
463+ modifiers: KeyModifiers::NONE,
466+ code: KeyCode::Char('.'),
467+ modifiers: KeyModifiers::NONE,
470+ code: KeyCode::Char('b'),
471+ modifiers: KeyModifiers::NONE,
474+ code: KeyCode::Char('a'),
475+ modifiers: KeyModifiers::NONE,
478+ code: KeyCode::Char('r'),
479+ modifiers: KeyModifiers::NONE,
482+ code: KeyCode::Enter,
483+ modifiers: KeyModifiers::NONE,
490+ fn parsing_invalid_macros_fails() {
491+ assert!(parse_macro("abc<C-").is_err());
492+ assert!(parse_macro("abc>123").is_err());
493+ assert!(parse_macro("wd<foo>").is_err());