1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Pending-state sub-dispatcher for `App::dispatch_action`.
//!
//! Handles variants that set up `App::pending_state` for a two-key chord:
//! - BeginPendingReplace
//! - BeginPendingFind
//! - BeginPendingAfterG
//! - BeginPendingAfterZ
//! - BeginPendingAfterOp
//! - BeginPendingSelectRegister
//! - BeginPendingSetMark
//! - BeginPendingGotoMarkLine
//! - BeginPendingGotoMarkChar
//! - QChord
//! - BeginPendingPlayMacro
use crate::keymap_actions::AppAction;
use super::App;
use hjkl_vim::VimEditorExt;
impl App {
/// Dispatch a pending-state-initiating [`AppAction`].
///
/// Each arm stores a `PendingState` variant into `self.pending_state`.
/// The next key is then routed through `hjkl_vim::step` in
/// `route_chord_key_inner` instead of the trie or engine FSM.
pub(crate) fn dispatch_pending_state_action(&mut self, action: AppAction) {
match action {
AppAction::BeginPendingReplace {
count: action_count,
} => {
// Use buffered count-prefix if present, otherwise the action count.
let n = self.pending_count.take_or(action_count) as usize;
self.pending_state = Some(hjkl_vim::PendingState::Replace { count: n });
}
AppAction::BeginPendingFind {
forward,
till,
count: action_count,
} => {
// Use buffered count-prefix if present, otherwise the action count.
let n = self.pending_count.take_or(action_count) as usize;
self.pending_state = Some(hjkl_vim::PendingState::Find {
count: n,
forward,
till,
});
}
AppAction::BeginPendingAfterG {
count: action_count,
} => {
// Capture explicitness before `take_or` consumes/resets the
// buffer — needed to distinguish `2gt` (absolute) from bare
// `gt` (relative); see `g_chord_explicit_count` doc comment.
self.g_chord_explicit_count = !self.pending_count.is_empty();
// Use buffered count-prefix if present, otherwise the action count.
let n = self.pending_count.take_or(action_count) as usize;
self.pending_state = Some(hjkl_vim::PendingState::AfterG { count: n });
}
AppAction::BeginPendingAfterZ {
count: action_count,
} => {
// Use buffered count-prefix if present, otherwise the action count.
let n = self.pending_count.take_or(action_count) as usize;
self.pending_state = Some(hjkl_vim::PendingState::AfterZ { count: n });
}
AppAction::BeginPendingAfterOp {
op,
count1: action_count,
} => {
// Use buffered count-prefix if present, otherwise the action count.
let n = self.pending_count.take_or(action_count) as usize;
self.pending_state = Some(hjkl_vim::PendingState::AfterOp {
op,
count1: n,
inner_count: 0,
});
}
AppAction::BeginPendingSelectRegister => {
// `"<reg>` register-prefix chord. The register char is captured
// by the second key. Do NOT reset pending_count here — a count
// typed before `"` (e.g. `5"add`) must survive through register
// selection so the subsequent operator (`d`) can consume it.
// Example: `5"add` → pending_count=5, `"` → SelectRegister (count
// preserved), `a` → SetPendingRegister, `dd` → delete 5 lines
// into register `a`.
self.pending_state = Some(hjkl_vim::PendingState::SelectRegister);
}
AppAction::BeginPendingSetMark => {
// `m<x>` mark-set chord. No count consumed — char captured by
// second key. Discard any buffered count (not meaningful here).
self.pending_count.reset();
self.pending_state = Some(hjkl_vim::PendingState::SetMark);
}
AppAction::BeginPendingGotoMarkLine => {
// `'<x>` mark-goto-line chord. No count consumed.
self.pending_count.reset();
self.pending_state = Some(hjkl_vim::PendingState::GotoMarkLine);
}
AppAction::BeginPendingGotoMarkChar => {
// `` `<x> `` mark-goto-char chord. No count consumed.
self.pending_count.reset();
self.pending_state = Some(hjkl_vim::PendingState::GotoMarkChar);
}
AppAction::QChord { .. } => {
// `q` in Normal mode. Branch: stop recording if active, else
// open the RecordMacroTarget chord to wait for the register char.
self.pending_count.reset();
if self.active_editor().is_recording_macro() {
// Bare `q` ends the active recording.
self.active_editor_mut().stop_macro_record();
} else {
self.pending_state = Some(hjkl_vim::PendingState::RecordMacroTarget);
}
}
AppAction::BeginPendingPlayMacro {
count: action_count,
} => {
// `@` in Normal mode. Capture count and wait for register char.
let n = self.pending_count.take_or(action_count) as usize;
self.pending_state =
Some(hjkl_vim::PendingState::PlayMacroTarget { count: n.max(1) });
}
// Any non-pending-state action routed here is a logic error — ignore silently.
_ => return,
}
// Arm the which-key idle timer so the popup can fire after
// `which_key_delay` while the user contemplates the second key
// of an engine-FSM chord (g/z/d/y/c/etc.). Without this the
// popup only ever fires for app_keymap trie prefixes.
self.note_prefix_set();
}
}