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