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