hjkl_vim/pending.rs
1/// Pending-state machine for second-key chords. The umbrella stores
2/// `Option<PendingState>`; when `Some`, it routes keys through `step`
3/// instead of the keymap trie.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum PendingState {
6 Replace { count: usize },
7 // 2b–2e variants land later.
8}
9
10/// One step of the reducer.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum Outcome {
13 /// Need more keys — keep accumulating with new state.
14 Wait(PendingState),
15 /// Run this engine command, then clear pending.
16 Commit(crate::cmd::EngineCmd),
17 /// Cancel pending (Esc, invalid char, etc.). No engine call.
18 Cancel,
19 /// Pending state didn't consume this key — host should route it
20 /// normally (e.g. modifier-only key). Pending state stays alive.
21 Forward,
22}
23
24/// `Key` is intentionally minimal — hjkl-vim should not depend on
25/// crossterm. Hosts translate their native keys into this shape.
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum Key {
28 Char(char),
29 Esc,
30 Enter,
31 Backspace,
32 Tab,
33 // Add more variants only as later chunks require them.
34}
35
36pub fn step(state: PendingState, key: Key) -> Outcome {
37 match state {
38 PendingState::Replace { count } => match key {
39 Key::Esc => Outcome::Cancel,
40 Key::Char(ch) => Outcome::Commit(crate::cmd::EngineCmd::ReplaceChar { ch, count }),
41 Key::Enter => Outcome::Commit(crate::cmd::EngineCmd::ReplaceChar { ch: '\n', count }),
42 _ => Outcome::Cancel,
43 },
44 }
45}