aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-04-18 22:09:30 -0700
committerDenys Vlasenko <vda.linux@googlemail.com>2010-04-18 22:09:30 -0700
commitc175c4664734e5a363d8cc8668c08f551eff1485 (patch)
tree7a71009d3d5a9b3a0e8be65bf020f4605cee4bae
parentdef4783a8a8b00f58d224ff6735d3532809aeb54 (diff)
downloadbusybox-w32-c175c4664734e5a363d8cc8668c08f551eff1485.tar.gz
busybox-w32-c175c4664734e5a363d8cc8668c08f551eff1485.tar.bz2
busybox-w32-c175c4664734e5a363d8cc8668c08f551eff1485.zip
vi: discover window size even on serial consoles. optional
function old new delta edit_file 671 761 +90 wh_helper - 57 +57 query_screen_dimensions 54 63 +9 ar_main 533 542 +9 refresh 767 773 +6 vi_main 242 243 +1 text_yank 56 54 -2 get_terminal_width_height 180 135 -45 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 5/2 up/down: 172/-47) Total: 125 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/Config.in12
-rw-r--r--editors/vi.c23
-rw-r--r--libbb/read_key.c2
-rw-r--r--libbb/xfuncs.c54
4 files changed, 65 insertions, 26 deletions
diff --git a/editors/Config.in b/editors/Config.in
index e4fdd0f38..5f9566f0a 100644
--- a/editors/Config.in
+++ b/editors/Config.in
@@ -168,6 +168,18 @@ config FEATURE_VI_WIN_RESIZE
168 help 168 help
169 Make busybox vi behave nicely with terminals that get resized. 169 Make busybox vi behave nicely with terminals that get resized.
170 170
171config FEATURE_VI_ASK_TERMINAL
172 bool "Use 'tell me cursor position' ESC sequence to measure window"
173 default n
174 depends on VI
175 help
176 If terminal size can't be retrieved and $LINES/$COLUMNS are not set,
177 this option makes vi perform a last-ditch effort to find it:
178 vi positions cursor to 999,999 and asks terminal to report real
179 cursor position using "ESC [ 6 n" escape sequence, then reads stdin.
180
181 This is not clean but helps a lot on serial lines and such.
182
171config FEATURE_VI_OPTIMIZE_CURSOR 183config FEATURE_VI_OPTIMIZE_CURSOR
172 bool "Optimize cursor movement" 184 bool "Optimize cursor movement"
173 default y 185 default y
diff --git a/editors/vi.c b/editors/vi.c
index f925984ba..d3a35e781 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -138,6 +138,9 @@ struct globals {
138 int save_argc; // how many file names on cmd line 138 int save_argc; // how many file names on cmd line
139 int cmdcnt; // repetition count 139 int cmdcnt; // repetition count
140 unsigned rows, columns; // the terminal screen is this size 140 unsigned rows, columns; // the terminal screen is this size
141#if ENABLE_FEATURE_VI_ASK_TERMINAL
142 int get_rowcol_error;
143#endif
141 int crow, ccol; // cursor is on Crow x Ccol 144 int crow, ccol; // cursor is on Crow x Ccol
142 int offset; // chars scrolled off the screen to the left 145 int offset; // chars scrolled off the screen to the left
143 int have_status_msg; // is default edit status needed? 146 int have_status_msg; // is default edit status needed?
@@ -503,7 +506,11 @@ static int init_text_buffer(char *fn)
503#if ENABLE_FEATURE_VI_WIN_RESIZE 506#if ENABLE_FEATURE_VI_WIN_RESIZE
504static void query_screen_dimensions(void) 507static void query_screen_dimensions(void)
505{ 508{
506 get_terminal_width_height(STDIN_FILENO, &columns, &rows); 509# if ENABLE_FEATURE_VI_ASK_TERMINAL
510 if (!G.get_rowcol_error)
511 G.get_rowcol_error =
512# endif
513 get_terminal_width_height(STDIN_FILENO, &columns, &rows);
507 if (rows > MAX_SCR_ROWS) 514 if (rows > MAX_SCR_ROWS)
508 rows = MAX_SCR_ROWS; 515 rows = MAX_SCR_ROWS;
509 if (columns > MAX_SCR_COLS) 516 if (columns > MAX_SCR_COLS)
@@ -530,6 +537,20 @@ static void edit_file(char *fn)
530 columns = 80; 537 columns = 80;
531 size = 0; 538 size = 0;
532 query_screen_dimensions(); 539 query_screen_dimensions();
540#if ENABLE_FEATURE_VI_ASK_TERMINAL
541 if (G.get_rowcol_error /* TODO? && no input on stdin */) {
542 uint64_t k;
543 write1("\033[999;999H" "\033[6n");
544 fflush_all();
545 k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100);
546 if ((int32_t)k == KEYCODE_CURSOR_POS) {
547 uint32_t rc = (k >> 32);
548 columns = (rc & 0x7fff);
549 rows = ((rc >> 16) & 0x7fff);
550 }
551 query_screen_dimensions();
552 }
553#endif
533 new_screen(rows, columns); // get memory for virtual screen 554 new_screen(rows, columns); // get memory for virtual screen
534 init_text_buffer(fn); 555 init_text_buffer(fn);
535 556
diff --git a/libbb/read_key.c b/libbb/read_key.c
index 8422976c9..64557ab14 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -214,7 +214,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
214 } 214 }
215 n++; 215 n++;
216 /* Try to decipher "ESC [ NNN ; NNN R" sequence */ 216 /* Try to decipher "ESC [ NNN ; NNN R" sequence */
217 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL 217 if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL || ENABLE_FEATURE_VI_ASK_TERMINAL)
218 && n >= 5 218 && n >= 5
219 && buffer[0] == '[' 219 && buffer[0] == '['
220 && buffer[n-1] == 'R' 220 && buffer[n-1] == 'R'
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index aec165f06..d93dd2af9 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -210,34 +210,40 @@ char* FAST_FUNC xmalloc_ttyname(int fd)
210 return buf; 210 return buf;
211} 211}
212 212
213/* It is perfectly ok to pass in a NULL for either width or for 213static int wh_helper(int value, int def_val, const char *env_name, int *err)
214 * height, in which case that value will not be set. */
215int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height)
216{ 214{
217 struct winsize win = { 0, 0, 0, 0 }; 215 if (value == 0) {
218 int ret = ioctl(fd, TIOCGWINSZ, &win); 216 char *s = getenv(env_name);
219 217 if (s) {
220 if (height) { 218 value = atoi(s);
221 if (!win.ws_row) { 219 /* If LINES/COLUMNS are set, pretent that there is
222 char *s = getenv("LINES"); 220 * no error getting w/h, this prevents some ugly
223 if (s) win.ws_row = atoi(s); 221 * cursor tricks by our callers */
224 } 222 *err = 0;
225 if (win.ws_row <= 1 || win.ws_row >= 30000)
226 win.ws_row = 24;
227 *height = (int) win.ws_row;
228 }
229
230 if (width) {
231 if (!win.ws_col) {
232 char *s = getenv("COLUMNS");
233 if (s) win.ws_col = atoi(s);
234 } 223 }
235 if (win.ws_col <= 1 || win.ws_col >= 30000)
236 win.ws_col = 80;
237 *width = (int) win.ws_col;
238 } 224 }
225 if (value <= 1 || value >= 30000)
226 value = def_val;
227 return value;
228}
239 229
240 return ret; 230/* It is perfectly ok to pass in a NULL for either width or for
231 * height, in which case that value will not be set. */
232int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height)
233{
234 struct winsize win;
235 int err;
236
237 win.ws_row = 0;
238 win.ws_col = 0;
239 /* I've seen ioctl returning 0, but row/col is (still?) 0.
240 * We treat that as an error too. */
241 err = ioctl(fd, TIOCGWINSZ, &win) != 0 || win.ws_row == 0;
242 if (height)
243 *height = wh_helper(win.ws_row, 24, "LINES", &err);
244 if (width)
245 *width = wh_helper(win.ws_col, 80, "COLUMNS", &err);
246 return err;
241} 247}
242 248
243int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) 249int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)