Re: nano appends a tilde when pasting five characters over ssh

Benno Schulenberg <[email protected]>
Newsgroups gmane.editors.nano.devel
Message-ID <[email protected]>
Op 24-02-2025 om 07:00 schreef Doug Smythies:
> I have been having an issue where nano will freeze after a paste of some characters.
> The only way out was to close the terminal and start again.  [...]

> is sort of fixed with
> commit 4a915b1ed581967350591c67965374f90e673030
> input: avoid hanging after a 39-character paste on a VSCode terminal
> As mentioned in the commit, there is an undesired ~ character
> pasted where previously the session would have frozen.

Finally, the issue was mostly fixed by commit bf12c90b:

    https://git.savannah.gnu.org/cgit/nano.git/commit/?id=bf12c90b


(The patch is also attached.)


Benno
0001-input-implement-bracketed-pastes-in-a-different-mann.patch (text/x-patch, 9.4 KB)
From bf12c90b076a424d2a399c543de24dac906f0a21 Mon Sep 17 00:00:00 2001
From: Benno Schulenberg <[email protected]>
Date: Sun, 9 Mar 2025 12:04:41 +0100
Subject: [PATCH] input: implement bracketed pastes in a different manner

Ask ncurses to recognize the escape sequences that mark the start
and end of a bracketed paste, and thus benefit from the waiting that
ncurses does for an escape sequence to complete.  This helps prevent
nano from failing to recognize an end-of-paste sequence (resulting
in hanging or inserting some sequence characters into the buffer).

This addresses https://savannah.gnu.org/bugs/?66858 in a better way.
Reported-by: Doug Smythies <[email protected]>
---
 src/browser.c     | 10 +++++-----
 src/definitions.h |  7 ++++---
 src/global.c      | 12 +++---------
 src/help.c        |  8 ++++----
 src/nano.c        | 17 ++++++++---------
 src/prompt.c      | 18 +++++++++++++++---
 src/prototypes.h  |  2 +-
 src/winio.c       |  3 +--
 8 files changed, 41 insertions(+), 36 deletions(-)

diff --git a/src/browser.c b/src/browser.c
index 56aa0410..3b2ddb45 100644
--- a/src/browser.c
+++ b/src/browser.c
@@ -483,11 +483,7 @@ char *browse(char *path)
 				continue;
 		}
 #endif /* ENABLE_MOUSE */
-#ifndef NANO_TINY
-		while (bracketed_paste && kbinput != FOREIGN_SEQUENCE)
-			kbinput = get_kbinput(midwin, BLIND);
-		bracketed_paste = FALSE;
-#endif
+
 		function = interpret(kbinput);
 
 		if (function == do_help || function == full_refresh) {
@@ -638,6 +634,10 @@ char *browse(char *path)
 			implant(first_sc_for(MBROWSER, function)->expansion);
 #endif
 #ifndef NANO_TINY
+		} else if (kbinput == START_OF_PASTE) {
+			while (get_kbinput(midwin, BLIND) != END_OF_PASTE)
+				;
+			statusline(AHEM, _("Paste is ignored"));
 		} else if (kbinput == THE_WINDOW_RESIZED) {
 			;  /* Gets handled below. */
 #endif
diff --git a/src/definitions.h b/src/definitions.h
index 97d5e203..c27a8a2c 100644
--- a/src/definitions.h
+++ b/src/definitions.h
@@ -217,6 +217,10 @@
 #define FOCUS_IN   0x491
 #define FOCUS_OUT  0x499
 
+/* Custom keycodes for signaling the start and end of a bracketed paste. */
+#define START_OF_PASTE  0x4B5
+#define END_OF_PASTE    0x4BE
+
 /* Special keycodes for when a string bind has been partially implanted
  * or has an unpaired opening brace, or when a function in a string bind
  * needs execution or a specified function name is invalid. */
@@ -233,9 +237,6 @@
 #define THE_WINDOW_RESIZED  0x4F7
 #endif
 
-/* A special keycode to signal the beginning and end of a bracketed paste. */
-#define BRACKETED_PASTE_MARKER  0x4FB
-
 /* A special keycode for when a key produces an unknown escape sequence. */
 #define FOREIGN_SEQUENCE  0x4FC
 
diff --git a/src/global.c b/src/global.c
index 1e133ea4..5f2a9c9f 100644
--- a/src/global.c
+++ b/src/global.c
@@ -43,8 +43,6 @@ bool shift_held;
 		/* Whether Shift was being held together with a movement key. */
 bool mute_modifiers = FALSE;
 		/* Whether to ignore modifier keys while running a macro or string bind. */
-bool bracketed_paste = FALSE;
-		/* Whether text is being pasted into nano from outside. */
 
 bool we_are_running = FALSE;
 		/* Becomes TRUE as soon as all options and files have been read. */
@@ -480,11 +478,6 @@ const keystruct *get_shortcut(const int keycode)
 	if (meta_key && keycode < 0x20)
 		return NULL;
 
-#ifndef NANO_TINY
-	/* During a paste at a prompt, ignore all command keycodes. */
-	if (bracketed_paste && keycode != BRACKETED_PASTE_MARKER)
-		return NULL;
-#endif
 #ifdef ENABLE_NANORC
 	if (keycode == PLANTED_A_COMMAND)
 		return planted_shortcut;
@@ -1583,8 +1576,9 @@ void shortcut_init(void)
 	add_to_sclist((MMOST & ~MMAIN) | MYESNO, "", KEY_CANCEL, do_cancel, 0);
 	add_to_sclist(MMAIN, "", KEY_CENTER, do_center, 0);
 	add_to_sclist(MMAIN, "", KEY_SIC, do_insertfile, 0);
-	/* Catch and ignore bracketed paste marker keys. */
-	add_to_sclist(MMOST|MBROWSER|MHELP|MYESNO, "", BRACKETED_PASTE_MARKER, do_nothing, 0);
+	add_to_sclist(MMAIN, "", START_OF_PASTE, suck_up_input_and_paste_it, 0);
+	add_to_sclist(MMOST, "", START_OF_PASTE, do_nothing, 0);
+	add_to_sclist(MMOST, "", END_OF_PASTE, do_nothing, 0);
 #else
 	add_to_sclist(MMOST|MBROWSER|MHELP|MYESNO, "", KEY_FRESH, full_refresh, 0);
 #endif
diff --git a/src/help.c b/src/help.c
index 65958e53..2888807e 100644
--- a/src/help.c
+++ b/src/help.c
@@ -476,10 +476,6 @@ void show_help(void)
 
 #ifndef NANO_TINY
 		spotlighted = FALSE;
-
-		while (bracketed_paste && kbinput != FOREIGN_SEQUENCE)
-			kbinput = get_kbinput(midwin, BLIND);
-		bracketed_paste = FALSE;
 #endif
 		function = interpret(kbinput);
 
@@ -508,6 +504,10 @@ void show_help(void)
 			get_mouseinput(&dummy_row, &dummy_col, TRUE);
 #endif
 #ifndef NANO_TINY
+		} else if (kbinput == START_OF_PASTE) {
+			while (get_kbinput(midwin, BLIND) != END_OF_PASTE)
+				;
+			statusline(AHEM, _("Paste is ignored"));
 		} else if (kbinput == THE_WINDOW_RESIZED) {
 			;  /* Nothing to do. */
 #endif
diff --git a/src/nano.c b/src/nano.c
index 58bdc2d1..7bd06326 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -1307,8 +1307,6 @@ void unbound_key(int code)
 		statusline(AHEM, _("Missing }"));
 #endif
 #ifndef NANO_TINY
-	else if (code == BRACKETED_PASTE_MARKER)
-		statusline(AHEM, _("Paste is ignored"));
 	else if (code > KEY_F0 && code < KEY_F0 + 25)
 		/* TRANSLATORS: This refers to an unbound function key. */
 		statusline(AHEM, _("Unbound key: F%i"), code - KEY_F0);
@@ -1446,7 +1444,7 @@ void suck_up_input_and_paste_it(void)
 	line->data = copy_of("");
 	cutbuffer = line;
 
-	while (bracketed_paste) {
+	while (TRUE) {
 		input = get_kbinput(midwin, BLIND);
 
 		if ((0x20 <= input && input <= 0xFF && input != DEL_CODE) || input == '\t') {
@@ -1458,8 +1456,8 @@ void suck_up_input_and_paste_it(void)
 			line = line->next;
 			line->data = copy_of("");
 			index = 0;
-		} else if (input != BRACKETED_PASTE_MARKER)
-			bracketed_paste = FALSE;
+		} else
+			break;
 	}
 
 	if (ISSET(VIEW_MODE))
@@ -1467,7 +1465,7 @@ void suck_up_input_and_paste_it(void)
 	else
 		paste_text();
 
-	if (input == FOREIGN_SEQUENCE)
+	if (input != END_OF_PASTE)
 		statusline(ALERT, _("Flawed paste"));
 
 	free_lines(cutbuffer);
@@ -1725,9 +1723,6 @@ void process_a_keystroke(void)
 	} else if (openfile->current != was_current)
 		also_the_last = FALSE;
 
-	if (bracketed_paste)
-		suck_up_input_and_paste_it();
-
 	if (ISSET(STATEFLAGS) && openfile->mark != was_mark)
 		titlebar(NULL);
 #endif
@@ -2483,6 +2478,10 @@ int main(int argc, char **argv)
 	shiftaltright = get_keycode("kRIT4", SHIFT_ALT_RIGHT);
 	shiftaltup = get_keycode("kUP4", SHIFT_ALT_UP);
 	shiftaltdown = get_keycode("kDN4", SHIFT_ALT_DOWN);
+
+	/* Tell ncurses to transform bracketed-paste sequences into keycodes. */
+	define_key("\e[200~", START_OF_PASTE);
+	define_key("\e[201~", END_OF_PASTE);
 #endif
 	mousefocusin = get_keycode("kxIN", FOCUS_IN);
 	mousefocusout = get_keycode("kxOUT", FOCUS_OUT);
diff --git a/src/prompt.c b/src/prompt.c
index e47f24ab..d5d7a043 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -426,6 +426,9 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
 	size_t fragment_length = 0;
 		/* The length of the fragment that the user tries to tab complete. */
 #endif
+#endif
+#ifndef NANO_TINY
+	bool bracketed_paste = FALSE;
 #endif
 	const keystruct *shortcut;
 	functionptrtype function;
@@ -450,6 +453,8 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
 #endif
 			return NULL;
 		}
+		if (input == START_OF_PASTE || input == END_OF_PASTE)
+			bracketed_paste = (input == START_OF_PASTE);
 #endif
 #ifdef ENABLE_MOUSE
 		/* For a click on a shortcut, read in the resulting keycode. */
@@ -466,6 +471,12 @@ functionptrtype acquire_an_answer(int *actual, bool *listed,
 		/* When it's a normal character, add it to the answer. */
 		absorb_character(input, function);
 
+#ifndef NANO_TINY
+		/* Ignore any commands inside an external paste. */
+		if (bracketed_paste)
+			continue;
+#endif
+
 		if (function == do_cancel || function == do_enter)
 			break;
 
@@ -711,10 +722,11 @@ int ask_user(bool withall, const char *question)
 			continue;
 
 		/* Accept first character of an external paste and ignore the rest. */
-		if (bracketed_paste)
+		if (kbinput == START_OF_PASTE) {
 			kbinput = get_kbinput(footwin, BLIND);
-		while (bracketed_paste)
-			get_kbinput(footwin, BLIND);
+			while (get_kbinput(footwin, BLIND) != END_OF_PASTE)
+				;
+		}
 #endif
 
 #ifdef ENABLE_NLS
diff --git a/src/prototypes.h b/src/prototypes.h
index f857365e..ceca2c23 100644
--- a/src/prototypes.h
+++ b/src/prototypes.h
@@ -32,7 +32,6 @@ extern bool shifted_metas;
 extern bool meta_key;
 extern bool shift_held;
 extern bool mute_modifiers;
-extern bool bracketed_paste;
 
 extern bool we_are_running;
 extern bool more_than_one;
@@ -441,6 +440,7 @@ void confirm_margin(void);
 #endif
 void unbound_key(int code);
 bool changes_something(functionptrtype f);
+void suck_up_input_and_paste_it(void);
 void inject(char *burst, size_t count);
 
 /* Most functions in prompt.c. */
diff --git a/src/winio.c b/src/winio.c
index 1095c292..bb56e771 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -728,8 +728,7 @@ int convert_CSI_sequence(const int *seq, size_t length, int *consumed)
 				/* Esc [ 2 0 0 ~ == start of a bracketed paste,
 				 * Esc [ 2 0 1 ~ == end of a bracketed paste. */
 				*consumed = 4;
-				bracketed_paste = (seq[2] == '0');
-				return BRACKETED_PASTE_MARKER;
+				return (seq[2] == '0') ? START_OF_PASTE : END_OF_PASTE;
 			} else {
 				*consumed = length;
 				return FOREIGN_SEQUENCE;
-- 
2.48.1
OpenPGP_signature.asc (application/pgp-signature, 840 B)
-----BEGIN PGP SIGNATURE-----

wsF5BAABCAAjFiEEFo5vQpe/16ea/USWUUu+Lrjhlh8FAmfRkWAFAwAAAAAACgkQUUu+Lrjhlh+C
Nw//f4r4aJt8yhiKTUDXb/yQESeAclHReQaPGHqqSaT3G7e32zYAJOyURjNxhZJphAG3zCZxo5Cm
NYYTP8blKwspmPoYUY9BrIgyVsoPa40H9GIx/TIfX+1DSqmNI8/YxSlpiv4Z46Wo0Sin81racFIX
LcExH1HCrGsZsiAzSQOhC4WYwqlu9ZbcMwvum9i7To4K8vcR6RDHM32l949jyrkeD5WwYWFKokZD
m6Vx2WZfqlzRQTpD3I8jP93pV1cMLKjUYIdpb2nH6aT2oDtW7hT9tNGpmxbH++98HCewCBoaNDe+
PnZP148Tfg3zzgyMdng0aJsIPc225DBVh+g83jnHPa2pIl53329IdCI6DhxgLlwmP2Iu5qJ2JvWf
xe6rDYbxRon22c+j7pGiCzRgHn5cX0++oasZ/1YKZ934Ufxm9sLtSdRmkUnHpPv1hTpXe9bSo2b1
hSfExMlE1GV3OTsfgt51LfNJEOiFR7E4nJGPvjFvep8Tx0e6lWjK3IOXwbBaOO6tPwVqD9Tyj4ma
fqjmg9obledFEiMpDlOwv8gQR81EyHg2+GmIh6xDwXQWfPPM20MtqEMTx5wKlMw7nqk6IXb5kuVE
hAQI5+ItgGzhsd89Glv7uKSqYMyHSJ0GSKgMye0LfWIGnogTvS/65+Dx6G5OUynhhIwuLgq0r525
GYk=
=KP6/
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.