inquire/input/
action.rs

1use crate::{
2    ui::{Key, KeyModifiers},
3    InnerAction,
4};
5
6use super::{LineDirection, Magnitude};
7
8/// Set of actions for a text input handler.
9#[derive(Copy, Clone, Debug, PartialEq, Eq)]
10pub enum InputAction {
11    /// Deletes a substring of the input according to the magnitude and the
12    /// direction to delete.
13    Delete(Magnitude, LineDirection),
14    /// Moves the cursor according to the magnitude and the direction to move.
15    MoveCursor(Magnitude, LineDirection),
16    /// Writes a character to the content, according to the current cursor
17    /// position.
18    Write(char),
19}
20
21impl InnerAction for InputAction {
22    type Config = ();
23
24    fn from_key(key: Key, _config: &()) -> Option<Self>
25    where
26        Self: Sized,
27    {
28        let action = match key {
29            Key::Backspace => Self::Delete(Magnitude::Char, LineDirection::Left),
30            Key::Char('h', m) if m.contains(KeyModifiers::CONTROL) => {
31                // Ctrl+Backspace is tricky, we don't want to handle a Ctrl+H
32                // but also don't want ctrl+h to simply write h.
33                // Let's catch this combination and ignore it.
34                return None;
35            }
36
37            Key::Delete(m) if m.contains(KeyModifiers::CONTROL) => {
38                Self::Delete(Magnitude::Word, LineDirection::Right)
39            }
40            Key::Delete(_) => Self::Delete(Magnitude::Char, LineDirection::Right),
41
42            Key::Home => Self::MoveCursor(Magnitude::Line, LineDirection::Left),
43            Key::Left(m) if m.contains(KeyModifiers::CONTROL) => {
44                Self::MoveCursor(Magnitude::Word, LineDirection::Left)
45            }
46            Key::Left(_) => Self::MoveCursor(Magnitude::Char, LineDirection::Left),
47
48            Key::End => Self::MoveCursor(Magnitude::Line, LineDirection::Right),
49            Key::Right(m) if m.contains(KeyModifiers::CONTROL) => {
50                Self::MoveCursor(Magnitude::Word, LineDirection::Right)
51            }
52            Key::Right(_) => Self::MoveCursor(Magnitude::Char, LineDirection::Right),
53
54            Key::Char(c, _) => Self::Write(c),
55            _ => return None,
56        };
57
58        Some(action)
59    }
60}
61
62#[cfg(test)]
63mod test {
64    use super::*;
65
66    #[test]
67    fn backspace_results_in_delete_char_left() {
68        assert_eq!(
69            InputAction::from_key(Key::Backspace, &()),
70            Some(InputAction::Delete(Magnitude::Char, LineDirection::Left))
71        );
72    }
73
74    #[test]
75    fn delete_results_in_delete_char_right() {
76        assert_eq!(
77            InputAction::from_key(Key::Delete(KeyModifiers::NONE), &()),
78            Some(InputAction::Delete(Magnitude::Char, LineDirection::Right))
79        );
80    }
81
82    #[test]
83    fn ctrl_delete_results_in_delete_word_right() {
84        assert_eq!(
85            InputAction::from_key(Key::Delete(KeyModifiers::CONTROL), &()),
86            Some(InputAction::Delete(Magnitude::Word, LineDirection::Right))
87        );
88    }
89
90    #[test]
91    fn ctrl_backspace_does_nothing() {
92        // Ctrl+Backspace is tricky, we don't want to handle a Ctrl+H
93        // but also don't want ctrl+h to simply write h.
94        // Let's catch this combination and ignore it.
95        assert_eq!(
96            InputAction::from_key(Key::Char('h', KeyModifiers::CONTROL), &()),
97            None
98        );
99    }
100
101    #[test]
102    fn horizontal_arrows_results_in_move_cursor_char() {
103        assert_eq!(
104            InputAction::from_key(Key::Left(KeyModifiers::NONE), &()),
105            Some(InputAction::MoveCursor(
106                Magnitude::Char,
107                LineDirection::Left
108            ))
109        );
110        assert_eq!(
111            InputAction::from_key(Key::Right(KeyModifiers::NONE), &()),
112            Some(InputAction::MoveCursor(
113                Magnitude::Char,
114                LineDirection::Right
115            ))
116        );
117    }
118
119    #[test]
120    fn vertical_arrows_do_nothing() {
121        assert_eq!(
122            InputAction::from_key(Key::Up(KeyModifiers::NONE), &()),
123            None
124        );
125        assert_eq!(
126            InputAction::from_key(Key::Down(KeyModifiers::NONE), &()),
127            None
128        );
129    }
130
131    #[test]
132    fn home_moves_to_beginning_of_line() {
133        assert_eq!(
134            InputAction::from_key(Key::Home, &()),
135            Some(InputAction::MoveCursor(
136                Magnitude::Line,
137                LineDirection::Left
138            ))
139        );
140    }
141
142    #[test]
143    fn end_moves_to_end_of_line() {
144        assert_eq!(
145            InputAction::from_key(Key::End, &()),
146            Some(InputAction::MoveCursor(
147                Magnitude::Line,
148                LineDirection::Right
149            ))
150        );
151    }
152
153    #[test]
154    fn arrows_with_ctrl_move_by_word() {
155        assert_eq!(
156            InputAction::from_key(Key::Left(KeyModifiers::CONTROL), &()),
157            Some(InputAction::MoveCursor(
158                Magnitude::Word,
159                LineDirection::Left
160            ))
161        );
162        assert_eq!(
163            InputAction::from_key(Key::Right(KeyModifiers::CONTROL), &()),
164            Some(InputAction::MoveCursor(
165                Magnitude::Word,
166                LineDirection::Right
167            ))
168        );
169    }
170
171    #[test]
172    fn chars_generate_write_actions() {
173        assert_eq!(
174            InputAction::from_key(Key::Char('a', KeyModifiers::NONE), &()),
175            Some(InputAction::Write('a'))
176        );
177        assert_eq!(
178            InputAction::from_key(Key::Char('a', KeyModifiers::SHIFT), &()),
179            Some(InputAction::Write('a'))
180        );
181        assert_eq!(
182            InputAction::from_key(Key::Char('∑', KeyModifiers::NONE), &()),
183            Some(InputAction::Write('∑'))
184        );
185        assert_eq!(
186            InputAction::from_key(Key::Char('ã', KeyModifiers::SHIFT), &()),
187            Some(InputAction::Write('ã'))
188        );
189        assert_eq!(
190            InputAction::from_key(Key::Char('❤', KeyModifiers::SHIFT), &()),
191            Some(InputAction::Write('❤'))
192        );
193        assert_eq!(
194            InputAction::from_key(Key::Char('ç', KeyModifiers::SHIFT), &()),
195            Some(InputAction::Write('ç'))
196        );
197        assert_eq!(
198            InputAction::from_key(Key::Char('ñ', KeyModifiers::SHIFT), &()),
199            Some(InputAction::Write('ñ'))
200        );
201    }
202
203    #[test]
204    fn page_up_and_down_do_nothing() {
205        assert_eq!(
206            InputAction::from_key(Key::PageUp(KeyModifiers::NONE), &()),
207            None
208        );
209        assert_eq!(
210            InputAction::from_key(Key::PageDown(KeyModifiers::NONE), &()),
211            None
212        );
213    }
214}