Module Name:    src
Committed By:   christos
Date:           Mon May  9 21:27:55 UTC 2016

Modified Files:
        src/lib/libedit: editline.3 editline.7 readline.c

Log Message:
GNU readline(3) regards history chronologically, that is, from the
perspective of the dawn of time, so "next" means "newer" and "previous"
means "older".  Libedit, by contrast, uses reverse chronology and
regards history from the perspective of the present, such that "next"
means "longer ago" and "previous" means "not so long ago".

The following patch fixes previous_history() and next_history()
as proposed by Bastian Maerkisch.

But there is a related problem demonstrated by Bastian's regression
tests that his patch did not fix:  next_history() can advance not
only to the newest entry, but beyond it, which core libedit cannot
do.  So that feature must be implemented locally in readline.c.

With that, the last of Bastians tests is fixed, test_movement_direction().

This patch also improves libedit documentation to more clearly state
what "previous" and "next" mean.  GNU readline documentation is
just as unclear, but we can't easily fix that since libedit doesn't
include its own readline.3 manual.

(Ingo Schwarze)


To generate a diff of this commit:
cvs rdiff -u -r1.89 -r1.90 src/lib/libedit/editline.3
cvs rdiff -u -r1.4 -r1.5 src/lib/libedit/editline.7
cvs rdiff -u -r1.131 -r1.132 src/lib/libedit/readline.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libedit/editline.3
diff -u src/lib/libedit/editline.3:1.89 src/lib/libedit/editline.3:1.90
--- src/lib/libedit/editline.3:1.89	Thu Apr 28 11:50:33 2016
+++ src/lib/libedit/editline.3	Mon May  9 17:27:55 2016
@@ -1,4 +1,4 @@
-.\"	$NetBSD: editline.3,v 1.89 2016/04/28 15:50:33 christos Exp $
+.\"	$NetBSD: editline.3,v 1.90 2016/05/09 21:27:55 christos Exp $
 .\"
 .\" Copyright (c) 1997-2014 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -26,7 +26,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd February 24, 2016
+.Dd May 9, 2016
 .Dt EDITLINE 3
 .Os
 .Sh NAME
@@ -761,8 +761,10 @@ Return the first element in the history.
 Return the last element in the history.
 .It Dv H_PREV
 Return the previous element in the history.
+It is newer than the current one.
 .It Dv H_NEXT
 Return the next element in the history.
+It is older than the current one.
 .It Dv H_CURR
 Return the current element in the history.
 .It Dv H_SET

Index: src/lib/libedit/editline.7
diff -u src/lib/libedit/editline.7:1.4 src/lib/libedit/editline.7:1.5
--- src/lib/libedit/editline.7:1.4	Mon May  2 08:51:25 2016
+++ src/lib/libedit/editline.7	Mon May  9 17:27:55 2016
@@ -1,4 +1,4 @@
-.\"	$NetBSD: editline.7,v 1.4 2016/05/02 12:51:25 wiz Exp $
+.\"	$NetBSD: editline.7,v 1.5 2016/05/09 21:27:55 christos Exp $
 .\"	$OpenBSD: editline.7,v 1.1 2016/04/20 01:11:45 schwarze Exp $
 .\"
 .\" Copyright (c) 2016 Ingo Schwarze <schwa...@openbsd.org>
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd May 2, 2016
+.Dd May 7, 2016
 .Dt EDITLINE 7
 .Os
 .Sh NAME
@@ -408,6 +408,7 @@ It is an error if the cursor is already 
 buffer.
 .It Ic ed-next-history Pq vi command: j, +, Ctrl-N; emacs: Ctrl-N
 Replace the edit buffer with the next history line.
+That line is older than the current line.
 With an argument, go forward by that number of history lines.
 It is a non-fatal error to advance by more lines than are available.
 .It Ic ed-next-line Pq not bound by default
@@ -427,6 +428,7 @@ It is an error if the cursor is already 
 edit buffer.
 .It Ic ed-prev-history Pq vi command: k, -, Ctrl-P; emacs: Ctrl-P
 Replace the edit buffer with the previous history line.
+That line is newer than the current line.
 With an argument, go back by that number of lines.
 It is a non-fatal error to back up by more lines than are available.
 .It Ic ed-prev-line Pq not bound by default

Index: src/lib/libedit/readline.c
diff -u src/lib/libedit/readline.c:1.131 src/lib/libedit/readline.c:1.132
--- src/lib/libedit/readline.c:1.131	Mon May  9 17:25:11 2016
+++ src/lib/libedit/readline.c	Mon May  9 17:27:55 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: readline.c,v 1.131 2016/05/09 21:25:11 christos Exp $	*/
+/*	$NetBSD: readline.c,v 1.132 2016/05/09 21:27:55 christos Exp $	*/
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include "config.h"
 #if !defined(lint) && !defined(SCCSID)
-__RCSID("$NetBSD: readline.c,v 1.131 2016/05/09 21:25:11 christos Exp $");
+__RCSID("$NetBSD: readline.c,v 1.132 2016/05/09 21:27:55 christos Exp $");
 #endif /* not lint && not SCCSID */
 
 #include <sys/types.h>
@@ -156,6 +156,14 @@ char *rl_special_prefixes = NULL;
  */
 int rl_completion_append_character = ' ';
 
+/*
+ * When the history cursor is on the newest element and next_history()
+ * is called, GNU readline moves the cursor beyond the newest element.
+ * The editline library does not provide data structures to express
+ * that state, so we need a local flag.
+ */
+static int current_history_valid = 1;
+
 /* stuff below is used internally by libedit for readline emulation */
 
 static History *h = NULL;
@@ -291,6 +299,8 @@ rl_initialize(void)
 	int editmode = 1;
 	struct termios t;
 
+	current_history_valid = 1;
+
 	if (e != NULL)
 		el_end(e);
 	if (h != NULL)
@@ -1451,6 +1461,7 @@ add_history(const char *line)
 	(void)history(h, &ev, H_ENTER, line);
 	if (history(h, &ev, H_GETSIZE) == 0)
 		history_length = ev.num;
+	current_history_valid = 1;
 
 	return !(history_length > 0); /* return 0 if all is okay */
 }
@@ -1543,6 +1554,7 @@ clear_history(void)
 
 	(void)history(h, &ev, H_CLEAR);
 	history_length = 0;
+	current_history_valid = 1;
 }
 
 
@@ -1575,7 +1587,7 @@ HIST_ENTRY *
 current_history(void)
 {
 
-	return _move_history(H_CURR);
+	return current_history_valid ? _move_history(H_CURR) : NULL;
 }
 
 
@@ -1620,6 +1632,7 @@ history_set_pos(int pos)
 
 	(void)history(h, &ev, H_CURR);
 	curr_num = ev.num;
+	current_history_valid = 1;
 
 	/*
 	 * use H_DELDATA to set to nth history (without delete) by passing
@@ -1635,12 +1648,17 @@ history_set_pos(int pos)
 
 /*
  * returns previous event in history and shifts pointer accordingly
+ * Note that readline and editline define directions in opposite ways.
  */
 HIST_ENTRY *
 previous_history(void)
 {
 
-	return _move_history(H_PREV);
+	if (current_history_valid == 0) {
+		current_history_valid = 1;
+		return _move_history(H_CURR);
+	}
+	return _move_history(H_NEXT);
 }
 
 
@@ -1650,8 +1668,12 @@ previous_history(void)
 HIST_ENTRY *
 next_history(void)
 {
+	HIST_ENTRY *he;
 
-	return _move_history(H_NEXT);
+	he = _move_history(H_PREV);
+	if (he == NULL)
+		current_history_valid = 0;
+	return he;
 }
 
 

Reply via email to