aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-05-17 16:44:54 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-05-17 16:44:54 +0200
commit020f40693a08b836abdea74f3823a0bce0378ec5 (patch)
tree4ae11c9b2156cccc1af8904c11c195b25b2886b0 /libbb
parent071ede1e5de784820f39c2546000c08d74b12f6d (diff)
downloadbusybox-w32-020f40693a08b836abdea74f3823a0bce0378ec5.tar.gz
busybox-w32-020f40693a08b836abdea74f3823a0bce0378ec5.tar.bz2
busybox-w32-020f40693a08b836abdea74f3823a0bce0378ec5.zip
line editing: add an option to emit ESC [ 6 n and use results
This makes line editing able to recognize case when cursor was not at the beginning of the line. It may also be adapted later to find out display size (serial line users would love it). Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb')
-rw-r--r--libbb/Config.in12
-rw-r--r--libbb/lineedit.c42
-rw-r--r--libbb/read_key.c57
3 files changed, 94 insertions, 17 deletions
diff --git a/libbb/Config.in b/libbb/Config.in
index f5b804ff8..7ced387a9 100644
--- a/libbb/Config.in
+++ b/libbb/Config.in
@@ -102,6 +102,18 @@ config FEATURE_EDITING_FANCY_PROMPT
102 Setting this option allows for prompts to use things like \w and 102 Setting this option allows for prompts to use things like \w and
103 \$ and escape codes. 103 \$ and escape codes.
104 104
105config FEATURE_EDITING_ASK_TERMINAL
106 bool "Query cursor position from terminal"
107 default n
108 depends on FEATURE_EDITING
109 help
110 Allow usage of "ESC [ 6 n" sequence. Terminal answers back with
111 current cursor position. This information is used to make line
112 editing more robust in some cases.
113 If you are not sure whether your terminals respond to this code
114 correctly, or want to save on code size (about 300 bytes),
115 then do not turn this option on.
116
105config FEATURE_VERBOSE_CP_MESSAGE 117config FEATURE_VERBOSE_CP_MESSAGE
106 bool "Give more precise messages when copy fails (cp, mv etc)" 118 bool "Give more precise messages when copy fails (cp, mv etc)"
107 default n 119 default n
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index ccf3e0dc8..e1404fb68 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -86,8 +86,8 @@ struct lineedit_statics {
86 volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */ 86 volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
87 sighandler_t previous_SIGWINCH_handler; 87 sighandler_t previous_SIGWINCH_handler;
88 88
89 unsigned cmdedit_x; /* real x terminal position */ 89 unsigned cmdedit_x; /* real x (col) terminal position */
90 unsigned cmdedit_y; /* pseudoreal y terminal position */ 90 unsigned cmdedit_y; /* pseudoreal y (row) terminal position */
91 unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */ 91 unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */
92 92
93 unsigned cursor; 93 unsigned cursor;
@@ -299,6 +299,16 @@ static void input_backward(unsigned num)
299 299
300static void put_prompt(void) 300static void put_prompt(void)
301{ 301{
302#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
303 /* Ask terminal where is cursor now.
304 * lineedit_read_key handles response and corrects
305 * our idea of current cursor position.
306 * Testcase: run "echo -n long_line_long_line_long_line",
307 * then type in a long, wrapping command and try to
308 * delete it using backspace key.
309 */
310 out1str("\033" "[6n");
311#endif
302 out1str(cmdedit_prompt); 312 out1str(cmdedit_prompt);
303 cursor = 0; 313 cursor = 0;
304 { 314 {
@@ -1430,18 +1440,33 @@ static void win_changed(int nsig)
1430 signal(SIGWINCH, win_changed); /* rearm ourself */ 1440 signal(SIGWINCH, win_changed); /* rearm ourself */
1431} 1441}
1432 1442
1433static int lineedit_read_key(smalluint *read_key_bufsize, char *read_key_buffer) 1443static int lineedit_read_key(char *read_key_buffer)
1434{ 1444{
1435 int ic; 1445 int64_t ic;
1436 struct pollfd pfd; 1446 struct pollfd pfd;
1447
1437 pfd.fd = STDIN_FILENO; 1448 pfd.fd = STDIN_FILENO;
1438 pfd.events = POLLIN; 1449 pfd.events = POLLIN;
1439 do { 1450 do {
1451 poll_again:
1440 /* Wait for input. Can't just call read_key, it will return 1452 /* Wait for input. Can't just call read_key, it will return
1441 * at once if stdin is in non-blocking mode. */ 1453 * at once if stdin is in non-blocking mode. */
1442 safe_poll(&pfd, 1, -1); 1454 safe_poll(&pfd, 1, -1);
1443 /* note: read_key sets errno to 0 on success: */ 1455 /* note: read_key sets errno to 0 on success: */
1444 ic = read_key(STDIN_FILENO, read_key_bufsize, read_key_buffer); 1456 ic = read_key(STDIN_FILENO, read_key_buffer);
1457 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
1458 && (int32_t)ic == KEYCODE_CURSOR_POS
1459 ) {
1460 int col = ((ic >> 32) & 0x7fff) - 1;
1461 if (col > 0) {
1462 cmdedit_x += col;
1463 while (cmdedit_x >= cmdedit_termw) {
1464 cmdedit_x -= cmdedit_termw;
1465 cmdedit_y++;
1466 }
1467 }
1468 goto poll_again;
1469 }
1445 } while (errno == EAGAIN); 1470 } while (errno == EAGAIN);
1446 return ic; 1471 return ic;
1447} 1472}
@@ -1482,7 +1507,6 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1482#endif 1507#endif
1483 struct termios initial_settings; 1508 struct termios initial_settings;
1484 struct termios new_settings; 1509 struct termios new_settings;
1485 smalluint read_key_bufsize;
1486 char read_key_buffer[KEYCODE_BUFFER_SIZE]; 1510 char read_key_buffer[KEYCODE_BUFFER_SIZE];
1487 1511
1488 INIT_S(); 1512 INIT_S();
@@ -1561,7 +1585,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1561 1585
1562 while (1) { 1586 while (1) {
1563 fflush(NULL); 1587 fflush(NULL);
1564 ic = lineedit_read_key(&read_key_bufsize, read_key_buffer); 1588 ic = lineedit_read_key(read_key_buffer);
1565 1589
1566#if ENABLE_FEATURE_EDITING_VI 1590#if ENABLE_FEATURE_EDITING_VI
1567 newdelflag = 1; 1591 newdelflag = 1;
@@ -1738,7 +1762,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1738 sc = cursor; 1762 sc = cursor;
1739 prev_ic = ic; 1763 prev_ic = ic;
1740 1764
1741 ic = lineedit_read_key(&read_key_bufsize, read_key_buffer); 1765 ic = lineedit_read_key(read_key_buffer);
1742 if (errno) /* error */ 1766 if (errno) /* error */
1743 goto prepare_to_die; 1767 goto prepare_to_die;
1744 1768
@@ -1801,7 +1825,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1801 put(); 1825 put();
1802 break; 1826 break;
1803 case 'r'|VI_CMDMODE_BIT: 1827 case 'r'|VI_CMDMODE_BIT:
1804 ic = lineedit_read_key(&read_key_bufsize, read_key_buffer); 1828 ic = lineedit_read_key(read_key_buffer);
1805 if (errno) /* error */ 1829 if (errno) /* error */
1806 goto prepare_to_die; 1830 goto prepare_to_die;
1807 if (ic < ' ' || ic > 255) { 1831 if (ic < ' ' || ic > 255) {
diff --git a/libbb/read_key.c b/libbb/read_key.c
index fd100b0ec..3771045d2 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -9,7 +9,7 @@
9 */ 9 */
10#include "libbb.h" 10#include "libbb.h"
11 11
12int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer) 12int64_t FAST_FUNC read_key(int fd, char *buffer)
13{ 13{
14 struct pollfd pfd; 14 struct pollfd pfd;
15 const char *seq; 15 const char *seq;
@@ -67,9 +67,7 @@ int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer)
67 }; 67 };
68 68
69 errno = 0; 69 errno = 0;
70 n = 0; 70 n = (unsigned char) *buffer++;
71 if (nbuffered)
72 n = *nbuffered;
73 if (n == 0) { 71 if (n == 0) {
74 /* If no data, block waiting for input. If we read more 72 /* If no data, block waiting for input. If we read more
75 * than the minimal ESC sequence size, the "n=0" below 73 * than the minimal ESC sequence size, the "n=0" below
@@ -148,11 +146,54 @@ int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer)
148 } 146 }
149 } 147 }
150 /* We did not find matching sequence, it was a bare ESC. 148 /* We did not find matching sequence, it was a bare ESC.
151 * We possibly read and stored more input in buffer[] 149 * We possibly read and stored more input in buffer[] by now. */
152 * by now. */ 150
151 /* Try to decipher "ESC [ NNN ; NNN R" sequence */
152 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
153 && n != 0
154 && buffer[0] == '['
155 ) {
156 char *end;
157 unsigned long row, col;
158
159 while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for cnt */
160 if (safe_poll(&pfd, 1, 50) == 0) {
161 /* No more data! */
162 break;
163 }
164 errno = 0;
165 if (safe_read(fd, buffer + n, 1) <= 0) {
166 /* If EAGAIN, then fd is O_NONBLOCK and poll lied:
167 * in fact, there is no data. */
168 if (errno != EAGAIN)
169 c = -1; /* otherwise it's EOF/error */
170 goto ret;
171 }
172 if (buffer[n++] == 'R')
173 goto got_R;
174 }
175 goto ret;
176 got_R:
177 if (!isdigit(buffer[1]))
178 goto ret;
179 row = strtoul(buffer + 1, &end, 10);
180 if (*end != ';' || !isdigit(end[1]))
181 goto ret;
182 col = strtoul(end + 1, &end, 10);
183 if (*end != 'R')
184 goto ret;
185 if (row < 1 || col < 1 || (row | col) > 0x7fff)
186 goto ret;
187
188 buffer[-1] = 0;
189
190 /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */
191 c = (((-1 << 15) | row) << 16) | col;
192 /* Return it in high-order word */
193 return ((int64_t) c << 32) | (uint32_t)KEYCODE_CURSOR_POS;
194 }
153 195
154 ret: 196 ret:
155 if (nbuffered) 197 buffer[-1] = n;
156 *nbuffered = n;
157 return c; 198 return c;
158} 199}