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

Parse quotes when extracting words from command history (#291)

This avoids splitting on quoted whitespace when extracting words
from the command history using the emacs M-. or vi _ command.

Example: if the prior command is

$ ls Stairway\ To\ Heaven.mp3

then, M-. in Emacs editing mode (and _ in vi mode) now inserts
Stairway\ To\ Heaven.mp3 instead of Heaven.mp3. The behavior is
similar for 'Stairway To Heaven.mp3' and "Stairway To Heaven.mp3".

src/cmd/ksh93/edit/history.c: hist_word():
- Skip over single-quoted and double-quoted strings and
  backslash-escaped characters.

src/cmd/ksh93/tests/pty.sh:
- Add regression test for this feature in vi mode. Since emacs and
  vi both use the same code for this, that should be good enough.

Co-authored-by: Martijn Dekker <martijn@inlv.org>
This commit is contained in:
Govind Kamat 2021-04-30 11:45:50 -07:00 committed by Martijn Dekker
parent d087b031f0
commit 7439e3dffe
3 changed files with 36 additions and 4 deletions

5
NEWS
View file

@ -5,6 +5,11 @@ Any uppercase BUG_* names are modernish shell bug IDs.
2021-04-30: 2021-04-30:
- The emacs 'ESC .' (M-.) and vi '_' commands now take shell quoting into
account when repeating a word from the previous command line. For example, if
the previous command is 'ls Stairway\ To\ Heaven.mp3', then they now insert
'Stairway\ To\ Heaven.mp3' instead of 'Heaven.mp3'. Thanks to Govind Kamat.
- Fixed a bug introduced on 2020-09-05 that caused "echo ${var:+'{}'}" - Fixed a bug introduced on 2020-09-05 that caused "echo ${var:+'{}'}"
to be misparsed. to be misparsed.

View file

@ -1057,6 +1057,8 @@ int hist_copy(char *s1,int size,int command,int line)
char *hist_word(char *string,int size,int word) char *hist_word(char *string,int size,int word)
{ {
register int c; register int c;
register int is_space;
register int quoted;
register char *s1 = string; register char *s1 = string;
register unsigned char *cp = (unsigned char*)s1; register unsigned char *cp = (unsigned char*)s1;
register int flag = 0; register int flag = 0;
@ -1064,21 +1066,32 @@ char *hist_word(char *string,int size,int word)
if(!hp) if(!hp)
return(NIL(char*)); return(NIL(char*));
hist_copy(string,size,(int)hp->histind-1,-1); hist_copy(string,size,(int)hp->histind-1,-1);
for(;c = *cp;cp++) for(quoted=0;c = *cp;cp++)
{ {
c = isspace(c); is_space = isspace(c) && !quoted;
if(c && flag) if(is_space && flag)
{ {
*cp = 0; *cp = 0;
if(--word==0) if(--word==0)
break; break;
flag = 0; flag = 0;
} }
else if(c==0 && flag==0) else if(is_space==0 && flag==0)
{ {
s1 = (char*)cp; s1 = (char*)cp;
flag++; flag++;
} }
if (c=='\'' && !quoted)
{
for(cp++;*cp && *cp != c;cp++)
;
}
else if (c=='\"' && !quoted)
{
for(cp++;*cp && (*cp != c || quoted);cp++)
quoted = *cp=='\\' ? !quoted : 0;
}
quoted = *cp=='\\' ? !quoted : 0;
} }
*cp = 0; *cp = 0;
if(s1 != string) if(s1 != string)

View file

@ -812,5 +812,19 @@ r ^:test-1: echo ok\r\n$
r ^ok\r\n$ r ^ok\r\n$
! !
# err_exit #
((SHOPT_VSH)) && tst $LINENO <<"!"
L split on quoted whitespace when extracting words from command history
# https://github.com/ksh93/ksh/pull/291
d 15
p :test-1:
w true ls One\\ "Two Three"$'Four Five'.mp3
r ^:test-1: true ls One\\ "Two Three"\$'Four Five'\.mp3\r\n$
p :test-2:
w :\E_
r ^:test-2: : One\\ "Two Three"\$'Four Five'\.mp3\r\n$
!
# ====== # ======
exit $((Errors<125?Errors:125)) exit $((Errors<125?Errors:125))