Skip to main content

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}