From c020d53e238ccb28b6cbf7ee9345a87244d05155 Mon Sep 17 00:00:00 2001 From: Benno Schulenberg Date: Sat, 27 Apr 2024 16:29:04 +0200 Subject: [PATCH] input: snip the `recordmacro` and `runmacro` keystrokes in a better way When recording a macro over a laggy connection or on a slow, overloaded computer, several keystrokes could be recorded in one burst, and if any but the last of those keystrokes was the shortcut for `runmacro`, then running the macro would lead to an infinite loop and nano would hang. This new implementation of snipping the "last keystroke" will, however, snip *too many* keystrokes when several of them were recorded at once and `runmacro` or `recordmacro` was among them, resulting in a cropped and thus misrecorded macro. But... that's better than hanging. In general, though, the user should be slow and deliberate when recording a macro: waiting for nano to have processed the last keystroke before typing the next. This fixes https://savannah.gnu.org/bugs/?65649. The issue was reported by `correctmost`. Problem existed since version 2.9.0, since macros were introduced. --- src/winio.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/winio.c b/src/winio.c index 0d977708..0d838563 100644 --- a/src/winio.c +++ b/src/winio.c @@ -79,6 +79,8 @@ static int *macro_buffer = NULL; /* A buffer where the recorded key codes are stored. */ static size_t macro_length = 0; /* The current length of the macro. */ +static size_t milestone = 0; + /* Where the last burst of recorded keystrokes started. */ /* Add the given code to the macro buffer. */ void add_to_macrobuffer(int code) @@ -88,15 +90,6 @@ void add_to_macrobuffer(int code) macro_buffer[macro_length - 1] = code; } -/* Remove the last key code plus any leading Esc codes from macro buffer. */ -void snip_last_keystroke(void) -{ - if (macro_length > 0) - macro_length--; - while (macro_length > 0 && macro_buffer[macro_length - 1] == '\x1b') - macro_length--; -} - /* Start or stop the recording of keystrokes. */ void record_macro(void) { @@ -106,7 +99,8 @@ void record_macro(void) macro_length = 0; statusline(REMARK, _("Recording a macro...")); } else { - snip_last_keystroke(); + /* Snip the keystroke that invoked this function. */ + macro_length = milestone; statusline(REMARK, _("Stopped recording")); } @@ -120,7 +114,7 @@ void run_macro(void) { if (recording) { statusline(AHEM, _("Cannot run macro while recording")); - snip_last_keystroke(); + macro_length = milestone; return; } @@ -280,6 +274,9 @@ void read_keys_from(WINDOW *frame) /* If we got a SIGWINCH, get out as the frame argument is no longer valid. */ if (input == KEY_WINCH) return; + + /* Remember where the recording of this keystroke (or burst of them) started. */ + milestone = macro_length; #endif /* Read in any remaining key codes using non-blocking input. */