From 0ea77d2ec71d42c28c28573794a4ac95bb3a912a Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Wed, 9 Oct 2024 07:25:18 +0200 Subject: [PATCH 1/3] Ticket #4597: fix CSI parser fish shell 4.0 wants to send sequences like "\x1b[=5u", so strip them from the output as well. See https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences In future we should probably pass through some sequences like bracketed paste. Signed-off-by: Yury V. Zaytsev --- lib/util.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/util.c b/lib/util.c index fdd758cf8c..ecc219ed8e 100644 --- a/lib/util.c +++ b/lib/util.c @@ -736,7 +736,10 @@ skip_numbers (const char *s) * "control sequence", in a sort of pidgin BNF, as follows: * * control-seq = Esc non-'[' - * | Esc '[' (0 or more digits or ';' or ':' or '?') (any other char) + * | Esc '[' (parameter-byte)* (intermediate-byte)* final-byte + * parameter-byte = [\x30-\x3F] # one of "0-9;:<=>?" + * intermediate-byte = [\x20–\x2F] # one of " !\"#$%&'()*+,-./" + * final-byte = [\x40-\x7e] # one of "@A–Z[\]^_`a–z{|}~" * * The 256-color and true-color escape sequences should allow either ';' or ':' inside as separator, * actually, ':' is the more correct according to ECMA-48. @@ -763,8 +766,10 @@ strip_ctrl_codes (char *s) if (*(++r) == '[' || *r == '(') { /* strchr() matches trailing binary 0 */ - while (*(++r) != '\0' && strchr ("0123456789;:?", *r) != NULL) + while (*(++r) != '\0' && strchr ("0123456789;:<=>?", *r) != NULL) ; + while (*r != '\0' && (*r < 0x40 || *r > 0x7E)) + ++r; } else if (*r == ']') { From 6e4510b55816139e06813ce423ca7e35f4e8ba05 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Wed, 9 Oct 2024 08:03:26 +0200 Subject: [PATCH 2/3] subshell: recognize CSI u encoding for ctrl-o If a subshell (like fish 4.0) wishes to use "Disambiguate control keys" from https://sw.kovidgoyal.net/kitty/keyboard-protocol/, ctrl-o sends a multi-byte sequence. Let's make sure we can intercept that too so we can suspend the shell. Note that the shell already disables "Disambiguate control keys" while it's suspended, so no other changes should be necessary. Unfortunately there is one bug left: when I start "SHELL=$(which fish) mc" and type `ctrl-o`, fish does not recognize CSI u bindings (such as `bind ctrl-2 'echo hello'`) yet. It only works after the second prompt. I haven't had time to figure that out. Signed-off-by: Yury V. Zaytsev --- src/subshell/common.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/subshell/common.c b/src/subshell/common.c index c196865c00..f75f8f6c24 100644 --- a/src/subshell/common.c +++ b/src/subshell/common.c @@ -180,6 +180,9 @@ static int subshell_pty_slave = -1; /* The key for switching back to MC from the subshell */ /* *INDENT-OFF* */ static const char subshell_switch_key = XCTRL ('o') & 255; + +static const char subshell_switch_key_csi_u[] = "\x1b[111;5u"; +static const size_t subshell_switch_key_csi_u_len = sizeof(subshell_switch_key_csi_u) - 1; /* *INDENT-ON* */ /* For reading/writing on the subshell's pty */ @@ -864,7 +867,10 @@ feed_subshell (int how, gboolean fail_on_error) } for (i = 0; i < bytes; ++i) - if (pty_buffer[i] == subshell_switch_key) + if (pty_buffer[i] == subshell_switch_key || + (subshell_switch_key_csi_u_len <= (size_t) bytes - i && + memcmp (&pty_buffer[i], subshell_switch_key_csi_u, + subshell_switch_key_csi_u_len) == 0)) { write_all (mc_global.tty.subshell_pty, pty_buffer, i); From 6ca20130827b59f0ebb2772c78e5ed8ed880c5d0 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Fri, 11 Oct 2024 08:26:48 +0200 Subject: [PATCH 3/3] subshell: advertise that we can suspend a shell that requested CSI u Add a new variable to let fish know that -- since the parent commit -- we are running a version where fish can use the kitty keyboard protocol without breaking mc. In a few years, both fish and mc should ideally remove this hack (and fish should speak the kitty keyboard protocol unconditionally), so no one should rely on this new variable except as a temporary workaround. Hence the feature-specific flag and not a generic version variable. Signed-off-by: Yury V. Zaytsev --- src/subshell/common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/subshell/common.c b/src/subshell/common.c index f75f8f6c24..64e911232c 100644 --- a/src/subshell/common.c +++ b/src/subshell/common.c @@ -430,10 +430,14 @@ init_subshell_child (const char *pty_name) execl (mc_global.shell->path, mc_global.shell->path, "-Z", "-g", (char *) NULL); break; + case SHELL_FISH: + execl (mc_global.shell->path, mc_global.shell->path, + "--init-command", "set --global __mc_csi_u 1", (char *) NULL); + break; + case SHELL_ASH_BUSYBOX: case SHELL_DASH: case SHELL_TCSH: - case SHELL_FISH: execl (mc_global.shell->path, mc_global.shell->path, (char *) NULL); break;