on master help sign in
Fix recursive macro crash and empty macro lockout (#2902)
030de46PabloMansanet
helix-term/src/commands.rs+8−4
@@ -4655,8 +4655,6 @@ fn replay_macro(cx: &mut Context) {
4655 return;
4655 return;
4656 }
4656 }
4657
4657
4658− cx.editor.macro_replaying.push(reg);
4659−
4660 let keys: Vec<KeyEvent> = if let Some([keys_str]) = cx.editor.registers.read(reg) {
4658 let keys: Vec<KeyEvent> = if let Some([keys_str]) = cx.editor.registers.read(reg) {
4661 match helix_view::input::parse_macro(keys_str) {
4659 match helix_view::input::parse_macro(keys_str) {
4662 Ok(keys) => keys,
4660 Ok(keys) => keys,
@@ -4670,6 +4668,10 @@ fn replay_macro(cx: &mut Context) {
4670 return;
4668 return;
4671 };
4669 };
4672
4670
4671+ // Once the macro has been fully validated, it's marked as being under replay
4672+ // to ensure we don't fall into infinite recursion.
4673+ cx.editor.macro_replaying.push(reg);
4674+
4673 let count = cx.count();
4675 let count = cx.count();
4674 cx.callback = Some(Box::new(move |compositor, cx| {
4676 cx.callback = Some(Box::new(move |compositor, cx| {
4675 for _ in 0..count {
4677 for _ in 0..count {
@@ -4677,7 +4679,9 @@ fn replay_macro(cx: &mut Context) {
4677 compositor.handle_event(crossterm::event::Event::Key(key.into()), cx);
4679 compositor.handle_event(crossterm::event::Event::Key(key.into()), cx);
4678 }
4680 }
4679 }
4681 }
4682+ // The macro under replay is cleared at the end of the callback, not in the
4683+ // macro replay context, or it will not correctly protect the user from
4684+ // replaying recursively.
4685+ cx.editor.macro_replaying.pop();
4680 }));
4686 }));
4681−
4682− cx.editor.macro_replaying.pop();
4683}
4687}