diff --git a/NEWS b/NEWS index ae358ac5da13..1b3ec19e813e 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,11 @@ Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library. - Fixed command line redrawing on resizing the window with --multiline off. +- Multiline editing is now automatically disabled if and when the TERM + environment variable is unset, not exported, or set to a terminal type + that does not support the necessary operations. It is automatically + reenabled when the TERM variable is corrected and --multiline is on. + 2023-04-08: - Fixed a termcap(5) detection bug that broke multiline editing on FreeBSD. diff --git a/src/cmd/ksh93/edit/edit.c b/src/cmd/ksh93/edit/edit.c index 0c88ebcc1b51..275d170cac07 100644 --- a/src/cmd/ksh93/edit/edit.c +++ b/src/cmd/ksh93/edit/edit.c @@ -45,8 +45,8 @@ #include "edit.h" #include "shlex.h" -static char *CURSOR_UP = Empty; /* move cursor up one line */ -static char *ERASE_EOS = Empty; /* erase to end of screen */ +static char *cursor_up; /* move cursor up one line */ +static char *erase_eos; /* erase to end of screen */ #if _tput_terminfo #define E_MULTILINE ep->e_multiline #define TPUT_CURSOR_UP "cuu1" @@ -415,7 +415,7 @@ void ed_ringbell(void) #if SHOPT_ESH || SHOPT_VSH -#ifdef _pth_tput +#if defined(_pth_tput) && (_tput_terminfo || _tput_termcap) /* * Get or update a tput (terminfo or termcap) capability string. */ @@ -427,19 +427,27 @@ static void get_tput(char *tp, char **cpp) sh_offoption(SH_RESTRICTED); sh_offoption(SH_VERBOSE); sh_offoption(SH_XTRACE); - sfprintf(sh.strbuf,".sh.value=$(" _pth_tput " %s 2>/dev/null)",tp); + sfprintf(sh.strbuf,".sh.value=${ " _pth_tput " %s 2>/dev/null;}",tp); sh_trap(sfstruse(sh.strbuf),0); if((cp = nv_getval(SH_VALNOD)) && (!*cpp || strcmp(cp,*cpp)!=0)) { - if(*cpp && *cpp!=Empty) + if(*cpp) free(*cpp); - *cpp = *cp ? sh_strdup(cp) : Empty; + *cpp = *cp ? sh_strdup(cp) : NULL; + } + else + { + if(*cpp) + free(*cpp); + *cpp = NULL; } nv_unset(SH_VALNOD); sh.options = o; sigrelease(SIGINT); } -#endif /* _pth_tput */ +#else +#define get_tput(tp,cpp) /* empty */ +#endif /* defined(_pth_tput) && (_tput_terminfo || _tput_termcap) */ /* ED_SETUP( max_prompt_size ) * @@ -620,6 +628,28 @@ void ed_setup(Edit_t *ep, int fd, int reedit) if(pp-ep->e_prompt > qlen) ep->e_plen = pp - ep->e_prompt - qlen; *pp = 0; + if(E_MULTILINE) + { + static char *oldterm; + Namval_t *np = nv_search("TERM",sh.var_tree,0); + char *term = NULL; + if(nv_isattr(np,NV_EXPORT)) + term = nv_getval(np); + if(!term) + term = ""; + if(!oldterm || strcmp(term,oldterm)) + { + get_tput(TPUT_CURSOR_UP,&cursor_up); + get_tput(TPUT_ERASE_EOS,&erase_eos); + if(oldterm) + free(oldterm); + oldterm = sh_strdup(term); + } + if(cursor_up && erase_eos) + ep->e_wsize = MAXLINE - (ep->e_plen + 1); + else + ep->e_multiline = 0; + } if(!E_MULTILINE && (ep->e_wsize -= ep->e_plen) < 7) { int shift = 7-ep->e_wsize; @@ -648,21 +678,6 @@ void ed_setup(Edit_t *ep, int fd, int reedit) sfset(sfstderr,SF_READ,1); sfwrite(sfstderr,ep->e_outptr,0); ep->e_eol = reedit; - if(E_MULTILINE) - { -#ifdef _pth_tput - char *term; - if(!ep->e_term) - ep->e_term = nv_search("TERM",sh.var_tree,0); - if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)e_termname) && strcmp(term,ep->e_termname)) - { - get_tput(TPUT_CURSOR_UP,&CURSOR_UP); - get_tput(TPUT_ERASE_EOS,&ERASE_EOS); - strcopy(ep->e_termname,term); - } -#endif /* _pth_tput */ - ep->e_wsize = MAXLINE - (ep->e_plen+1); - } if(ep->e_default && (pp = nv_getval(ep->e_default))) { n = strlen(pp); @@ -730,6 +745,7 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) int n, newsize; char *cp; sh_winsize(NULL,&newsize); + ed_putchar(ep,'\r'); /* * Try to move cursor to start of first line and pray it works... it's very * failure-prone if the window size changed, especially on modern terminals @@ -737,13 +753,17 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) */ if(E_MULTILINE) { - n = (ep->e_plen + ep->e_cur) / newsize; - while(n--) - ed_putstring(ep,CURSOR_UP); + n = (ep->e_plen + ep->e_peol) / ep->e_winsz; + while(n-- > 0) + ed_putstring(ep,cursor_up); + /* clear the current command line */ + ed_putstring(ep,erase_eos); + } + else + { + ed_nputchar(ep,newsize-1,' '); + ed_putchar(ep,'\r'); } - ed_putchar(ep,'\r'); - /* clear the current command line */ - ed_putstring(ep,ERASE_EOS); ed_flush(ep); /* show any buffered 'set -b' job notification(s) */ if(sh.notifybuf && (cp = sfstruse(sh.notifybuf)) && *cp) @@ -1127,7 +1147,7 @@ int ed_setcursor(Edit_t *ep,genchar *physical,int old,int new,int first) { int n,pline,plen=ep->e_plen; for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--) - ed_putstring(ep,CURSOR_UP); + ed_putstring(ep,cursor_up); pline = plen/(ep->e_winsz+1); if(newpos.line <= pline) plen -= pline*(ep->e_winsz+1); @@ -1150,7 +1170,7 @@ int ed_setcursor(Edit_t *ep,genchar *physical,int old,int new,int first) ed_putchar(ep,physical[m++]); } ed_nputchar(ep,n,' '); - ed_putstring(ep,CURSOR_UP); + ed_putstring(ep,cursor_up); } } } diff --git a/src/cmd/ksh93/features/cmds b/src/cmd/ksh93/features/cmds index fe0f90e7e5ea..2ba10697f4cd 100644 --- a/src/cmd/ksh93/features/cmds +++ b/src/cmd/ksh93/features/cmds @@ -10,7 +10,8 @@ tput_terminfo note{ does tput support terminfo codes }end run{ export TERM=xterm case ${_pth_tput-} in \"/*/tput\") - tput=`echo "${_pth_tput}" | sed 's/^"//; s/"$//'` + tput=${_pth_tput#\"} + tput=${tput%\"} if "$tput" ed >/dev/null 2>&1 && "$tput" cuu1 >/dev/null 2>&1 then echo '#define _tput_terminfo 1 /* tput supports terminfo codes */' @@ -25,7 +26,8 @@ tput_termcap note{ does tput support termcap codes }end run{ export TERM=xterm case ${_pth_tput-} in \"/*/tput\") - tput=`echo "${_pth_tput}" | sed 's/^"//; s/"$//'` + tput=${_pth_tput#\"} + tput=${tput%\"} if "$tput" cd >/dev/null 2>&1 && "$tput" up >/dev/null 2>&1 then echo '#define _tput_termcap 1 /* tput supports termcap codes */' diff --git a/src/cmd/ksh93/include/edit.h b/src/cmd/ksh93/include/edit.h index 0a8f256842b0..8b5346b33d7f 100644 --- a/src/cmd/ksh93/include/edit.h +++ b/src/cmd/ksh93/include/edit.h @@ -141,8 +141,6 @@ typedef struct edit int e_winsz; /* columns in window */ Edpos_t e_curpos; /* cursor line and column */ Namval_t *e_default; /* variable containing default value */ - Namval_t *e_term; /* TERM variable */ - char e_termname[80]; /* terminal name */ #if SHOPT_EDPREDICT Histmatch_t **hlist; Histmatch_t *hfirst; diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1 index b61322c89059..fc5af17cb4bd 100644 --- a/src/cmd/ksh93/sh.1 +++ b/src/cmd/ksh93/sh.1 @@ -7779,11 +7779,23 @@ Same as .B multiline The built-in editors will use multiple lines on the screen for lines that are longer than the width of the screen. This may not work -for all terminals. The option is forced off on systems with neither -.B terminfo (5) +for all terminals. +The shell uses the system's +.BR tput (1) +command to obtain the terminal escape codes for the necessary operations. +Multi-line editing is disabled if this fails. +On most systems, setting the +.B TERM +variable to your terminal's type and exporting it corrects this situation. +The +.B multiline +option is permanently forced off on systems whose +.BR tput (1) +command supports neither +.BR terminfo (5) nor -.B termcap (5) -support. +.BR termcap (5) +capability names. .TP 8 .B noclobber Same as diff --git a/src/cmd/ksh93/tests/pty.sh b/src/cmd/ksh93/tests/pty.sh index 230f2b4e6045..bb16c67216b3 100755 --- a/src/cmd/ksh93/tests/pty.sh +++ b/src/cmd/ksh93/tests/pty.sh @@ -804,7 +804,8 @@ w :\E_ r ^:test-2: : One\\ "Two Three"\$'Four Five'\.mp3\r\n$ ! -((SHOPT_VSH)) && tst $LINENO <<"!" +# needs non-dumb terminal for multiline editing +((SHOPT_VSH)) && TERM=vt100 tst $LINENO <<"!" L crash when entering comment into history file (vi mode) # https://github.com/att/ast/issues/798 @@ -857,7 +858,8 @@ w $'`/dev\t r ^:test-5: \$'`/dev[[:blank:]]*\r\n$ ! -((SHOPT_ESH)) && VISUAL=emacs tst $LINENO <<"!" +# needs non-dumb terminal for multiline editing +((SHOPT_ESH)) && VISUAL=emacs TERM=vt100 tst $LINENO <<"!" L emacs: keys with repeat parameters repeat extra steps # https://github.com/ksh93/ksh/issues/292 @@ -1083,7 +1085,8 @@ w p\E[AT u CORRECT ! -((SHOPT_ESH)) && mkdir -p fullcomplete/foe && VISUAL=emacs tst $LINENO <<"!" +# needs non-dumb terminal for multiline editing +((SHOPT_ESH)) && mkdir -p fullcomplete/foe && VISUAL=emacs TERM=vt100 tst $LINENO <<"!" L full-word completion in emacs mode # https://github.com/ksh93/ksh/pull/580 @@ -1099,7 +1102,8 @@ w true fullcomplete/foi\cb* r ^:test-3: true fullcomplete/foi\r\n ! -((SHOPT_VSH)) && mkdir -p fullcomplete/fov && VISUAL=vi tst $LINENO <<"!" +# needs non-dumb terminal for multiline editing +((SHOPT_VSH)) && mkdir -p fullcomplete/fov && VISUAL=vi TERM=vt100 tst $LINENO <<"!" L full-word completion in vi mode # https://github.com/ksh93/ksh/pull/580