rskit_cli/prompt/key.rs
1//! The keystroke vocabulary a key-driven [`Terminal`](crate::prompt::terminal::Terminal) yields.
2//!
3//! [`Key`] is rskit's own, minimal key abstraction so no third-party terminal
4//! type (crossterm, termion, …) leaks into the public prompt surface. The rich
5//! terminal maps platform events onto it; the scripted terminal feeds canned
6//! sequences of it in tests.
7
8/// A single decoded keystroke from an interactive terminal.
9///
10/// Only the keys the prompt widgets act on are modelled; anything else decodes
11/// to [`Key::Unknown`] so callers can ignore it without a catch-all on a
12/// platform enum.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14#[non_exhaustive]
15pub enum Key {
16 /// Confirm the current answer (Enter / Return).
17 Enter,
18 /// Space bar — toggles the focused item in multi-select, or inserts a
19 /// literal space in text entry.
20 Space,
21 /// Delete the character before the cursor (Backspace).
22 Backspace,
23 /// Abandon the prompt (Escape).
24 Escape,
25 /// Advance focus (Tab).
26 Tab,
27 /// Move focus up / to the previous item.
28 Up,
29 /// Move focus down / to the next item.
30 Down,
31 /// Move the text cursor left.
32 Left,
33 /// Move the text cursor right.
34 Right,
35 /// Jump to the first item / start of line.
36 Home,
37 /// Jump to the last item / end of line.
38 End,
39 /// A printable character was typed.
40 Char(char),
41 /// A cancellation request (Ctrl+C / Ctrl+D).
42 Interrupt,
43 /// A key with no prompt-relevant meaning.
44 Unknown,
45}
46
47impl Key {
48 /// Whether this key represents a cancellation request.
49 #[must_use]
50 pub const fn is_interrupt(self) -> bool {
51 matches!(self, Self::Interrupt)
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::Key;
58
59 #[test]
60 fn only_interrupt_reports_as_interrupt() {
61 assert!(Key::Interrupt.is_interrupt());
62 for key in [
63 Key::Enter,
64 Key::Escape,
65 Key::Char('a'),
66 Key::Space,
67 Key::Unknown,
68 ] {
69 assert!(!key.is_interrupt());
70 }
71 }
72}