leader_sequence/
leader_sequence.rs1use std::time::{Duration, Instant};
11
12use keymap_core::{Key, KeyInput, Modifiers};
13use keymap_seq::{Match, SequenceKeymap, Step, TimedPending};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16enum Action {
17 Save,
18 Quit,
19 GotoTop,
20 NormalMode,
21}
22
23fn ctrl(c: char) -> KeyInput {
24 KeyInput::new(Key::Char(c), Modifiers::CTRL)
25}
26
27fn plain(c: char) -> KeyInput {
28 KeyInput::new(Key::Char(c), Modifiers::NONE)
29}
30
31fn main() {
32 untimed();
33 println!();
34 timed();
35}
36
37fn untimed() {
39 println!("== untimed ==");
40 let mut map = SequenceKeymap::new();
41 map.bind([ctrl('x'), ctrl('s')], Action::Save).unwrap();
42 map.bind([ctrl('x'), ctrl('c')], Action::Quit).unwrap();
43 map.bind([plain('g'), plain('g')], Action::GotoTop).unwrap();
44
45 let stream = [
48 ctrl('x'),
49 ctrl('s'),
50 ctrl('x'),
51 plain('z'),
52 plain('g'),
53 plain('g'),
54 ];
55
56 let mut pending: Vec<KeyInput> = Vec::new();
57 for key in stream {
58 pending.push(key);
59 match map.lookup(&pending) {
60 Match::Exact(action) => {
61 println!("{} -> fire {action:?}", render(&pending));
62 pending.clear();
63 }
64 Match::Prefix => {
65 println!("{} -> prefix, waiting", render(&pending));
66 }
67 Match::NoMatch => {
68 println!("{} -> no binding, passing through", render(&pending));
69 pending.clear();
70 }
71 }
72 }
73}
74
75fn timed() {
87 const WINDOW: Duration = Duration::from_millis(500);
88
89 println!("== timed (jj, via TimedPending) ==");
90 let mut map = SequenceKeymap::new();
91 map.bind([plain('j'), plain('j')], Action::NormalMode)
92 .unwrap();
93
94 let base = Instant::now();
96 let stream = [
97 (plain('j'), 0u64),
98 (plain('j'), 120), (plain('j'), 900),
100 (plain('j'), 1700), ];
102
103 let mut pending = TimedPending::new();
104 for (key, ms) in stream {
105 let now = base + Duration::from_millis(ms);
106 let result = pending.feed(&map, key, now, WINDOW);
107
108 if let Some(expired) = result.expired {
110 println!(
111 "{} @ +{ms}ms -> idle timeout, flushed as literals",
112 render(&expired),
113 );
114 }
115
116 match result.step {
117 Step::Fired(action) => println!("{key} @ +{ms}ms -> fire {action:?}"),
118 Step::Pending => println!("{key} @ +{ms}ms -> prefix, waiting (window {WINDOW:?})"),
119 Step::PassThrough(keys) => {
120 println!("{} @ +{ms}ms -> no binding, passing through", render(&keys));
121 }
122 }
123 }
124
125 let dangling = pending.flush();
127 if !dangling.is_empty() {
128 println!(
129 "{} -> pending at end; flushed as literals",
130 render(&dangling)
131 );
132 }
133}
134
135fn render(keys: &[KeyInput]) -> String {
136 keys.iter()
137 .map(ToString::to_string)
138 .collect::<Vec<_>>()
139 .join(" ")
140}