diff --git a/NEWS b/NEWS index 9e91f5431..5b191a86f 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,9 @@ Any uppercase BUG_* names are modernish shell bug IDs. substitution after entering: '`something or generate a spurious 'end of file unexpected' syntax error after entering: '$(something. +- Fixed bug where tab completion stopped working for arguments following a + quoted string with an escaped backslash in the form $'foo\'bar'. + 2022-06-04: - Added a new --functrace long-form shell option which causes the -x/--xtrace diff --git a/src/cmd/ksh93/edit/completion.c b/src/cmd/ksh93/edit/completion.c index b22af55fb..727f1294d 100644 --- a/src/cmd/ksh93/edit/completion.c +++ b/src/cmd/ksh93/edit/completion.c @@ -105,12 +105,17 @@ static char *overlaid(register char *str,register const char *newstr,int nocase) /* * returns pointer to beginning of expansion and sets type of expansion + * + * Detects variable expansions, command substitutions, and three quoting styles: + * 1. '...' inquote=='\'', dollarquote==0; no special characters + * 2. $'...' inquote=='\'', dollarquote==1; skips \. + * 3. "..." inquote=='"', dollarquote==0; skips \., $..., ${...}, $(...), `...` */ static char *find_begin(char outbuff[], char *last, int endchar, int *type) { register char *cp=outbuff, *bp, *xp; - register int c,inquote = 0, inassign=0; - int mode=*type; + char inquote = 0, dollarquote = 0, inassign = 0; + int mode=*type, c; bp = outbuff; *type = 0; mbinit(); @@ -127,10 +132,10 @@ static char *find_begin(char outbuff[], char *last, int endchar, int *type) break; } if(inquote==c) - inquote = 0; + inquote = dollarquote = 0; break; case '\\': - if(inquote != '\'') + if(inquote != '\'' || dollarquote) mbchar(cp); break; case '$': @@ -177,6 +182,8 @@ static char *find_begin(char outbuff[], char *last, int endchar, int *type) if(*(cp=xp)!=')') bp = xp; } + else if(c=='\'' && !inquote) + dollarquote = 1; break; case '`': if(inquote=='\'') @@ -214,7 +221,11 @@ static char *find_begin(char outbuff[], char *last, int endchar, int *type) } } if(inquote && *bp==inquote) - *type = *bp++; + { + /* set special type -1 for $'...' */ + *type = dollarquote ? -1 : inquote; + bp++; + } return(bp); } @@ -360,7 +371,11 @@ int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count) com = sh_argbuild(&narg,comptr,0); /* special handling for leading quotes */ if(begin>outbuff && (begin[-1]=='"' || begin[-1]=='\'')) - begin--; + { + begin--; + if(var == -1) /* $'...' */ + begin--; /* also remove initial dollar */ + } } sh_offstate(SH_COMPLETE); /* allow a search to be aborted */ diff --git a/src/cmd/ksh93/tests/pty.sh b/src/cmd/ksh93/tests/pty.sh index bf6fb9ede..0a8d2dbed 100755 --- a/src/cmd/ksh93/tests/pty.sh +++ b/src/cmd/ksh93/tests/pty.sh @@ -821,11 +821,12 @@ r \thist -lnN 1\r\n$ ((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!" L tab completion while expanding ${.sh.*} variables # https://github.com/att/ast/issues/1461 +# also tests $'...' string: https://github.com/ksh93/ksh/issues/462 d 15 p :test-1: -w test \$\{.sh.level\t -r ^:test-1: test \$\{.sh.level\}\r\n$ +w test \$'foo\\'bar' \$\{.sh.level\t +r ^:test-1: test \$'foo\\'bar' \$\{.sh.level\}\r\n$ ! ((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"