tui: keybinds work?
Some checks are pending
/ build (push) Waiting to run

This commit is contained in:
🪞👃🪞 2025-08-10 01:14:26 +03:00
parent b52c1f5828
commit 24ac52d807
10 changed files with 238 additions and 203 deletions

View file

@ -17,23 +17,6 @@ impl Input for TuiIn {
fn is_done (&self) -> bool { self.exited.fetch_and(true, Relaxed) }
fn done (&self) { self.exited.store(true, Relaxed); }
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
pub struct TuiEvent(Event);
impl Ord for TuiEvent {
fn cmp (&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other) .unwrap_or_else(||format!("{:?}", self).cmp(&format!("{other:?}"))) // FIXME perf
}
}
impl From<Event> for TuiEvent {
fn from (event: Event) -> Self {
Self(event)
}
}
impl From<Arc<str>> for TuiEvent {
fn from (x: Arc<str>) -> Self {
TuiEvent(TuiKey::new(x.as_ref()).build().unwrap_or_else(||panic!("invalid key: {x}")))
}
}
impl TuiIn {
/// Spawn the input thread.
pub fn run_input <T: Handle<TuiIn> + Send + Sync + 'static> (
@ -60,7 +43,7 @@ impl TuiIn {
},
_ => {
let exited = exited.clone();
let event = event.into();
let event = TuiEvent::from_crossterm(event);
if let Err(e) = state.write().unwrap().handle(&TuiIn { exited, event }) {
panic!("{e}")
}
@ -70,105 +53,3 @@ impl TuiIn {
})
}
}
//#[cfg(feature = "dsl")]
//impl DslInput for TuiIn {
//fn matches_dsl (&self, token: &str) -> bool {
//if let Some(event) = TuiKey::new(token).build() {
//&event == self.event()
//} else {
//false
//}
//}
//}
pub struct TuiKey {
valid: bool,
key: Option<KeyCode>,
mods: KeyModifiers,
}
impl TuiKey {
pub 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..])
}
}
pub fn build (self) -> Option<Event> {
if self.valid && self.key.is_some() {
Some(Event::Key(KeyEvent::new(self.key.unwrap(), self.mods)))
} else {
None
}
}
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}")))
}
}
}
self
}
fn named_key (token: &str) -> Option<KeyCode> {
use KeyCode::*;
Some(match token {
"up" => Up,
"down" => Down,
"left" => Left,
"right" => Right,
"esc" | "escape" => Esc,
"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('`'),
"lt" => Char('<'),
"gt" => Char('>'),
"cbopen" | "openbrace" => Char('{'),
"cbclose" | "closebrace" => Char('}'),
"bropen" | "openbracket" => Char('['),
"brclose" | "closebracket" => Char(']'),
"pgup" | "pageup" => PageUp,
"pgdn" | "pagedown" => PageDown,
"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),
_ => return None,
})
}
}