diff --git a/NEWS b/NEWS index dcb02f114..44fdd3665 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,13 @@ For full details, see the git log at: https://github.com/ksh93/ksh Any uppercase BUG_* names are modernish shell bug IDs. +2021-02-17: + +- Emacs mode fixes: + 1. Erasing a backslash while doing a reverse search (^R) no longer deletes + extra characters. + 2. The backslash now escapes a subsequent interrupt (^C) as documented. + 2021-02-15: - Fixed a regression introduced by ksh93 (was not in ksh88): an empty 'case' diff --git a/src/cmd/ksh93/edit/edit.c b/src/cmd/ksh93/edit/edit.c index 0e85c671e..895a96ba6 100644 --- a/src/cmd/ksh93/edit/edit.c +++ b/src/cmd/ksh93/edit/edit.c @@ -1068,7 +1068,7 @@ int ed_getchar(register Edit_t *ep,int mode) { ed_flush(ep); ep->e_inmacro = 0; - /* The while is necessary for reads of partial multbyte chars */ + /* The while is necessary for reads of partial multibyte chars */ *ep->e_vi_insert = (mode==-2); if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0) n = putstack(ep,readin,n,1); diff --git a/src/cmd/ksh93/edit/emacs.c b/src/cmd/ksh93/edit/emacs.c index b5e483645..8b39d4483 100644 --- a/src/cmd/ksh93/edit/emacs.c +++ b/src/cmd/ksh93/edit/emacs.c @@ -281,11 +281,12 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit) #endif /* ESH_NFIRST */ } ep->CntrlO = 0; - while ((c = ed_getchar(ep->ed,0)) != (-1)) + while ((c = ed_getchar(ep->ed,backslash)) != (-1)) { if (backslash) { - backslash = 0; + if(c!='\\') + backslash = 0; if (c==usrerase||c==usrkill||(!print(c) && (c!='\r'&&c!='\n'))) { @@ -1298,20 +1299,35 @@ static void search(Emacs_t* ep,genchar *out,int direction) beep(); goto restore; } - if (i == '\\') + if (!sh_isoption(SH_NOBACKSLCTRL)) { - string[sl++] = '\\'; - string[sl] = '\0'; - cur = sl; - draw(ep,APPEND); - i = ed_getchar(ep->ed,1); - string[--sl] = '\0'; + while (i == '\\') + { + /* + * Append the backslash to the command line, then escape + * the next control character. Repeat the loop if the + * next input is another backslash (otherwise every + * second backslash is skipped). + */ + string[sl++] = '\\'; + string[sl] = '\0'; + cur = sl; + draw(ep,APPEND); + i = ed_getchar(ep->ed,1); + + /* Backslashes don't affect newlines */ + if (i == '\n' || i == '\r') + goto skip; + else if (i == usrerase || !print(i)) + string[--sl] = '\0'; + } } string[sl++] = i; string[sl] = '\0'; cur = sl; draw(ep,APPEND); } + skip: i = genlen(string); if(ep->prevdirection == -2 && i!=2 || direction!=1) diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index ce73daf45..14afcfb78 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -20,7 +20,7 @@ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_SVER "1.0.0-alpha" /* semantic version number: https://semver.org */ -#define SH_RELEASE_DATE "2021-02-15" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2021-02-17" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */ diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1 index 9e6e97abf..040642d2f 100644 --- a/src/cmd/ksh93/sh.1 +++ b/src/cmd/ksh93/sh.1 @@ -4969,7 +4969,7 @@ If the shell option is on (which is the default setting), this escapes the next character. Editing characters, the user's erase, kill and interrupt (normally -.BR ^? ) +.BR ^C ) characters may be entered in a command line or in a search string if preceded by a diff --git a/src/cmd/ksh93/tests/pty.sh b/src/cmd/ksh93/tests/pty.sh index 7014e4951..3b282be9a 100755 --- a/src/cmd/ksh93/tests/pty.sh +++ b/src/cmd/ksh93/tests/pty.sh @@ -640,5 +640,35 @@ r ^/dev/null\r\n$ r ^:test-2: ! +# err_exit # +((SHOPT_ESH)) && [[ -o ?backslashctrl ]] && tst $LINENO <<"!" +L nobackslashctrl in emacs + +d 10 +w set -o emacs --nobackslashctrl + +# --nobackslashctrl shouldn't be ignored by reverse search +p :test-2: +w \cR\\\cH\cH +r ^:test-2: \r\n$ +! + +# err_exit # +((SHOPT_ESH)) && tst $LINENO <<"!" +L emacs backslash escaping + +d 10 +w set -o emacs + +# Test for too many backslash deletions in reverse-search mode +p :test-2: +w \cRset\\\\\\\\\cH\cH\cH\cH\cH +r ^:test-2: set -o emacs$ + +# \ should escape the interrupt character (usually Ctrl+C) +w true \\\cC +r true \^C +! + # ====== exit $((Errors<125?Errors:125))