pub trait Key: Clone + PartialEq + Eq + Send + Sync + 'static {
fn display(&self) -> String;
fn is_backspace(&self) -> bool;
fn from_char(_c: char) -> Option<Self>
where
Self: Sized,
{
None
}
fn from_special_name(_name: &str) -> Option<Self>
where
Self: Sized,
{
None
}
fn space() -> Self
where
Self: Sized;
}
pub fn parse_key_sequence<K: Key>(s: &str, leader: &K) -> Vec<K> {
let mut keys = Vec::new();
let mut chars = s.chars().peekable();
while let Some(c) = chars.next() {
if c == '<' {
let mut special = String::new();
while let Some(&next) = chars.peek() {
if next == '>' {
chars.next();
break;
}
special.push(chars.next().unwrap());
}
if special.eq_ignore_ascii_case("leader") {
keys.push(leader.clone());
continue;
}
if let Some(key) = K::from_special_name(&special) {
keys.push(key);
}
} else if let Some(key) = K::from_char(c) {
keys.push(key);
}
}
keys
}
#[cfg(test)]
mod tests {
use crossterm::event::{KeyCode, KeyModifiers};
use crate::parse_key_sequence;
fn leader() -> crossterm::event::KeyEvent {
crossterm::event::KeyEvent::new(KeyCode::Char('\\'), KeyModifiers::empty())
}
#[test]
fn lt_parses_to_literal_less_than() {
let keys = parse_key_sequence("<lt>", &leader());
assert_eq!(keys.len(), 1);
assert_eq!(keys[0].code, KeyCode::Char('<'));
assert_eq!(keys[0].modifiers, KeyModifiers::empty());
}
#[test]
fn gt_parses_to_literal_greater_than() {
let keys = parse_key_sequence("<gt>", &leader());
assert_eq!(keys.len(), 1);
assert_eq!(keys[0].code, KeyCode::Char('>'));
assert_eq!(keys[0].modifiers, KeyModifiers::empty());
}
#[test]
fn lt_and_gt_in_mixed_sequence() {
let keys = parse_key_sequence("a<lt>b<gt>c", &leader());
assert_eq!(keys.len(), 5);
assert_eq!(keys[0].code, KeyCode::Char('a'));
assert_eq!(keys[1].code, KeyCode::Char('<'));
assert_eq!(keys[2].code, KeyCode::Char('b'));
assert_eq!(keys[3].code, KeyCode::Char('>'));
assert_eq!(keys[4].code, KeyCode::Char('c'));
}
#[test]
fn consecutive_lt_gt_parses_to_angle_bracket_pair() {
let keys = parse_key_sequence("<lt><gt>", &leader());
assert_eq!(keys.len(), 2);
assert_eq!(keys[0].code, KeyCode::Char('<'));
assert_eq!(keys[1].code, KeyCode::Char('>'));
}
}