On Friday 15 May 2009 10:17, Rob Landley wrote:
> By the way, what the heck is smalluint?  Why isn't uint16_t usable?  c99 was 
> a 
> full decade ago...

Because bytes are more efficient on x86. On ARM, you'd rather use
full-sized words.

> > * if neither $LINES/$COLUMNS are set nor ioctl(TIOCGWINSZ)
> >   returns useful data, print
> >   ESC"7" ESC"[r" ESC"[9999;9999H" ESC"[6n" ESC"8"
> >   in order to retrieve terminal's size, and whenever read_key
> >   does detect that, use this info for proper linewrapping
> >   in line editing.
> 
> A) Some terminals don't handle 9999, they max out at 3 digits and abort 
> parsing the sequence at 4.  (Yes, I tested this.)
> 
> B) That gives you size but not position.
> 
> > First snag I hit is that line editing does not yet use read_key,
> > it has another (and buggy) implementation. Fixing that.
> >
> > Is the above plan good?
> 
> It's an improvement, but not a full fix.  Jumping to the left edge and 
> overwriting data with a prompt is behavior other shells don't do for a 
> _reason_.

Please try this patch. It prints "ESC [ 6 n" before each prompt
and if response's column value is not 1, then ash's idea of
current column is updated by += (col - 1).
--
vda

--
vda
diff -d -urpN busybox.2/include/libbb.h busybox.3/include/libbb.h
--- busybox.2/include/libbb.h	2009-05-15 23:19:55.000000000 +0200
+++ busybox.3/include/libbb.h	2009-05-16 16:13:20.000000000 +0200
@@ -962,8 +962,12 @@ enum {
 	KEYCODE_FUN11    = -22,
 	KEYCODE_FUN12    = -23,
 #endif
-	/* How long the longest ESC sequence we know? */
-	KEYCODE_BUFFER_SIZE = 4
+	KEYCODE_CURSOR_POS = -0x100,
+	/* How long is the longest ESC sequence we know?
+	 * We want it big enough to be able to contain
+	 * cursor position sequence "ESC [ 9999 ; 9999 R"
+	 */
+	KEYCODE_BUFFER_SIZE = 16
 };
 /* Note: fd may be in blocking or non-blocking mode, both make sense.
  * For one, less uses non-blocking mode.
@@ -971,7 +975,7 @@ enum {
  * (unless fd is in non-blocking mode),
  * subsequent reads will time out after a few milliseconds.
  */
-int read_key(int fd, smalluint *nbuffered, char *buffer) FAST_FUNC;
+long long read_key(int fd, smalluint *nbuffered, char *buffer) FAST_FUNC;
 
 
 /* Networking */
diff -d -urpN busybox.2/libbb/lineedit.c busybox.3/libbb/lineedit.c
--- busybox.2/libbb/lineedit.c	2009-05-15 02:04:29.000000000 +0200
+++ busybox.3/libbb/lineedit.c	2009-05-16 16:13:20.000000000 +0200
@@ -86,8 +86,8 @@ struct lineedit_statics {
 	volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
 	sighandler_t previous_SIGWINCH_handler;
 
-	unsigned cmdedit_x;        /* real x terminal position */
-	unsigned cmdedit_y;        /* pseudoreal y terminal position */
+	unsigned cmdedit_x;        /* real x (col) terminal position */
+	unsigned cmdedit_y;        /* pseudoreal y (row) terminal position */
 	unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */
 
 	unsigned cursor;
@@ -299,6 +299,14 @@ static void input_backward(unsigned num)
 
 static void put_prompt(void)
 {
+	/* Ask terminal where is cursor now.
+	 * lineedit_read_key handles response and corrects
+	 * our idea of current cursor position.
+	 * Testcase: run "echo -n long_line_long_line_long_line",
+	 * then type in a long, wrapping command and try to
+	 * delete it using backspace key.
+	 */
+	out1str("\033" "[6n");
 	out1str(cmdedit_prompt);
 	cursor = 0;
 	{
@@ -1432,16 +1440,29 @@ static void win_changed(int nsig)
 
 static int lineedit_read_key(smalluint *read_key_bufsize, char *read_key_buffer)
 {
-	int ic;
+	long long ic;
 	struct pollfd pfd;
+
 	pfd.fd = STDIN_FILENO;
 	pfd.events = POLLIN;
 	do {
+ poll_again:
 		/* Wait for input. Can't just call read_key, it will return
 		 * at once if stdin is in non-blocking mode. */
 		safe_poll(&pfd, 1, -1);
 		/* note: read_key sets errno to 0 on success: */
 		ic = read_key(STDIN_FILENO, read_key_bufsize, read_key_buffer);
+		if ((int32_t)ic == KEYCODE_CURSOR_POS) {
+			int col = ((ic >> 32) & 0x7fff) - 1;
+			if (col > 0) {
+				cmdedit_x += col;
+				while (cmdedit_x >= cmdedit_termw) {
+					cmdedit_x -= cmdedit_termw;
+					cmdedit_y++;
+				}
+			}
+			goto poll_again;
+		}
 	} while (errno == EAGAIN);
 	return ic;
 }
diff -d -urpN busybox.2/libbb/read_key.c busybox.3/libbb/read_key.c
--- busybox.2/libbb/read_key.c	2009-05-15 02:04:29.000000000 +0200
+++ busybox.3/libbb/read_key.c	2009-05-16 16:13:20.000000000 +0200
@@ -9,7 +9,7 @@
  */
 #include "libbb.h"
 
-int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer)
+long long FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer)
 {
 	struct pollfd pfd;
 	const char *seq;
@@ -148,8 +148,49 @@ int FAST_FUNC read_key(int fd, smalluint
 		}
 	}
 	/* We did not find matching sequence, it was a bare ESC.
-	 * We possibly read and stored more input in buffer[]
-	 * by now. */
+	 * We possibly read and stored more input in buffer[] by now. */
+
+	/* Try to decipher "ESC [ NNN ; NNN R" sequence */
+	if (n != 0 && buffer[0] == '[') {
+		char *end;
+		unsigned long row, col;
+
+		while (n < KEYCODE_BUFFER_SIZE-1) {
+			if (safe_poll(&pfd, 1, 50) == 0) {
+				/* No more data! */
+				break;
+			}
+			errno = 0;
+			if (safe_read(fd, buffer + n, 1) <= 0) {
+				/* If EAGAIN, then fd is O_NONBLOCK and poll lied:
+				 * in fact, there is no data. */
+				if (errno != EAGAIN)
+					c = -1; /* otherwise it's EOF/error */
+				goto ret;
+			}
+			if (buffer[n++] == 'R')
+				goto got_R;
+		}
+		goto ret;
+ got_R:
+		buffer[n] = '\0';
+		if (!isdigit(buffer[1]))
+			goto ret;
+		row = strtoul(buffer + 1, &end, 10);
+		if (*end != ';' || !isdigit(end[1]))
+			goto ret;
+		col = strtoul(end + 1, &end, 10);
+		if (*end != 'R')
+			goto ret;
+		if (row < 1 || col < 1 || (row | col) > 0x7fff)
+			goto ret;
+
+		if (nbuffered)
+			*nbuffered = 0;
+		/* Pack them into "1 <row15bits> <col16bits>" 32-bit sequence */
+		c = (((-1 << 15) | row) << 16) | col;
+		return ((long long) c << 32) | (uint32_t)KEYCODE_CURSOR_POS;
+	}
 
  ret:
 	if (nbuffered)
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to