1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum PendingState {
6 Replace {
7 count: usize,
8 },
9 Find {
13 count: usize,
14 forward: bool,
15 till: bool,
16 },
17 AfterG {
22 count: usize,
23 },
24 }
26
27#[derive(Debug, Clone, PartialEq, Eq)]
29pub enum Outcome {
30 Wait(PendingState),
32 Commit(crate::cmd::EngineCmd),
34 Cancel,
36 Forward,
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum Key {
45 Char(char),
46 Esc,
47 Enter,
48 Backspace,
49 Tab,
50 }
52
53pub fn step(state: PendingState, key: Key) -> Outcome {
54 match state {
55 PendingState::Replace { count } => match key {
56 Key::Esc => Outcome::Cancel,
57 Key::Char(ch) => Outcome::Commit(crate::cmd::EngineCmd::ReplaceChar { ch, count }),
58 Key::Enter => Outcome::Commit(crate::cmd::EngineCmd::ReplaceChar { ch: '\n', count }),
59 _ => Outcome::Cancel,
60 },
61 PendingState::Find {
62 count,
63 forward,
64 till,
65 } => match key {
66 Key::Esc => Outcome::Cancel,
67 Key::Char(ch) => Outcome::Commit(crate::cmd::EngineCmd::FindChar {
68 ch,
69 forward,
70 till,
71 count,
72 }),
73 _ => Outcome::Cancel,
75 },
76 PendingState::AfterG { count } => match key {
77 Key::Esc => Outcome::Cancel,
78 Key::Char(ch) => Outcome::Commit(crate::cmd::EngineCmd::AfterGChord { ch, count }),
79 _ => Outcome::Cancel,
81 },
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use crate::cmd::EngineCmd;
89
90 #[test]
93 fn after_g_gg_commits() {
94 let state = PendingState::AfterG { count: 1 };
95 assert_eq!(
96 step(state, Key::Char('g')),
97 Outcome::Commit(EngineCmd::AfterGChord { ch: 'g', count: 1 })
98 );
99 }
100
101 #[test]
102 fn after_g_gv_commits() {
103 let state = PendingState::AfterG { count: 1 };
104 assert_eq!(
105 step(state, Key::Char('v')),
106 Outcome::Commit(EngineCmd::AfterGChord { ch: 'v', count: 1 })
107 );
108 }
109
110 #[test]
111 fn after_g_gu_operator_commits() {
112 let state = PendingState::AfterG { count: 1 };
114 assert_eq!(
115 step(state, Key::Char('U')),
116 Outcome::Commit(EngineCmd::AfterGChord { ch: 'U', count: 1 })
117 );
118 }
119
120 #[test]
121 fn after_g_gi_commits() {
122 let state = PendingState::AfterG { count: 1 };
123 assert_eq!(
124 step(state, Key::Char('i')),
125 Outcome::Commit(EngineCmd::AfterGChord { ch: 'i', count: 1 })
126 );
127 }
128
129 #[test]
130 fn after_g_esc_cancels() {
131 let state = PendingState::AfterG { count: 1 };
132 assert_eq!(step(state, Key::Esc), Outcome::Cancel);
133 }
134
135 #[test]
136 fn after_g_count_carry_through() {
137 let state = PendingState::AfterG { count: 5 };
139 assert_eq!(
140 step(state, Key::Char('g')),
141 Outcome::Commit(EngineCmd::AfterGChord { ch: 'g', count: 5 })
142 );
143 }
144
145 #[test]
146 fn after_g_non_char_cancels() {
147 let state = PendingState::AfterG { count: 1 };
149 assert_eq!(step(state, Key::Enter), Outcome::Cancel);
150 }
151}