Download raw body.
bin/ksh: fix emacs/vi mode using wrong terminal width
On Thu, 22 Jan 2026 16:59:21 +0100,
Kirill A. Korinsky <kirill@korins.ky> wrote:
>
> tech@,
>
> this is clear re-submission of my patch to ksh to fix terminal width
> detecion.
>
> xterm and other terminal emulators resize the pty after starting the
> shell. x_init() queries the terminal size at startup before the resize
> occurs, so x_cols stays at the default 80 columns.
>
> SIGWINCH arrives, but check_sigwinch() isn't called until after command
> entry. This makes the line editor think the screen is 80 columns, which
> makes it show '<' and truncate input before the actual terminal edge on
> large windows, and causes weird behavior on small ones.
>
> Call check_sigwinch() when entering edit mode and on EINTR in x_getc().
> The callback lets emacs/vi mode recalculate display width and redraw.
>
Here reworked version which addressed an edge case when prompt is duplicated
when resize had happened when curses application is used which was reported
by Walter Alejandro Iglesias, and suggestion from chris@ to honor curses
when it possible.
Also, I had introduced a regression tests with one note: the vi mode resize
path is multi stage and can interleave with pending input, so the byte
stream varies even when the final screen is correct; to make the test
deterministic, edit.c waits for two consecutive quiet poll timeouts to
ensure the child is idle before sending TIOCSWINSZ and SIGWINCH.
Ok?
diff --git bin/ksh/edit.c bin/ksh/edit.c
index 3ed69e5375d..83bab8ffbad 100644
--- bin/ksh/edit.c
+++ bin/ksh/edit.c
@@ -25,7 +25,8 @@ X_chars edchars;
static void x_sigwinch(int);
volatile sig_atomic_t got_sigwinch;
-static void check_sigwinch(void);
+void check_sigwinch(void);
+void (*x_resize_cb)(void); /* callback for resize during edit */
static int x_file_glob(int, const char *, int, char ***);
static int x_command_glob(int, const char *, int, char ***);
@@ -58,7 +59,7 @@ x_sigwinch(int sig)
got_sigwinch = 1;
}
-static void
+void
check_sigwinch(void)
{
if (got_sigwinch) {
@@ -75,11 +76,16 @@ check_sigwinch(void)
* see the change cause the environ doesn't change.
*/
if (ws.ws_col) {
+ int old_cols = x_cols;
+
x_cols = ws.ws_col < MIN_COLS ? MIN_COLS :
ws.ws_col;
if ((vp = typeset("COLUMNS", 0, 0, 0, 0)))
setint(vp, (int64_t) ws.ws_col);
+
+ if (x_cols != old_cols && x_resize_cb)
+ (*x_resize_cb)();
}
if (ws.ws_row && (vp = typeset("LINES", 0, 0, 0, 0)))
setint(vp, (int64_t) ws.ws_row);
@@ -120,12 +126,14 @@ x_getc(void)
char c;
int n;
- while ((n = blocking_read(STDIN_FILENO, &c, 1)) < 0 && errno == EINTR)
+ while ((n = blocking_read(STDIN_FILENO, &c, 1)) < 0 && errno == EINTR) {
+ check_sigwinch();
if (trap) {
x_mode(false);
runtraps(0);
x_mode(true);
}
+ }
if (n != 1)
return -1;
return (int) (unsigned char) c;
diff --git bin/ksh/edit.h bin/ksh/edit.h
index 1d573e1f6fb..abcecc667e0 100644
--- bin/ksh/edit.h
+++ bin/ksh/edit.h
@@ -39,6 +39,8 @@ extern X_chars edchars;
#define XCF_COMMAND_FILE (XCF_COMMAND|XCF_FILE)
/* edit.c */
+void check_sigwinch(void);
+extern void (*x_resize_cb)(void);
int x_getc(void);
void x_flush(void);
int x_putc(int);
diff --git bin/ksh/emacs.c bin/ksh/emacs.c
index 3c9b0074d81..43223bc06b2 100644
--- bin/ksh/emacs.c
+++ bin/ksh/emacs.c
@@ -105,6 +105,7 @@ static int xlp_valid;
/* end from 4.9 edit.h } */
static int x_tty; /* are we on a tty? */
static int x_bind_quiet; /* be quiet when binding keys */
+static void x_emacs_resize(void);
static int (*x_last_command)(int);
static char **x_histp; /* history position */
@@ -286,6 +287,9 @@ x_emacs(char *buf, size_t len)
xmp = NULL;
x_histp = histptr + 1;
+ x_resize_cb = NULL;
+ check_sigwinch();
+ x_resize_cb = x_emacs_resize;
xx_cols = x_cols;
x_col = promptlen(prompt, &p);
prompt_skip = p - prompt;
@@ -316,8 +320,11 @@ x_emacs(char *buf, size_t len)
x_last_command = NULL;
while (1) {
x_flush();
- if ((at = x_e_getu8(line, at)) < 0)
+ if ((at = x_e_getu8(line, at)) < 0) {
+ x_resize_cb = NULL;
return 0;
+ }
+
ntries++;
if (x_arg == -1) {
@@ -378,6 +385,7 @@ x_emacs(char *buf, size_t len)
x_last_command = NULL;
break;
case KEOL:
+ x_resize_cb = NULL;
ret = xep - xbuf;
return (ret);
break;
@@ -2162,4 +2170,51 @@ x_lastcp(void)
return (xlp);
}
+static void
+x_emacs_resize(void)
+{
+ int cr_done = 0, cleared = 0;
+
+#ifndef SMALL
+ if (cur_term != NULL) {
+ if (carriage_return != NULL &&
+ tputs(carriage_return, 1, x_putc) != ERR)
+ cr_done = 1;
+ if (clr_eos != NULL &&
+ tputs(clr_eos, 1, x_putc) != ERR)
+ cleared = 1;
+ }
+#endif
+ if (!cr_done)
+ x_putc('\r');
+ if (!cleared) {
+ x_putc('\033');
+ x_putc('[');
+ x_putc('J');
+ }
+
+ xx_cols = x_cols;
+ x_col = promptlen(prompt, NULL);
+ if (x_col > xx_cols)
+ x_col = x_col - (x_col / xx_cols) * xx_cols;
+ x_displen = xx_cols - 2 - x_col;
+ if (x_displen < 1) {
+ x_col = 0;
+ x_displen = xx_cols - 2;
+ prompt_redraw = 0;
+ } else {
+ xbp = xbuf;
+ xlp_valid = false;
+ if (xcp <= x_lastcp()) {
+ x_redraw(0);
+ x_flush();
+ return;
+ }
+ }
+
+ x_col = 0;
+ x_displen = xx_cols - 2;
+ x_adjust();
+}
+
#endif /* EMACS */
diff --git bin/ksh/vi.c bin/ksh/vi.c
index 28be809036d..168a9a8ffa5 100644
--- bin/ksh/vi.c
+++ bin/ksh/vi.c
@@ -75,6 +75,8 @@ static void vi_error(void);
static void vi_macro_reset(void);
static int x_vi_putbuf(const char *, size_t);
static int isu8cont(unsigned char);
+static void x_vi_resize(void);
+static void calc_winsize(void);
#define C_ 0x1 /* a valid command that isn't a M_, E_, U_ */
#define M_ 0x2 /* movement command (h, l, etc.) */
@@ -200,6 +202,9 @@ x_vi(char *buf, size_t len)
{
int c;
+ x_resize_cb = NULL;
+ check_sigwinch();
+ x_resize_cb = x_vi_resize;
vi_reset(buf, len > LINE ? LINE : len);
vi_pprompt(1);
x_flush();
@@ -242,6 +247,7 @@ x_vi(char *buf, size_t len)
x_flush();
}
+ x_resize_cb = NULL;
x_putc('\r'); x_putc('\n'); x_flush();
if (c == -1 || len <= (size_t)es->linelen)
@@ -1424,8 +1430,6 @@ free_edstate(struct edstate *old)
static void
edit_reset(char *buf, size_t len)
{
- const char *p;
-
es = &ebuf;
es->cbuf = buf;
es->cbufsize = len;
@@ -1436,6 +1440,17 @@ edit_reset(char *buf, size_t len)
es->cursor = undo->cursor = 0;
es->winleft = undo->winleft = 0;
+ calc_winsize();
+ win = 0;
+ morec = ' ';
+ holdlen = 0;
+}
+
+static void
+calc_winsize(void)
+{
+ const char *p;
+
cur_col = pwidth = promptlen(prompt, &p);
prompt_skip = p - prompt;
if (pwidth > x_cols - 3 - MIN_EDIT_SPACE) {
@@ -1452,9 +1467,6 @@ edit_reset(char *buf, size_t len)
(void) memset(wbuf[0], ' ', wbuf_len);
(void) memset(wbuf[1], ' ', wbuf_len);
winwidth = x_cols - pwidth - 3;
- win = 0;
- morec = ' ';
- holdlen = 0;
}
/*
@@ -2300,4 +2312,42 @@ isu8cont(unsigned char c)
{
return !Flag(FVISHOW8) && (c & (0x80 | 0x40)) == 0x80;
}
+
+static void
+x_vi_resize(void)
+{
+ int cur = 0, col = 0;
+ int cr_done = 0, cleared = 0;
+
+#ifndef SMALL
+ if (cur_term != NULL) {
+ if (carriage_return != NULL &&
+ tputs(carriage_return, 1, x_putc) != ERR)
+ cr_done = 1;
+ if (clr_eos != NULL &&
+ tputs(clr_eos, 1, x_putc) != ERR)
+ cleared = 1;
+ }
+#endif
+ if (!cr_done)
+ x_putc('\r');
+ if (!cleared) {
+ x_putc('\033');
+ x_putc('[');
+ x_putc('J');
+ }
+
+ calc_winsize();
+
+ while (cur < es->linelen)
+ col = newcol((unsigned char) es->cbuf[cur++], col);
+ if (col <= winwidth)
+ es->winleft = 0;
+ else if (outofwin())
+ rewindow();
+
+ redraw_line(0, 0);
+ refresh_line(insert != 0);
+ x_flush();
+}
#endif /* VI */
diff --git regress/bin/ksh/edit/edit.c regress/bin/ksh/edit/edit.c
index 7b49f371ab6..785dc5a251b 100644
--- regress/bin/ksh/edit/edit.c
+++ regress/bin/ksh/edit/edit.c
@@ -16,6 +16,7 @@
*/
#include <sys/wait.h>
+#include <sys/ioctl.h>
#include <err.h>
#include <errno.h>
@@ -49,6 +50,7 @@ main(int argc, char *argv[])
ssize_t n;
size_t nin, nprompt, nread, nwrite;
int c, nready, ptyfd, readprompt, ret, status, timeout;
+ int pending_resize, pending_cols, pending_quiet, pending_post;
while ((c = getopt(argc, argv, "p:")) != -1) {
switch (c) {
@@ -96,14 +98,20 @@ main(int argc, char *argv[])
}
nprompt = nread = nwrite = ret = 0;
+ pending_resize = pending_cols = pending_quiet = pending_post = 0;
readprompt = 1;
while (!gotsig) {
pfd.fd = ptyfd;
- if (!readprompt && nwrite < nin)
+ if (pending_resize || pending_post) {
+ pfd.events = POLLIN;
+ timeout = WRTIM;
+ } else if (!readprompt && nwrite < nin) {
pfd.events = POLLOUT;
- else
+ timeout = WRTIM;
+ } else {
pfd.events = POLLIN;
- timeout = readprompt ? PRTIM : WRTIM;
+ timeout = readprompt ? PRTIM : WRTIM;
+ }
nready = poll(&pfd, 1, timeout);
if (nready == -1) {
if (errno == EINTR)
@@ -111,6 +119,22 @@ main(int argc, char *argv[])
err(1, "poll");
}
if (nready == 0) {
+ if (pending_resize) {
+ if (++pending_quiet >= 2) {
+ ws.ws_col = pending_cols;
+ if (ioctl(ptyfd, TIOCSWINSZ, &ws) == -1)
+ err(1, "ioctl TIOCSWINSZ");
+ kill(pid, SIGWINCH);
+ pending_resize = pending_cols = 0;
+ pending_quiet = 0;
+ pending_post = 1;
+ }
+ continue;
+ }
+ if (pending_post) {
+ pending_post = 0;
+ continue;
+ }
if (timeout == PRTIM) {
warnx("timeout waiting from prompt");
ret = 1;
@@ -136,6 +160,28 @@ main(int argc, char *argv[])
readprompt = 0;
}
} else if (pfd.revents & POLLOUT) {
+ if (in[nwrite] == '\0' && nwrite + 3 < nin &&
+ in[nwrite + 1] == 'R' &&
+ in[nwrite + 2] == 'S' &&
+ in[nwrite + 3] >= '0' && in[nwrite + 3] <= '9') {
+ size_t i = nwrite + 3;
+ int cols = 0, nd = 0;
+
+ while (i < nin && nd < 3 &&
+ in[i] >= '0' && in[i] <= '9') {
+ cols = cols * 10 + (in[i] - '0');
+ i++;
+ nd++;
+ }
+ if (nd > 0 && (i == nin ||
+ in[i] < '0' || in[i] > '9') &&
+ cols > 0) {
+ pending_resize = 1;
+ pending_cols = cols;
+ nwrite = i;
+ continue;
+ }
+ }
if (strchr(linefeed, in[nwrite]) != NULL)
readprompt = 1;
@@ -143,6 +189,8 @@ main(int argc, char *argv[])
if (n == -1)
err(1, "write");
nwrite += n;
+ if (pending_resize)
+ pending_quiet = 0;
}
}
close(ptyfd);
diff --git regress/bin/ksh/edit/emacs.sh regress/bin/ksh/edit/emacs.sh
index abd664664bb..6ae4184e928 100644
--- regress/bin/ksh/edit/emacs.sh
+++ regress/bin/ksh/edit/emacs.sh
@@ -52,6 +52,30 @@ testseq "z\0002\0363\0277\0277\0277" " # z\b\0363\0277\0277\0277z\b"
testseq "z\0002\0364\0200\0200\0200" " # z\b\0364\0200\0200\0200z\b"
testseq "z\0002\0364\0217\0277\0277" " # z\b\0364\0217\0277\0277z\b"
+# ASCII resize: cols=1/11/12
+testseq "aaaaaaaaaabbbbbbbbbb\0001\000RS1" \
+ " # aaaaaaaaaabbbbbbbbbb\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J\r # aaaaaaa>\b\b\b\b\b\b\b\b"
+testseq "aaaaaaaaaabbbbbbbbbb\003310\0002\000RS11" \
+ " # aaaaaaaaaabbbbbbbbbb\b\b\b\b\b\b\b\b\b\b\r\033[J\raaaaabbbbb*\b\b\b\b\b\b"
+testseq "aaaaaaaaaabbbbbbbbbb\000RS12" \
+ " # aaaaaaaaaabbbbbbbbbb\r\033[J\rbbbbb <\b\b\b\b\b\b"
+
+# ASCII resize: cols=13, cursor -1/0/+1
+testseq "aaaaaaaaaabbbbbbbbbb\003313\0002\000RS13" \
+ " # aaaaaaaaaabbbbbbbbbb\b\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J\r # aaaaaaaa>\b\b"
+testseq "aaaaaaaaaabbbbbbbbbb\003312\0002\000RS13" \
+ " # aaaaaaaaaabbbbbbbbbb\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J\r # aaaaaaaa>\b"
+testseq "aaaaaaaaaabbbbbbbbbb\003311\0002\000RS13" \
+ " # aaaaaaaaaabbbbbbbbbb\b\b\b\b\b\b\b\b\b\b\b\r\033[J\raaaaaabbbbb*\b\b\b\b\b\b\b"
+
+# ASCII resize: cols=79/80/81
+testseq "aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc\0001\000RS79" \
+ " # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc\rbbbbbbbbbbbbccccccccccccccccccccccccc <\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J\r # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccc>\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
+testseq "aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc\0001\000RS80" \
+ " # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc\rbbbbbbbbbbbbccccccccccccccccccccccccc <\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
+testseq "aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc\0001\000RS81" \
+ " # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc\rbbbbbbbbbbbbccccccccccccccccccccccccc <\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J\r # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
+
# insertion of incomplete UTF-8
testseq "z\0002\0302\0006" " # z\b\0302z\bz"
testseq "z\0002\0377\0006" " # z\b\0377z\bz"
diff --git regress/bin/ksh/edit/vi.sh regress/bin/ksh/edit/vi.sh
index a4baa9ccf60..b32c9f7a566 100644
--- regress/bin/ksh/edit/vi.sh
+++ regress/bin/ksh/edit/vi.sh
@@ -201,3 +201,27 @@ testseq "(x)\00330%hrc" " # (x)\b\b\b(x\bc\b"
# ^R: Redraw.
testseq "test\0033h\0022" " # test\b\b\r\r\n # test\b\b"
+
+# ASCII resize: cols=1/11/12
+testseq "aaaaaaaaaabbbbbbbbbb\0033hhhhhhhhhhhhhhhhhhh\000RS1" \
+ " # aaaaaaaaaabbbbbbbbbb\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J# aaaaaaa >\r# "
+testseq "aaaaaaaaaabbbbbbbbbb\0033hhhhhhhhh\000RS11" \
+ " # aaaaaaaaaabbbbbbbbbb\b\b\b\b\b\b\b\b\b\b\r\033[J# aaabbbb +\b\b\b\b\b\b"
+testseq "aaaaaaaaaabbbbbbbbbb\0033\000RS12" \
+ " # aaaaaaaaaabbbbbbbbbb\b\r\033[J# bbbb <\b\b\b\b\b\b"
+
+# ASCII resize: cols=13, cursor -1/0/+1
+testseq "aaaaaaaaaabbbbbbbbbb\0033hhhhhhhhhhhhh\000RS13" \
+ " # aaaaaaaaaabbbbbbbbbb\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J # aaaaaaa >\b\b\b"
+testseq "aaaaaaaaaabbbbbbbbbb\0033hhhhhhhhhhhh\000RS13" \
+ " # aaaaaaaaaabbbbbbbbbb\b\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J # aaaaaab +\b\b\b\b\b\b"
+testseq "aaaaaaaaaabbbbbbbbbb\0033hhhhhhhhhhh\000RS13" \
+ " # aaaaaaaaaabbbbbbbbbb\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J # aaaaabb +\b\b\b\b\b\b"
+
+# ASCII resize: cols=79/80/81
+testseq "aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc\0033hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\000RS79" \
+ " # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccc\r # bbbbbbbbbbbbbcccccccccccccccccccccccc <\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bc\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\baaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccc >\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccc >\r # "
+testseq "aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc\0033hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\000RS80" \
+ " # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccc\r # bbbbbbbbbbbbbcccccccccccccccccccccccc <\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bc\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\baaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccc >\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
+testseq "aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc\0033hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\000RS81" \
+ " # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccc\r # bbbbbbbbbbbbbcccccccccccccccccccccccc <\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bc\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\baaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccc >\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\033[J # aaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccc >\r # "
--
2.52.0
bin/ksh: fix emacs/vi mode using wrong terminal width