1use std::borrow::Cow;
28use std::collections::VecDeque;
29
30use crate::actions::MacroAction;
31use crate::errors::{EditError, EditResult};
32use crate::key::MacroError;
33use crate::keybindings::{dialog::Dialog, BindingMachine, InputKey};
34use crate::prelude::*;
35
36use super::{
37 application::ApplicationInfo,
38 context::{EditContext, Resolve},
39 rope::EditRope,
40 store::{RegisterPutFlags, Store},
41};
42
43const MAX_MACRO_EXEC_DEPTH: usize = 100;
44
45pub struct KeyManager<K, A, S>
47where
48 K: InputKey,
49{
50 bindings: Box<dyn BindingMachine<K, A, S, EditContext>>,
51 keystack: VecDeque<K>,
52
53 recording: Option<(Register, bool)>,
54 macro_exec_depth: usize,
55 commit_on_input: bool,
56 committed: EditRope,
57 pending: EditRope,
58}
59
60impl<K, A, S> KeyManager<K, A, S>
61where
62 K: InputKey,
63{
64 pub fn new<B: BindingMachine<K, A, S, EditContext> + 'static>(bindings: B) -> Self {
66 let bindings = Box::new(bindings);
67
68 Self {
69 bindings,
70 keystack: VecDeque::new(),
71
72 recording: None,
73 macro_exec_depth: 0,
74 commit_on_input: false,
75 committed: EditRope::from(""),
76 pending: EditRope::from(""),
77 }
78 }
79
80 pub fn macro_command<I: ApplicationInfo>(
82 &mut self,
83 act: &MacroAction,
84 ctx: &EditContext,
85 store: &mut Store<I>,
86 ) -> EditResult<EditInfo, I>
87 where
88 K: InputKey<Error = MacroError>,
89 {
90 let (mstr, count) = match act {
91 MacroAction::Execute(count) => {
92 let reg = ctx.get_register().unwrap_or(Register::UnnamedMacro);
93 let rope = store.registers.get_macro(reg)?;
94
95 (rope.to_string(), ctx.resolve(count))
96 },
97 MacroAction::Run(s, count) => (s.clone(), ctx.resolve(count)),
98 MacroAction::Repeat(count) => {
99 let rope = store.registers.get_last_macro()?;
100 (rope.to_string(), ctx.resolve(count))
101 },
102 MacroAction::ToggleRecording => {
103 if let Some((reg, append)) = &self.recording {
104 let mut rope = EditRope::from("");
106 std::mem::swap(&mut rope, &mut self.committed);
107
108 let mut flags = RegisterPutFlags::NOTEXT;
109
110 if *append {
111 flags |= RegisterPutFlags::APPEND;
112 }
113
114 store.registers.put(reg, rope.into(), flags)?;
115
116 self.recording = None;
118 self.commit_on_input = false;
119 self.pending = EditRope::from("");
120 } else {
121 let reg = ctx.get_register().unwrap_or(Register::UnnamedMacro);
122
123 self.recording = Some((reg, ctx.get_register_append()));
124 }
125
126 return Ok(None);
127 },
128 act => {
129 return Err(EditError::Unimplemented(format!("unknown action: {act:?}")));
130 },
131 };
132
133 self.macro_exec_depth += 1;
134
135 if self.macro_exec_depth >= MAX_MACRO_EXEC_DEPTH {
136 let err = MacroError::LoopingMacro(self.macro_exec_depth);
137 return Err(err.into());
138 }
139
140 for _ in 0..count {
141 let mut keys = VecDeque::from(K::from_macro_str(mstr.as_ref())?);
142 keys.append(&mut self.keystack);
143 self.keystack = keys;
144 }
145
146 return Ok(None);
147 }
148}
149
150impl<K, A, S> BindingMachine<K, A, S, EditContext> for KeyManager<K, A, S>
151where
152 K: InputKey + ToString,
153{
154 fn input_key(&mut self, key: K) {
155 self.macro_exec_depth = 0;
156
157 if self.recording.is_some() {
158 let mut rope = EditRope::from(key.to_string());
159
160 if self.commit_on_input {
161 std::mem::swap(&mut self.pending, &mut rope);
162 self.committed += rope;
163 self.commit_on_input = false;
164 } else {
165 self.pending += rope;
166 }
167 }
168
169 self.keystack.clear();
170 self.bindings.input_key(key);
171 }
172
173 fn pop(&mut self) -> Option<(A, EditContext)> {
174 loop {
175 if let res @ Some(_) = self.bindings.pop() {
176 self.commit_on_input = true;
177
178 return res;
179 }
180
181 match self.keystack.pop_front() {
182 Some(key) => self.bindings.input_key(key),
183 None => return None,
184 }
185 }
186 }
187
188 fn context(&mut self) -> EditContext {
189 self.bindings.context()
190 }
191
192 fn show_dialog(&mut self, max_rows: usize, max_cols: usize) -> Vec<Cow<'_, str>> {
193 self.bindings.show_dialog(max_rows, max_cols)
194 }
195
196 fn show_mode(&self) -> Option<String> {
197 self.bindings.show_mode()
198 }
199
200 fn reset_mode(&mut self) {
201 self.bindings.reset_mode()
202 }
203
204 fn get_cursor_indicator(&self) -> Option<char> {
205 self.bindings.get_cursor_indicator()
206 }
207
208 fn repeat(&mut self, seq: S, other: Option<EditContext>) {
209 self.bindings.repeat(seq, other)
210 }
211
212 fn run_dialog(&mut self, dialog: Box<dyn Dialog<A>>) {
213 self.bindings.run_dialog(dialog)
214 }
215}
216
217#[cfg(test)]
218#[macro_use]
219mod tests {
220 use super::*;
221 use crossterm::event::{KeyCode, KeyEvent};
222
223 use crate::{
224 editing::application::EmptyInfo,
225 editing::store::{RegisterError, Store},
226 env::vim::VimState,
227 env::CommonKeyClass,
228 errors::EditError,
229 key::TerminalKey,
230 keybindings::EdgeEvent::{Class, Key},
231 keybindings::{dialog::PromptYesNo, EmptySequence, ModalMachine, Mode, ModeKeys, Step},
232 };
233
234 type TestStore = Store<EmptyInfo>;
235 type TestMachine = ModalMachine<TerminalKey, TestStep>;
236 type TestKeyManager = KeyManager<TerminalKey, TestAction, EmptySequence>;
237
238 #[derive(Clone)]
239 struct TestStep(Option<TestAction>, Option<TestMode>);
240
241 impl Step<TerminalKey> for TestStep {
242 type A = TestAction;
243 type State = VimState;
244 type Class = CommonKeyClass;
245 type M = TestMode;
246 type Sequence = EmptySequence;
247
248 fn is_unmapped(&self) -> bool {
249 self.0.is_none() && self.1.is_none()
250 }
251
252 fn step(&self, ctx: &mut VimState) -> (Vec<TestAction>, Option<TestMode>) {
253 let act = self.0.clone().into_iter().collect();
254
255 ctx.action.count = ctx.action.counting;
256
257 (act, self.1)
258 }
259 }
260
261 impl From<TestAction> for TestStep {
262 fn from(action: TestAction) -> Self {
263 TestStep(Some(action), None)
264 }
265 }
266
267 impl From<TestMode> for TestStep {
268 fn from(mode: TestMode) -> Self {
269 TestStep(None, Some(mode))
270 }
271 }
272
273 #[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq)]
274 enum TestMode {
275 #[default]
276 Normal,
277 Insert,
278 }
279
280 impl Mode<TestAction, VimState> for TestMode {}
281
282 impl ModeKeys<TerminalKey, TestAction, VimState> for TestMode {
283 fn unmapped(
284 &self,
285 key: &TerminalKey,
286 _: &mut VimState,
287 ) -> (Vec<TestAction>, Option<TestMode>) {
288 match self {
289 TestMode::Normal => {
290 return (vec![], None);
291 },
292 TestMode::Insert => {
293 if let Some(c) = key.get_char() {
294 return (vec![TestAction::Type(c)], None);
295 }
296
297 return (vec![], None);
298 },
299 }
300 }
301 }
302
303 #[derive(Clone, Debug, Default, Eq, PartialEq)]
304 enum TestAction {
305 Macro(MacroAction),
306 SetFlag(bool),
307 Type(char),
308 #[default]
309 NoOp,
310 }
311
312 fn setup_recursive_bindings() -> (TestKeyManager, TestStore) {
313 use crate::keybindings::EdgeRepeat::{Min, Once};
314
315 let mut bindings = TestMachine::empty();
316 let store = Store::default();
317
318 bindings.add_mapping(
320 TestMode::Normal,
321 &[(Once, Key("n".parse().unwrap()))],
322 &TestAction::NoOp.into(),
323 );
324 bindings.add_mapping(
325 TestMode::Normal,
326 &[(Once, Key("a".parse().unwrap()))],
327 &TestAction::Macro(MacroAction::Run("n".into(), Count::Contextual)).into(),
328 );
329 bindings.add_mapping(
330 TestMode::Normal,
331 &[(Once, Key("b".parse().unwrap()))],
332 &TestAction::Macro(MacroAction::Run("aa".into(), Count::Contextual)).into(),
333 );
334 bindings.add_mapping(
335 TestMode::Normal,
336 &[(Once, Key("c".parse().unwrap()))],
337 &TestAction::Macro(MacroAction::Run("c".into(), Count::Contextual)).into(),
338 );
339
340 bindings.add_prefix(
342 TestMode::Normal,
343 &[
344 (Once, Key("\"".parse().unwrap())),
345 (Once, Class(CommonKeyClass::Register)),
346 ],
347 &None,
348 );
349 bindings.add_prefix(TestMode::Normal, &[(Min(1), Class(CommonKeyClass::Count))], &None);
350
351 (TestKeyManager::new(bindings), store)
352 }
353
354 fn setup_bindings(skip_confirm: bool) -> (TestKeyManager, TestStore) {
355 use crate::keybindings::EdgeRepeat::{Min, Once};
356
357 let mut bindings = TestMachine::empty();
358 let store = Store::default();
359
360 bindings.add_mapping(
362 TestMode::Normal,
363 &[
364 (Once, Key("q".parse().unwrap())),
365 (Once, Key("q".parse().unwrap())),
366 (Once, Key("q".parse().unwrap())),
367 ],
368 &TestAction::Macro(MacroAction::ToggleRecording).into(),
369 );
370 bindings.add_mapping(
371 TestMode::Normal,
372 &[(Once, Key("@".parse().unwrap()))],
373 &TestAction::Macro(MacroAction::Repeat(Count::Contextual)).into(),
374 );
375 bindings.add_mapping(
376 TestMode::Normal,
377 &[(Once, Key("Q".parse().unwrap()))],
378 &TestAction::Macro(MacroAction::Execute(Count::Contextual)).into(),
379 );
380 bindings.add_mapping(
381 TestMode::Normal,
382 &[(Once, Key("f".parse().unwrap()))],
383 &TestAction::SetFlag(skip_confirm).into(),
384 );
385 bindings.add_mapping(
386 TestMode::Normal,
387 &[(Once, Key("i".parse().unwrap()))],
388 &TestMode::Insert.into(),
389 );
390
391 bindings.add_prefix(
393 TestMode::Normal,
394 &[
395 (Once, Key("\"".parse().unwrap())),
396 (Once, Class(CommonKeyClass::Register)),
397 ],
398 &None,
399 );
400 bindings.add_prefix(TestMode::Normal, &[(Min(1), Class(CommonKeyClass::Count))], &None);
401
402 bindings.add_mapping(
404 TestMode::Insert,
405 &[(Once, Key("<Esc>".parse().unwrap()))],
406 &TestMode::Normal.into(),
407 );
408
409 (TestKeyManager::new(bindings), store)
410 }
411
412 fn input(
413 key: TerminalKey,
414 bindings: &mut TestKeyManager,
415 store: &mut TestStore,
416 s: &mut String,
417 flag: &mut bool,
418 noops: &mut usize,
419 err: &mut Option<EditError<EmptyInfo>>,
420 ) {
421 *noops = 0;
422 *err = None;
423
424 bindings.input_key(key);
425
426 while let Some((act, ctx)) = bindings.pop() {
427 match act {
428 TestAction::NoOp => {
429 *noops += 1;
430 continue;
431 },
432 TestAction::Macro(act) => {
433 *err = bindings.macro_command(&act, &ctx, store).err();
434
435 if err.is_some() {
436 return;
437 }
438 },
439 TestAction::SetFlag(skip_confirm) => {
440 if skip_confirm {
441 *flag = true;
442 } else {
443 let act = vec![TestAction::SetFlag(true)];
444 let msg = "Are you sure you want to set the flag";
445 let confirm = PromptYesNo::new(msg, act);
446 bindings.run_dialog(Box::new(confirm));
447 }
448 },
449 TestAction::Type(c) => s.push(c),
450 }
451 }
452 }
453
454 #[test]
455 fn test_macro_run() {
456 let (mut bindings, mut store) = setup_bindings(true);
457 let ctx = EditContext::from(VimState::<EmptyInfo>::default());
458
459 let run = MacroAction::Run("flif<Esc>fi".into(), 2.into());
461 let _ = bindings.macro_command(&run, &ctx, &mut store).unwrap();
462
463 assert_pop1!(bindings, TestAction::SetFlag(true), ctx);
465 assert_pop1!(bindings, TestAction::NoOp, ctx);
466 assert_pop1!(bindings, TestAction::NoOp, ctx);
467 assert_pop1!(bindings, TestAction::Type('f'), ctx);
468 assert_pop1!(bindings, TestAction::NoOp, ctx);
469 assert_pop1!(bindings, TestAction::SetFlag(true), ctx);
470 assert_pop1!(bindings, TestAction::NoOp, ctx);
471
472 assert_pop1!(bindings, TestAction::Type('f'), ctx);
474 assert_pop1!(bindings, TestAction::Type('l'), ctx);
475 assert_pop1!(bindings, TestAction::Type('i'), ctx);
476 assert_pop1!(bindings, TestAction::Type('f'), ctx);
477 assert_pop1!(bindings, TestAction::NoOp, ctx);
478 assert_pop1!(bindings, TestAction::SetFlag(true), ctx);
479 assert_pop2!(bindings, TestAction::NoOp, ctx);
480 }
481
482 #[test]
483 fn test_record_and_execute() {
484 let (mut bindings, mut store) = setup_bindings(true);
485 let mut s = String::new();
486 let mut flag = false;
487 let mut err = None;
488 let mut noops = 0;
489
490 macro_rules! get_register {
491 ($reg: expr) => {
492 store.registers.get(&$reg).unwrap().value
493 };
494 }
495
496 macro_rules! input {
497 ($key: expr) => {
498 input($key, &mut bindings, &mut store, &mut s, &mut flag, &mut noops, &mut err)
499 };
500 }
501
502 assert_eq!(get_register!(Register::UnnamedMacro).to_string(), "");
504
505 input!(key!('@'));
507 assert!(matches!(err, Some(EditError::Register(RegisterError::NoLastMacro))), "{:?}", err);
508
509 input!(key!('l'));
511
512 input!(key!('"'));
514 input!(key!('a'));
515 input!(key!('q'));
516 input!(key!('q'));
517 input!(key!('q'));
518
519 input!(key!('n'));
521 input!(key!('z'));
522
523 input!(key!('f'));
525
526 input!(key!('i'));
528 input!(key!('a'));
529 input!(key!('b'));
530 input!(key!('c'));
531
532 input!("<Esc>".parse().unwrap());
534
535 input!(key!('q'));
537 input!(key!('q'));
538 input!(key!('q'));
539
540 assert_eq!(get_register!(Register::Named('a')).to_string(), "nzfiabc<Esc>");
542 assert_eq!(s, "abc");
543 assert_eq!(flag, true);
544
545 flag = false;
547
548 input!(key!('"'));
550 input!(key!('a'));
551 input!(key!('2'));
552 input!(key!('Q'));
553 assert_eq!(s, "abcabcabc");
554 assert_eq!(flag, true);
555
556 flag = false;
558
559 input!(key!('@'));
561 assert_eq!(s, "abcabcabcabc");
562 assert_eq!(flag, true);
563
564 flag = false;
566
567 input!(key!('q'));
569 input!(key!('q'));
570 input!(key!('q'));
571 input!(key!('i'));
572 input!(key!('d'));
573 input!(key!('e'));
574 input!(key!('f'));
575 input!("<Esc>".parse().unwrap());
576 input!(key!('"'));
577 input!(key!('a'));
578 input!(key!('Q'));
579 input!(key!('q'));
580 input!(key!('q'));
581 input!(key!('q'));
582
583 assert_eq!(get_register!(Register::UnnamedMacro).to_string(), "idef<Esc>\"aQ");
585 assert_eq!(get_register!(Register::Named('a')).to_string(), "nzfiabc<Esc>");
586 assert_eq!(s, "abcabcabcabcdefabc");
587 assert_eq!(flag, true);
588
589 flag = false;
591
592 input!(key!('3'));
594 input!(key!('Q'));
595 assert_eq!(s, "abcabcabcabcdefabcdefabcdefabcdefabc");
596 assert_eq!(flag, true);
597
598 flag = false;
600
601 input!(key!('2'));
603 input!(key!('@'));
604 assert_eq!(s, "abcabcabcabcdefabcdefabcdefabcdefabcabcabc");
605 assert_eq!(flag, true);
606 }
607
608 #[test]
609 fn test_macro_dialog() {
610 let (mut bindings, mut store) = setup_bindings(false);
611 let mut s = String::new();
612 let mut flag = false;
613 let mut err = None;
614 let mut noops = 0;
615
616 macro_rules! get_register {
617 ($reg: expr) => {
618 store.registers.get(&$reg).unwrap().value
619 };
620 }
621
622 macro_rules! input {
623 ($key: expr) => {
624 input($key, &mut bindings, &mut store, &mut s, &mut flag, &mut noops, &mut err)
625 };
626 }
627
628 assert_eq!(bindings.show_dialog(10, 100).len(), 0);
629 assert_eq!(flag, false);
630
631 input!(key!('"'));
633 input!(key!('a'));
634 input!(key!('q'));
635 input!(key!('q'));
636 input!(key!('q'));
637
638 input!(key!('f'));
640 assert_eq!(bindings.show_dialog(10, 100).len(), 1);
641 assert_eq!(flag, false);
642
643 input!(key!('y'));
645 assert_eq!(bindings.show_dialog(10, 100).len(), 0);
646 assert_eq!(flag, true);
647
648 input!(key!('q'));
650 input!(key!('q'));
651 input!(key!('q'));
652
653 assert_eq!(get_register!(Register::Named('a')).to_string(), "fy");
655
656 flag = false;
658
659 input!(key!('"'));
661 input!(key!('a'));
662 input!(key!('Q'));
663
664 assert_eq!(bindings.show_dialog(10, 100).len(), 0);
666 assert_eq!(flag, true);
667 }
668
669 #[test]
670 fn test_macro_limit_depth() {
671 let (mut bindings, mut store) = setup_recursive_bindings();
672 let mut s = String::new();
673 let mut flag = false;
674 let mut err = None;
675 let mut noops = 0;
676
677 macro_rules! input {
678 ($key: expr) => {
679 input($key, &mut bindings, &mut store, &mut s, &mut flag, &mut noops, &mut err)
680 };
681 }
682
683 input!(key!('1'));
685 input!(key!('1'));
686 input!(key!('0'));
687 input!(key!('a'));
688 assert!(err.is_none());
689 assert_eq!(noops, 110);
690
691 input!(key!('4'));
693 input!(key!('9'));
694 input!(key!('b'));
695 assert!(err.is_none());
696 assert_eq!(noops, 98);
697
698 input!(key!('5'));
700 input!(key!('0'));
701 input!(key!('b'));
702 println!("err = {err:?}");
703 assert!(matches!(
704 err.take().unwrap(),
705 EditError::MacroFailure(MacroError::LoopingMacro(100))
706 ));
707 assert_eq!(noops, 98);
708
709 input!(key!('c'));
711 println!("err = {err:?}");
712 assert!(matches!(
713 err.take().unwrap(),
714 EditError::MacroFailure(MacroError::LoopingMacro(100))
715 ));
716 assert_eq!(noops, 0);
717 }
718}