Skip to content

Commit

Permalink
emacs: Fix sticky numeric param. after meta command (re: 13c3fb2)
Browse files Browse the repository at this point in the history
Reproducer: type (each line folluwed by RETURN):

  set -o emacs
  : bad corret wrong

Now type ESC 3 ESC _ to recall the third word ("corret") from the
history. Type Ctrl+B to move the cursor back one position.

Expected result: the cursor is over the 't' of 'corret' so you can
insert missing the 'c', resulting in 'correct'.

Actual result: the cursor moves back three positions instead of
one, so it's over the second 'r' in 'corret' and inserting a 'c'
would result in 'corcret'.

Analysis: When the escape() function in emacs.c returns -1 to unset
the current numeric parameter 'adjust', vt220_save_repeat is not reset
(lines 600-602). However, this reset should only be avoided when
processing escape codes related to VT220 keys, whose handling was
introduced in the referenced commit. It should be saved for them
because they are translated to native emacs commands (e.g. left
arrow is translated to Ctrl+B) that are inserted into the input
buffer and processed in another ed_emacsread pass. For all other
ESC/meta commands, it should be reset as normal.

src/cmd/ksh93/edit/emacs.c:
- In ed_emacsread(), only reset vt220_save_repeat if escape()
  returns a value > -2. Change a -2 return back to -1 in the
  'adjust' variable to prevent potential side effects.
- In escape(), return -2 for all the VT220 escape sequences.
  On line 956, change the check for 'count == -1' to 'count < 0'.

The effect is that the numeric parameter is still saved for VT220
escape sequences but correctly reset for all other meta commands.
  • Loading branch information
McDutchie committed Dec 22, 2024
1 parent f0268e9 commit 9172b73
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 26 deletions.
8 changes: 8 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ This documents significant changes in the dev branch of ksh 93u+m.
For full details, see the git log at: https://github.com/ksh93/ksh
Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library.

2024-12-21:

- Fixed a bug in the emacs/gmacs line editor where a command repeat count
(e.g., ESC 3) sticks and is re-used for the next command after an ESC
command. For example, ESC 3 ESC _ recalls the third word from the last
command in the history. The bug is that the next command, such as ^B to
move back, is then repeated three times. Bug introduced on 2020-09-17.

2024-12-18:

- Persuant to POSIX.1-2024, exec(1) will no longer cause the shell to exit
Expand Down
6 changes: 3 additions & 3 deletions src/cmd/builtin/pty.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ static const char usage[] =
"\amilliseconds\a; the default is no delay]"
"[i \are\a?read a line from the master; if it matches \are\a "
"then execute lines until matching \be\b or \bf\b]"
"[e [re]]?else [if match re]] then execute lines until matching "
"\be\b or \bf\b]"
"[e [\are\a]]?else [if match \are\a]] then execute lines until "
"matching \be\b or \bf\b]"
"[f?end of \bi\b/\be\b block]"
"[m \atext\a?write \atext\a to the standard error]"
"[p \atext\a?peek input until \atext\a is found at the beginning "
"of a line; input is not consumed]"
"[r [\are\a]]?read a line from the master [and it should match "
"re]]]"
"\are\a]]]"
"[s \amilliseconds\a?sleep for \amilliseconds\a]"
"[t \amilliseconds\a?set the master read timeout to "
"\amilliseconds\a; the default is \b1000\b]"
Expand Down
46 changes: 24 additions & 22 deletions src/cmd/ksh93/edit/emacs.c
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,10 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit)
vt220_save_repeat = oadjust;
do_escape:
adjust = escape(ep,out,oadjust);
if(adjust > -1)
if(adjust > -2)
vt220_save_repeat = 0;
if(adjust < -1)
adjust = -1;
continue;
case cntl('R') :
search(ep,out,count);
Expand Down Expand Up @@ -1026,32 +1028,32 @@ static int escape(Emacs_t* ep,genchar *out,int count)
case 'A':
/* VT220 up arrow */
if(!sh_isoption(SH_NOARROWSRCH) && dosearch(ep,out,1))
return -1;
return -2;
ed_ungetchar(ep->ed,cntl('P'));
return -1;
return -2;
case 'B':
/* VT220 down arrow */
if(!sh_isoption(SH_NOARROWSRCH) && dosearch(ep,out,0))
return -1;
return -2;
ed_ungetchar(ep->ed,cntl('N'));
return -1;
return -2;
case 'C':
/* VT220 right arrow */
ed_ungetchar(ep->ed,cntl('F'));
return -1;
return -2;
case 'D':
/* VT220 left arrow */
ed_ungetchar(ep->ed,cntl('B'));
return -1;
return -2;
case 'H':
/* VT220 Home key */
ed_ungetchar(ep->ed,cntl('A'));
return -1;
return -2;
case 'F':
case 'Y':
/* VT220 End key */
ed_ungetchar(ep->ed,cntl('E'));
return -1;
return -2;
case '1':
case '7':
/*
Expand All @@ -1062,7 +1064,7 @@ static int escape(Emacs_t* ep,genchar *out,int count)
if(ch == '~')
{ /* Home key */
ed_ungetchar(ep->ed,cntl('A'));
return -1;
return -2;
}
else if(i == '1' && ch == ';')
{
Expand All @@ -1085,17 +1087,17 @@ static int escape(Emacs_t* ep,genchar *out,int count)
}
ed_ungetchar(ep->ed,ch);
ed_ungetchar(ep->ed,i);
return -1;
return -2;
case '2': /* Insert key */
ch = ed_getchar(ep->ed,1);
if(ch == '~')
{
ed_ungetchar(ep->ed, cntl('V'));
return -1;
return -2;
}
ed_ungetchar(ep->ed,ch);
ed_ungetchar(ep->ed,i);
return -1;
return -2;
case '3':
ch = ed_getchar(ep->ed,1);
if(ch == '~')
Expand All @@ -1107,7 +1109,7 @@ static int escape(Emacs_t* ep,genchar *out,int count)
*/
if(cur < eol)
ed_ungetchar(ep->ed,ERASECHAR);
return -1;
return -2;
}
else if(ch == ';')
{
Expand All @@ -1127,7 +1129,7 @@ static int escape(Emacs_t* ep,genchar *out,int count)
}
ed_ungetchar(ep->ed,ch);
ed_ungetchar(ep->ed,i);
return -1;
return -2;
case '5': /* Haiku terminal Ctrl-Arrow key */
ch = ed_getchar(ep->ed,1);
switch(ch)
Expand All @@ -1140,34 +1142,34 @@ static int escape(Emacs_t* ep,genchar *out,int count)
goto forward;
case '~': /* Page Up (perform reverse search) */
if(dosearch(ep,out,1))
return -1;
return -2;
ed_ungetchar(ep->ed,cntl('P'));
return -1;
return -2;
}
ed_ungetchar(ep->ed,ch);
ed_ungetchar(ep->ed,i);
return -1;
return -2;
case '6':
ch = ed_getchar(ep->ed,1);
if(ch == '~')
{
/* Page Down (perform backwards reverse search) */
if(dosearch(ep,out,0))
return -1;
return -2;
ed_ungetchar(ep->ed,cntl('N'));
return -1;
return -2;
}
ed_ungetchar(ep->ed,ch);
ed_ungetchar(ep->ed,i);
return -1;
return -2;
case '4':
case '8': /* rxvt */
ch = ed_getchar(ep->ed,1);
if(ch == '~')
{
/* End key */
ed_ungetchar(ep->ed,cntl('E'));
return -1;
return -2;
}
ed_ungetchar(ep->ed,ch);
/* FALLTHROUGH */
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/ksh93/include/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include <ast_release.h>
#include "git.h"

#define SH_RELEASE_DATE "2024-12-18" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_DATE "2024-12-21" /* must be in this format for $((.sh.version)) */
/*
* This comment keeps SH_RELEASE_DATE a few lines away from SH_RELEASE_SVER to avoid
* merge conflicts when cherry-picking dev branch commits onto a release branch.
Expand Down
15 changes: 15 additions & 0 deletions src/cmd/ksh93/tests/pty.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1385,5 +1385,20 @@ c \Ek
r :test-2: true
!

((SHOPT_ESH)) && VISUAL=emacs tst $LINENO <<"!"
L emacs: repeat count sticks after ESC commands
# a bug introduced on 2020-09-17 and fixed on 2024-12-21
d 15
# The 'P' command sets an automatic 'p' before every 'w', delaying writing until a match is read.
P :test-.:
w false bad rigt wrong
# Insert 'print '; recall 3rd word 'rigt' (ESC 3 ESC _); cursor back one position (^B); insert 'h'.
# (With the bug, the repeat count of 3 sticks and ^B goes back 3 positions, resulting in 'rhigt'.)
w print \E3\E_\cBh
I print
r right
!

# ======
exit $((Errors<125?Errors:125))

0 comments on commit 9172b73

Please sign in to comment.