ksh: Reverse-search bug in Emacs line editor

This isn’t a bug, or I don’t think it’s really a bug. But is it proper behavior? It’s certainly not expected. (aside: u+m needs fora)

This is a bug in reverse-search…

$ history
1	PS1='$ '
2	CLEAR
3	history

Ok, now you can search backwards:

$ hist↑

Which is replaced on the command line by:

$ history

All good.

But now, do something that isn’t found in a reverse-search:

$ hist2↑

You get a bell, because there’s no match. All good.

Backspace, remove the ‘2’. reverse-search again:

$ hist↑

And you get a bell. Why? There’s a match, it was just demonstrated. You have to remove the entire typed string before reverse-search finds history again.

it’s not backspacing that does this, it’s the failed search that makes it happen. You can reverse-search successfully, backspace over part of the result, and search again, and the reverse-search succeeds.

It’s actually broken differently on ksh2020, if reverse-search fails there, backspacing and searching again doesn’t work until there’s been an intervening <CR>.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 23

Most upvoted comments

Please try this. I think it makes it act like you prefer, i.e., the search is reset whenever the line is edited.

--- a/src/cmd/ksh93/edit/emacs.c
+++ b/src/cmd/ksh93/edit/emacs.c
@@ -1097,7 +1097,7 @@ static int escape(register Emacs_t* ep,register genchar *out,int count)
 				if(cur>0 && eol==cur && (cur<(SEARCHSIZE-2) || ep->prevdirection == -2))
 #endif /* SHOPT_EDPREDICT */
 				{
-					if(ep->lastdraw==APPEND)
+					if(ep->lastdraw==APPEND || killing)
 					{
 						out[cur] = 0;
 						gencpy((genchar*)lstring+1,out);
@@ -1422,7 +1422,14 @@ static void draw(register Emacs_t *ep,Draw_t option)
 	logcursor = sptr + cur;
 	longline = NORMAL;
 	ep->lastdraw = option;
-	
+
+	if (option == APPEND || killing)
+	{
+		/* Reset arrow-up history search state */
+		hloff = 0;
+		hline = histlines;
+	}
+
 	if (option == FIRST || option == REFRESH)
 	{
 		ep->overflow = NORMAL;

@McDutchie I think it’s only “working” on your end because of duplicate entries in your history file. To reproduce the bug I have to put new command entries in the history file on each run. Hopefully this is a more clarified reproducer:

# The following two commands are _always_ run for each attempt at reproducing the bug.
$ alias foo=bar
$ alias foo=other

$ alias foo<Up Arrow>  # This give you 'alias foo=other'. Press the backspace key five times, then up arrow
$ alias foo=bar  # It completes to 'alias foo=bar', because it didn't reset it's entry in the history file

Additionally, I’ve found a bug related to tab completion. Reverse search doesn’t activate after tab completion:

# Like the above, always run the following three commands for each attempt
$ true /bin/foo
$ true /bin/bar
$ false

$ true /bin<Tab> <Up Arrow>  # The result is 'false' rather than 'true /bin/bar'

I followed @posguy99 instructions and it still happens as he describes. Once, I get the bell and try an up arrow it always bells until I start over with a new line or erase the entire line. I will note that the behavior @McDutchie describes starts happening when I have another occurrence of ‘history’ in my history log.

$ arch/*/bin/ksh
$ set --state
set --default --bgnice --braceexpand --emacs --monitor --multiline --viraw
$ history
510	ls
511	cd git
512	set --state
513	history
$ # perform instructions and get a bell no matter what I do
$ history
510	ls
511	cd git
512	set --state
513	history
514	history
$ # perform instructions and now able to just backspace to a character and get a match with hist and up arrow.