inquire/prompts/
action.rs1use std::fmt::Debug;
5
6use crate::ui::{Key, KeyModifiers};
7
8#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15pub enum Action<I>
16where
17 I: Copy + Clone + PartialEq + Eq,
18{
19 Submit,
21 Cancel,
23 Interrupt,
25 Inner(I),
27}
28
29impl<I> Action<I>
30where
31 I: Copy + Clone + PartialEq + Eq,
32{
33 pub fn from_key<C>(key: Key, config: &C) -> Option<Action<I>>
35 where
36 I: InnerAction<Config = C>,
37 {
38 match key {
39 Key::Enter
40 | Key::Char('\n', KeyModifiers::NONE)
41 | Key::Char('j', KeyModifiers::CONTROL)
42 if I::ESCAPE_POLICY == EscapePolicy::CancelOnEscape =>
43 {
44 Some(Action::Submit)
45 }
46 Key::Escape if I::ESCAPE_POLICY == EscapePolicy::SubmitOnEscape => Some(Action::Submit),
47 Key::Escape if I::ESCAPE_POLICY == EscapePolicy::CancelOnEscape => Some(Action::Cancel),
48 Key::Char('c', KeyModifiers::CONTROL) => Some(Action::Interrupt),
49 key => I::from_key(key, config).map(Action::Inner),
50 }
51 }
52}
53
54#[derive(Copy, Clone, Debug, PartialEq, Eq)]
60pub enum EscapePolicy {
61 CancelOnEscape,
63 SubmitOnEscape,
65 IgnoreEscape,
67}
68
69pub trait InnerAction
74where
75 Self: Sized + Copy + Clone + PartialEq + Eq,
76{
77 const ESCAPE_POLICY: EscapePolicy = EscapePolicy::CancelOnEscape;
79
80 type Config;
84
85 fn from_key(key: Key, config: &Self::Config) -> Option<Self>
87 where
88 Self: Sized;
89}
90
91#[cfg(test)]
92mod test {
93 use crate::{
94 ui::{Key, KeyModifiers},
95 Action, InnerAction,
96 };
97
98 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
99 pub enum MockInnerAction {
100 Action(Key),
101 }
102
103 impl InnerAction for MockInnerAction {
104 type Config = ();
105
106 fn from_key(key: Key, _config: &()) -> Option<Self>
107 where
108 Self: Sized,
109 {
110 Some(Self::Action(key))
111 }
112 }
113
114 #[test]
115 fn standard_keybindings_for_submit() {
116 let key = Key::Enter;
117 assert_eq!(
118 Some(Action::<MockInnerAction>::Submit),
119 Action::from_key(key, &())
120 );
121 }
122
123 #[test]
124 fn standard_keybindings_for_cancel() {
125 let key = Key::Escape;
126 assert_eq!(
127 Some(Action::<MockInnerAction>::Cancel),
128 Action::from_key(key, &())
129 );
130 }
131
132 #[test]
133 fn ctrl_c_results_in_interrupt_action() {
134 let key = Key::Char('c', KeyModifiers::CONTROL);
135 assert_eq!(
136 Some(Action::<MockInnerAction>::Interrupt),
137 Action::from_key(key, &())
138 );
139 }
140
141 #[test]
142 fn generic_keys_are_passed_down_to_inner_action() {
143 assert_eq!(
144 Some(Action::<MockInnerAction>::Inner(MockInnerAction::Action(
145 Key::Char('a', KeyModifiers::NONE)
146 ))),
147 Action::from_key(Key::Char('a', KeyModifiers::NONE), &())
148 );
149 assert_eq!(
150 Some(Action::<MockInnerAction>::Inner(MockInnerAction::Action(
151 Key::Home
152 ))),
153 Action::from_key(Key::Home, &())
154 );
155 assert_eq!(
156 Some(Action::<MockInnerAction>::Inner(MockInnerAction::Action(
157 Key::PageDown(KeyModifiers::NONE)
158 ))),
159 Action::from_key(Key::PageDown(KeyModifiers::NONE), &())
160 );
161 }
162
163 #[test]
164 fn emacs_control_keybindings() {
165 assert_eq!(
166 Some(Action::<MockInnerAction>::Submit),
167 Action::from_key(Key::Char('j', KeyModifiers::CONTROL), &())
168 );
169 assert_eq!(
170 Some(Action::<MockInnerAction>::Cancel),
171 Action::from_key(Key::Char('g', KeyModifiers::CONTROL), &())
172 );
173 }
174}