tui-pages 0.7.0

Coordination runtime for keyboard-driven, page-based TUI applications: input sequences, command resolution, focus, navigation, buffers, and panes.
Documentation
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct KeyChord {
    pub code: KeyCode,
    pub modifiers: KeyModifiers,
}

impl KeyChord {
    pub fn new(code: KeyCode, modifiers: KeyModifiers) -> Self {
        Self { code, modifiers }
    }

    pub fn from_event(event: &KeyEvent) -> Self {
        let mut modifiers = event.modifiers;
        // SHIFT is encoded in the character itself (':' vs ';', 'A' vs 'a'),
        // so a binding like `":"` should match an event of `Char(':') + SHIFT`.
        // We keep SHIFT only when combined with another modifier (e.g. Ctrl+Shift+S).
        if matches!(event.code, KeyCode::Char(_)) && modifiers == KeyModifiers::SHIFT {
            modifiers = KeyModifiers::empty();
        }
        if event.code == KeyCode::BackTab {
            modifiers -= KeyModifiers::SHIFT;
        }
        Self {
            code: event.code,
            modifiers,
        }
    }

    pub fn display_string(&self) -> String {
        let mut out = String::new();
        if self.modifiers.contains(KeyModifiers::CONTROL) {
            out.push_str("Ctrl+");
        }
        if self.modifiers.contains(KeyModifiers::ALT) {
            out.push_str("Alt+");
        }
        if self.modifiers.contains(KeyModifiers::SHIFT) {
            out.push_str("Shift+");
        }

        match self.code {
            KeyCode::Char(c) => out.push(c),
            KeyCode::Enter => out.push_str("Enter"),
            KeyCode::Tab => out.push_str("Tab"),
            KeyCode::BackTab => out.push_str("BackTab"),
            KeyCode::Backspace => out.push_str("Backspace"),
            KeyCode::Esc => out.push_str("Esc"),
            KeyCode::Up => out.push_str("Up"),
            KeyCode::Down => out.push_str("Down"),
            KeyCode::Left => out.push_str("Left"),
            KeyCode::Right => out.push_str("Right"),
            other => out.push_str(&format!("{other:?}")),
        }

        out
    }
}