mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
a random KeyMatcher appears
This commit is contained in:
parent
12faadef44
commit
44201ebf76
6 changed files with 152 additions and 80 deletions
|
|
@ -2,50 +2,134 @@ use crate::*;
|
|||
|
||||
impl EdnInput for TuiIn {
|
||||
fn matches_edn (&self, token: &str) -> bool {
|
||||
if let Some(event) = parse_key_spec(token.to_string(), KeyModifiers::NONE) {
|
||||
if let Some(event) = KeyMatcher::new(token).build() {
|
||||
&event == self.event()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn get_event <S: AsRef<str>> (item: &EdnItem<S>) -> Option<Event> {
|
||||
match item { EdnItem::Sym(s) => parse_key_spec(s.as_ref().to_string(), KeyModifiers::NONE), _ => None }
|
||||
match item { EdnItem::Sym(s) => KeyMatcher::new(s).build(), _ => None }
|
||||
}
|
||||
}
|
||||
fn parse_key_spec (spec: String, mut mods: KeyModifiers) -> Option<Event> {
|
||||
Some(Event::Key(match spec.as_str() {
|
||||
":enter" | ":return" => KeyEvent::new(KeyCode::Enter, mods),
|
||||
":delete" | ":del" => KeyEvent::new(KeyCode::Enter, mods),
|
||||
|
||||
":comma" => KeyEvent::new(KeyCode::Char(','), mods),
|
||||
":period" => KeyEvent::new(KeyCode::Char('.'), mods),
|
||||
|
||||
":plus" => KeyEvent::new(KeyCode::Char('+'), mods),
|
||||
":underscore" => KeyEvent::new(KeyCode::Char('_'), mods),
|
||||
|
||||
":up" => KeyEvent::new(KeyCode::Up, mods),
|
||||
":down" => KeyEvent::new(KeyCode::Down, mods),
|
||||
":left" => KeyEvent::new(KeyCode::Left, mods),
|
||||
":right" => KeyEvent::new(KeyCode::Right, mods),
|
||||
|
||||
_ => {
|
||||
let chars = spec.chars().collect::<Vec<_>>();
|
||||
match chars.as_slice() {
|
||||
[':', c] => KeyEvent::new(KeyCode::Char(*c), mods),
|
||||
[':', c @ ..] => {
|
||||
let mut splits = c.split(|c|*c=='-');
|
||||
while let Some(split) = splits.next() {
|
||||
match split {
|
||||
['c','t','r','l'] => mods |= KeyModifiers::CONTROL,
|
||||
['a','l','t'] => mods |= KeyModifiers::ALT,
|
||||
['s','h','i','f','t'] => mods |= KeyModifiers::SHIFT,
|
||||
_ => return parse_key_spec(split.iter().collect(), mods)
|
||||
}
|
||||
}
|
||||
panic!("invalid key event {spec:?}")
|
||||
struct KeyMatcher {
|
||||
valid: bool,
|
||||
key: Option<KeyCode>,
|
||||
mods: KeyModifiers,
|
||||
}
|
||||
impl KeyMatcher {
|
||||
fn new (token: impl AsRef<str>) -> Self {
|
||||
let token = token.as_ref();
|
||||
if token.len() < 2 {
|
||||
Self { valid: false, key: None, mods: KeyModifiers::NONE }
|
||||
} else if token.chars().next() != Some(':') {
|
||||
Self { valid: false, key: None, mods: KeyModifiers::NONE }
|
||||
} else {
|
||||
Self { valid: true, key: None, mods: KeyModifiers::NONE }.next(&token[1..])
|
||||
}
|
||||
}
|
||||
fn next (mut self, token: &str) -> Self {
|
||||
let mut tokens = token.split('-').peekable();
|
||||
while let Some(token) = tokens.next() {
|
||||
if tokens.peek().is_some() {
|
||||
match token {
|
||||
"ctrl" | "Ctrl" | "c" | "C" => self.mods |= KeyModifiers::CONTROL,
|
||||
"alt" | "Alt" | "m" | "M" => self.mods |= KeyModifiers::ALT,
|
||||
"shift" | "Shift" | "s" | "S" => {
|
||||
self.mods |= KeyModifiers::SHIFT;
|
||||
// + TODO normalize character case, BackTab, etc.
|
||||
},
|
||||
_ => panic!("unknown modifier {token}"),
|
||||
}
|
||||
} else {
|
||||
self.key = if token.len() == 1 {
|
||||
Some(KeyCode::Char(token.chars().next().unwrap()))
|
||||
} else {
|
||||
Some(Self::named_key(token).unwrap_or_else(||panic!("unknown character {token}")))
|
||||
}
|
||||
_ => panic!("invalid key event {spec:?}")
|
||||
}
|
||||
}
|
||||
}))
|
||||
self
|
||||
}
|
||||
fn named_key (token: &str) -> Option<KeyCode> {
|
||||
use KeyCode::*;
|
||||
Some(match token {
|
||||
"up" => Up,
|
||||
"down" => Down,
|
||||
"left" => Left,
|
||||
"right" => Right,
|
||||
"enter" | "return" => Enter,
|
||||
"delete" | "del" => Delete,
|
||||
"tab" => Tab,
|
||||
"space" => Char(' '),
|
||||
"comma" => Char(','),
|
||||
"period" => Char('.'),
|
||||
"plus" => Char('+'),
|
||||
"minus" | "dash" => Char('-'),
|
||||
"equal" | "equals" => Char('='),
|
||||
"underscore" => Char('_'),
|
||||
"backtick" => Char('`'),
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
fn build (self) -> Option<Event> {
|
||||
if self.valid && self.key.is_some() {
|
||||
Some(Event::Key(KeyEvent::new(self.key.unwrap(), self.mods)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] #[test] fn test_parse_key () {
|
||||
use KeyModifiers as Mods;
|
||||
let test = |x: &str, y|assert_eq!(KeyMatcher::new(x).build(), Some(Event::Key(y)));
|
||||
test(":x",
|
||||
KeyEvent::new(KeyCode::Char('x'), Mods::NONE));
|
||||
test(":ctrl-x",
|
||||
KeyEvent::new(KeyCode::Char('x'), Mods::CONTROL));
|
||||
test(":alt-x",
|
||||
KeyEvent::new(KeyCode::Char('x'), Mods::ALT));
|
||||
test(":shift-x",
|
||||
KeyEvent::new(KeyCode::Char('x'), Mods::SHIFT));
|
||||
test(":ctrl-alt-shift-x",
|
||||
KeyEvent::new(KeyCode::Char('x'), Mods::CONTROL | Mods::ALT | Mods::SHIFT ));
|
||||
}
|
||||
|
||||
//fn parse_key (spec: std::str::Chars<'_>, mut mods: KeyModifiers) -> Option<Event> {
|
||||
//Some(Event::Key(match spec.chars() {
|
||||
//":enter" | ":return" => KeyEvent::new(KeyCode::Enter, mods),
|
||||
//":delete" | ":del" => KeyEvent::new(KeyCode::Enter, mods),
|
||||
|
||||
//":comma" => KeyEvent::new(KeyCode::Char(','), mods),
|
||||
//":period" => KeyEvent::new(KeyCode::Char('.'), mods),
|
||||
|
||||
//":plus" => KeyEvent::new(KeyCode::Char('+'), mods),
|
||||
//":underscore" => KeyEvent::new(KeyCode::Char('_'), mods),
|
||||
|
||||
//":up" => KeyEvent::new(KeyCode::Up, mods),
|
||||
//":down" => KeyEvent::new(KeyCode::Down, mods),
|
||||
//":left" => KeyEvent::new(KeyCode::Left, mods),
|
||||
//":right" => KeyEvent::new(KeyCode::Right, mods),
|
||||
|
||||
//_ => {
|
||||
//let chars = spec.chars().collect::<Vec<_>>();
|
||||
//match chars.as_slice() {
|
||||
//[':', c] => KeyEvent::new(KeyCode::Char(*c), mods),
|
||||
//[':', c @ ..] => {
|
||||
//let mut splits = c.split(|c|*c=='-');
|
||||
//while let Some(split) = splits.next() {
|
||||
//match split {
|
||||
//['c','t','r','l'] => mods |= KeyModifiers::CONTROL,
|
||||
//['a','l','t'] => mods |= KeyModifiers::ALT,
|
||||
//['s','h','i','f','t'] => mods |= KeyModifiers::SHIFT,
|
||||
//_ => return parse_key(split.iter().collect(), mods)
|
||||
//}
|
||||
//}
|
||||
//panic!("invalid key event {spec:?}")
|
||||
//}
|
||||
//_ => panic!("invalid key event {spec:?}")
|
||||
//}
|
||||
//}
|
||||
//}))
|
||||
//}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue