1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-13 03:32:24 +00:00

Fix bell character handling when redrawing command line (#250)

To set a window title in bash and zsh, the $PS1 prompt can be set
with the title placed between $'\E]0;' and $'\a':

set -o emacs    # Or vi mode
typeset -A fmt=(
        [start_title]=$'\E]0;'
        [end_title]=$'\a'
)
PS1="${fmt[start_title]}$(hostname): $(uname)${fmt[end_title]}\$ "

This also works in ksh unless the shell receives SIGWINCH. With a
$PS1 that sets a window title, the prompt breaks until two
interrupts are received. This is caused by ed_setup() skipping
$'\a' (the bell character) when setting up the e_prompt buffer
which is an edited version of the final line of the PS1 prompt for
use when redrawing the command line.

One fix would be to avoid cutting out the bell character. But if
the prompt contains a bell, we only want the terminal to beep when
a new prompt is printed, and not upon refreshing the command line,
e.g. when receiving SIGWINCH or pressing Ctrl+L.

To avoid the problem, this commit adds code that cuts out sequences
of the form ESC ] <number> ; <text> BELL from the prompt redraw
buffer altogether. They are not needed there because these
sequences will already have taken effect when the full prompt was
printed by io_prompt().

This commit also adds a tweak that should improve the recognition
of other escape sequences to count their length.

src/cmd/ksh93/edit/edit.c: ed_setup():
- When preparing the e_prompt buffer, cut out dtterm/xterm
  Operating System Commands that set window/icon title, etc.
  See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
- When counting the length of escape sequences in that part of PS1,
  try to recognize some more types of sequences. These changes are
  part of a ksh2020 patch: https://github.com/att/ast/issues/399

src/cmd/ksh93/sh.1:
- Document that any '!' in escape sequences in the PS1 prompt needs
  to be changed to '!!'. To avoid breaking compatibility, this
  requirement is documented instead of backporting the changes to
  io_prompt() from https://github.com/att/ast/issues/399 which try
  to remove that requirement for specific escape sequences.

Co-authored-by: Martijn Dekker <martijn@inlv.org>
This commit is contained in:
Johnothan King 2021-04-05 00:06:53 -07:00 committed by GitHub
parent ee34a96b8f
commit 56b530c433
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 7 deletions

4
NEWS
View file

@ -5,6 +5,10 @@ Any uppercase BUG_* names are modernish shell bug IDs.
2021-04-04:
- A bug was fixed that caused a broken prompt display upon redrawing the
command line if the last line of the prompt includes an xterm escape
sequence that is terminated by $'\a' (the bell character).
- Harden readonly variables. Readonly variables or arrays no longer allow
attribute changes which would otherwise allow their value to be altered.
Expanded support for readonly variables within multidimensional arrays.

View file

@ -651,6 +651,10 @@ void ed_setup(register Edit_t *ep, int fd, int reedit)
ep->e_winsz = ep->e_wsize+2;
ep->e_crlf = 1;
ep->e_plen = 0;
/*
* Prepare e_prompt buffer for use when redrawing the command line.
* Use only the last line of the potentially multi-line prompt.
*/
pp = ep->e_prompt;
ppmax = pp+PRSIZE-1;
*pp++ = '\r';
@ -661,9 +665,40 @@ void ed_setup(register Edit_t *ep, int fd, int reedit)
case ESC:
{
int skip=0;
if(*last == ']')
{
/*
* Cut out dtterm/xterm Operating System Commands that set window/icon title, etc.
* See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
*/
char *cp = last + 1;
while(*cp >= '0' && *cp <= '9')
cp++;
if(*cp++ == ';')
{
while(c = *cp++)
{
if(c == '\a') /* legacy terminator */
break;
if(c == ESC && *cp == '\\') /* recommended terminator */
{
cp++;
break;
}
}
if(!c)
break;
last = cp;
continue;
}
}
/*
* Try to add the length of included escape sequences to qlen
* which is subtracted from the physical length of the prompt.
*/
ep->e_crlf = 0;
if(pp<ppmax)
*pp++ = c;
*pp++ = ESC;
for(n=1; c = *last++; n++)
{
if(pp < ppmax)
@ -675,9 +710,11 @@ void ed_setup(register Edit_t *ep, int fd, int reedit)
skip = 0;
continue;
}
if(n>1 && c==';')
if(n==3 && (c=='?' || c=='!'))
continue;
else if(n>1 && c==';')
skip = 1;
else if(n>2 || (c!= '[' && c!= ']'))
else if(n>2 || (c!='[' && c!=']' && c!='('))
break;
}
if(c==0 || c==ESC || c=='\r')

View file

@ -108,7 +108,7 @@ typedef struct edit
char *e_outptr; /* pointer to position in output buffer */
char *e_outlast; /* pointer to end of output buffer */
genchar *e_inbuf; /* pointer to input buffer */
char *e_prompt; /* pointer to buffer containing the prompt */
char *e_prompt; /* pointer to trimmed final line of PS1 prompt, used when redrawing command line */
genchar *e_killbuf; /* pointer to delete buffer */
char e_search[SEARCHSIZE]; /* search string */
genchar *e_physbuf; /* temporary workspace buffer */

View file

@ -2122,9 +2122,12 @@ if executing under
.TP
.SM
.B PS1
The value of this variable is expanded for parameter
expansion, command substitution, and arithmetic substitution to define the
primary prompt string which by default is
Every time a new command line is started on an interactive shell,
the value of this variable is expanded to resolve
backslash escaping, parameter expansion, command substitution,
and arithmetic substitution.
The result defines the primary prompt string for that command line.
The default is
.RB `` "$ \|\|\|" ''.
The character
.B !
@ -2138,6 +2141,12 @@ Two successive occurrences of
will produce a single
.B !
when the prompt string is printed.
Note that any terminal escape sequences used in the
.B PS1
prompt thus need every instance of
.B !
in them to be changed to
.BR !! .
.TP
.SM
.B PS2