#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PendingState {
Replace {
count: usize,
},
Find {
count: usize,
forward: bool,
till: bool,
},
AfterG {
count: usize,
},
AfterZ {
count: usize,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Outcome {
Wait(PendingState),
Commit(crate::cmd::EngineCmd),
Cancel,
Forward,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Key {
Char(char),
Esc,
Enter,
Backspace,
Tab,
}
pub fn step(state: PendingState, key: Key) -> Outcome {
match state {
PendingState::Replace { count } => match key {
Key::Esc => Outcome::Cancel,
Key::Char(ch) => Outcome::Commit(crate::cmd::EngineCmd::ReplaceChar { ch, count }),
Key::Enter => Outcome::Commit(crate::cmd::EngineCmd::ReplaceChar { ch: '\n', count }),
_ => Outcome::Cancel,
},
PendingState::Find {
count,
forward,
till,
} => match key {
Key::Esc => Outcome::Cancel,
Key::Char(ch) => Outcome::Commit(crate::cmd::EngineCmd::FindChar {
ch,
forward,
till,
count,
}),
_ => Outcome::Cancel,
},
PendingState::AfterG { count } => match key {
Key::Esc => Outcome::Cancel,
Key::Char(ch) => Outcome::Commit(crate::cmd::EngineCmd::AfterGChord { ch, count }),
_ => Outcome::Cancel,
},
PendingState::AfterZ { count } => match key {
Key::Esc => Outcome::Cancel,
Key::Char(ch) => Outcome::Commit(crate::cmd::EngineCmd::AfterZChord { ch, count }),
_ => Outcome::Cancel,
},
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cmd::EngineCmd;
#[test]
fn after_g_gg_commits() {
let state = PendingState::AfterG { count: 1 };
assert_eq!(
step(state, Key::Char('g')),
Outcome::Commit(EngineCmd::AfterGChord { ch: 'g', count: 1 })
);
}
#[test]
fn after_g_gv_commits() {
let state = PendingState::AfterG { count: 1 };
assert_eq!(
step(state, Key::Char('v')),
Outcome::Commit(EngineCmd::AfterGChord { ch: 'v', count: 1 })
);
}
#[test]
fn after_g_gu_operator_commits() {
let state = PendingState::AfterG { count: 1 };
assert_eq!(
step(state, Key::Char('U')),
Outcome::Commit(EngineCmd::AfterGChord { ch: 'U', count: 1 })
);
}
#[test]
fn after_g_gi_commits() {
let state = PendingState::AfterG { count: 1 };
assert_eq!(
step(state, Key::Char('i')),
Outcome::Commit(EngineCmd::AfterGChord { ch: 'i', count: 1 })
);
}
#[test]
fn after_g_esc_cancels() {
let state = PendingState::AfterG { count: 1 };
assert_eq!(step(state, Key::Esc), Outcome::Cancel);
}
#[test]
fn after_g_count_carry_through() {
let state = PendingState::AfterG { count: 5 };
assert_eq!(
step(state, Key::Char('g')),
Outcome::Commit(EngineCmd::AfterGChord { ch: 'g', count: 5 })
);
}
#[test]
fn after_g_non_char_cancels() {
let state = PendingState::AfterG { count: 1 };
assert_eq!(step(state, Key::Enter), Outcome::Cancel);
}
#[test]
fn after_z_zz_commits() {
let state = PendingState::AfterZ { count: 1 };
assert_eq!(
step(state, Key::Char('z')),
Outcome::Commit(EngineCmd::AfterZChord { ch: 'z', count: 1 })
);
}
#[test]
fn after_z_zf_commits() {
let state = PendingState::AfterZ { count: 1 };
assert_eq!(
step(state, Key::Char('f')),
Outcome::Commit(EngineCmd::AfterZChord { ch: 'f', count: 1 })
);
}
#[test]
fn after_z_esc_cancels() {
let state = PendingState::AfterZ { count: 1 };
assert_eq!(step(state, Key::Esc), Outcome::Cancel);
}
#[test]
fn after_z_count_carry_through() {
let state = PendingState::AfterZ { count: 3 };
assert_eq!(
step(state, Key::Char('z')),
Outcome::Commit(EngineCmd::AfterZChord { ch: 'z', count: 3 })
);
}
#[test]
fn after_z_non_char_cancels() {
let state = PendingState::AfterZ { count: 1 };
assert_eq!(step(state, Key::Enter), Outcome::Cancel);
}
}