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 {
7 count: usize,
8 },
9 /// `f<x>` / `F<x>` / `t<x>` / `T<x>` — find single char on current line.
10 /// `forward` = direction (true for f/t, false for F/T).
11 /// `till` = stop one char before target (true for t/T, false for f/F).
12 Find {
13 count: usize,
14 forward: bool,
15 till: bool,
16 },
17 // 2c–2e variants land later.
18}
19
20/// One step of the reducer.
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum Outcome {
23 /// Need more keys — keep accumulating with new state.
24 Wait(PendingState),
25 /// Run this engine command, then clear pending.
26 Commit(crate::cmd::EngineCmd),
27 /// Cancel pending (Esc, invalid char, etc.). No engine call.
28 Cancel,
29 /// Pending state didn't consume this key — host should route it
30 /// normally (e.g. modifier-only key). Pending state stays alive.
31 Forward,
32}
33
34/// `Key` is intentionally minimal — hjkl-vim should not depend on
35/// crossterm. Hosts translate their native keys into this shape.
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum Key {
38 Char(char),
39 Esc,
40 Enter,
41 Backspace,
42 Tab,
43 // Add more variants only as later chunks require them.
44}
45
46pub fn step(state: PendingState, key: Key) -> Outcome {
47 match state {
48 PendingState::Replace { count } => match key {
49 Key::Esc => Outcome::Cancel,
50 Key::Char(ch) => Outcome::Commit(crate::cmd::EngineCmd::ReplaceChar { ch, count }),
51 Key::Enter => Outcome::Commit(crate::cmd::EngineCmd::ReplaceChar { ch: '\n', count }),
52 _ => Outcome::Cancel,
53 },
54 PendingState::Find {
55 count,
56 forward,
57 till,
58 } => match key {
59 Key::Esc => Outcome::Cancel,
60 Key::Char(ch) => Outcome::Commit(crate::cmd::EngineCmd::FindChar {
61 ch,
62 forward,
63 till,
64 count,
65 }),
66 // Any non-char key cancels (vim cancels f<non-char>).
67 _ => Outcome::Cancel,
68 },
69 }
70}