1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

Fix completion following $'foo\'bar'

On an interactive shell in emacs or vi, type a command with a $'…'
quoted string that contains a backslash-escaped single quote, like:

    $ true $'foo\'bar' ▁

Then begin to type the name of a file present in the current
working directory and press tab. Nothing happens as completion
fails to work.

The completion code does not recognise $'…' strings. Instead, it
parses them as '…' strings in which there are no backslash escapes,
so it considers the last ' to open a second quoted string which is
not terminated.

Plus, when replacing a $'…' string with a (backslash-escaped)
completed string, the initial '$' is not replaced:

    $ $'/etc/hosts<Tab>
    $ $/etc/hosts

src/cmd/ksh93/edit/completion.c:
- find_begin():
  - Learn how to recognise $'…' strings. A new local dollarquote
    flag variable is used to distinguish them from regular '…'
    strings. The difference is that backslash escapes (and only
    those) should be recognised as in "…".
  - Set a special type -1 for $'…' as the caller will need a way
    to distinguish those from '…'.
- ed_expand(): When replacing a quoted string, remove an extra
  initial character (being the $ in $') if the type set by
  find_begin() is -1.

Resolves: https://github.com/ksh93/ksh/issues/462
This commit is contained in:
Martijn Dekker 2022-06-06 02:46:57 +01:00
parent 7a5423dfb6
commit 80f8cc497f
3 changed files with 27 additions and 8 deletions

3
NEWS
View file

@ -9,6 +9,9 @@ Any uppercase BUG_* names are modernish shell bug IDs.
substitution after entering: '`something<TAB> or generate a spurious
'end of file unexpected' syntax error after entering: '$(something<TAB>.
- 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

View file

@ -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 */

View file

@ -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 <<"!"