less: optionally query terminal size via "ESC [ 6 n". Closes bug 2659.

+7 bytes is not selected, +100 if selected.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2011-07-25 15:18:20 +02:00
parent be391e7596
commit 4e552a70ec
4 changed files with 123 additions and 84 deletions

View File

@ -132,8 +132,8 @@
//config: help //config: help
//config: If terminal size can't be retrieved and $LINES/$COLUMNS are not set, //config: If terminal size can't be retrieved and $LINES/$COLUMNS are not set,
//config: this option makes vi perform a last-ditch effort to find it: //config: this option makes vi perform a last-ditch effort to find it:
//config: vi positions cursor to 999,999 and asks terminal to report real //config: position cursor to 999,999 and ask terminal to report real
//config: cursor position using "ESC [ 6 n" escape sequence, then reads stdin. //config: cursor position using "ESC [ 6 n" escape sequence, then read stdin.
//config: //config:
//config: This is not clean but helps a lot on serial lines and such. //config: This is not clean but helps a lot on serial lines and such.
//config: //config:

View File

@ -214,7 +214,10 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
} }
n++; n++;
/* Try to decipher "ESC [ NNN ; NNN R" sequence */ /* Try to decipher "ESC [ NNN ; NNN R" sequence */
if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL || ENABLE_FEATURE_VI_ASK_TERMINAL) if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL
|| ENABLE_FEATURE_VI_ASK_TERMINAL
|| ENABLE_FEATURE_LESS_ASK_TERMINAL
)
&& n >= 5 && n >= 5
&& buffer[0] == '[' && buffer[0] == '['
&& buffer[n-1] == 'R' && buffer[n-1] == 'R'

View File

@ -360,72 +360,6 @@ config FEATURE_LAST_FANCY
logged into the system (mimics sysvinit last). +900 bytes. logged into the system (mimics sysvinit last). +900 bytes.
endchoice endchoice
config LESS
bool "less"
default y
help
'less' is a pager, meaning that it displays text files. It possesses
a wide array of features, and is an improvement over 'more'.
config FEATURE_LESS_MAXLINES
int "Max number of input lines less will try to eat"
default 9999999
depends on LESS
config FEATURE_LESS_BRACKETS
bool "Enable bracket searching"
default y
depends on LESS
help
This option adds the capability to search for matching left and right
brackets, facilitating programming.
config FEATURE_LESS_FLAGS
bool "Enable extra flags"
default y
depends on LESS
help
The extra flags provided do the following:
The -M flag enables a more sophisticated status line.
The -m flag enables a simpler status line with a percentage.
config FEATURE_LESS_MARKS
bool "Enable marks"
default y
depends on LESS
help
Marks enable positions in a file to be stored for easy reference.
config FEATURE_LESS_REGEXP
bool "Enable regular expressions"
default y
depends on LESS
help
Enable regular expressions, allowing complex file searches.
config FEATURE_LESS_WINCH
bool "Enable automatic resizing on window size changes"
default y
depends on LESS
help
Makes less track window size changes.
config FEATURE_LESS_DASHCMD
bool "Enable flag changes ('-' command)"
default y
depends on LESS
help
This enables the ability to change command-line flags within
less itself ('-' keyboard command).
config FEATURE_LESS_LINENUMS
bool "Enable dynamic switching of line numbers"
default y
depends on FEATURE_LESS_DASHCMD
help
Enables "-N" command.
config HDPARM config HDPARM
bool "hdparm" bool "hdparm"
default y default y

View File

@ -21,6 +21,85 @@
* redirected input has been read from stdin * redirected input has been read from stdin
*/ */
//config:config LESS
//config: bool "less"
//config: default y
//config: help
//config: 'less' is a pager, meaning that it displays text files. It possesses
//config: a wide array of features, and is an improvement over 'more'.
//config:
//config:config FEATURE_LESS_MAXLINES
//config: int "Max number of input lines less will try to eat"
//config: default 9999999
//config: depends on LESS
//config:
//config:config FEATURE_LESS_BRACKETS
//config: bool "Enable bracket searching"
//config: default y
//config: depends on LESS
//config: help
//config: This option adds the capability to search for matching left and right
//config: brackets, facilitating programming.
//config:
//config:config FEATURE_LESS_FLAGS
//config: bool "Enable extra flags"
//config: default y
//config: depends on LESS
//config: help
//config: The extra flags provided do the following:
//config:
//config: The -M flag enables a more sophisticated status line.
//config: The -m flag enables a simpler status line with a percentage.
//config:
//config:config FEATURE_LESS_MARKS
//config: bool "Enable marks"
//config: default y
//config: depends on LESS
//config: help
//config: Marks enable positions in a file to be stored for easy reference.
//config:
//config:config FEATURE_LESS_REGEXP
//config: bool "Enable regular expressions"
//config: default y
//config: depends on LESS
//config: help
//config: Enable regular expressions, allowing complex file searches.
//config:
//config:config FEATURE_LESS_WINCH
//config: bool "Enable automatic resizing on window size changes"
//config: default y
//config: depends on LESS
//config: help
//config: Makes less track window size changes.
//config:
//config:config FEATURE_LESS_ASK_TERMINAL
//config: bool "Use 'tell me cursor position' ESC sequence to measure window"
//config: default y
//config: depends on FEATURE_LESS_WINCH
//config: help
//config: Makes less track window size changes.
//config: If terminal size can't be retrieved and $LINES/$COLUMNS are not set,
//config: this option makes less perform a last-ditch effort to find it:
//config: position cursor to 999,999 and ask terminal to report real
//config: cursor position using "ESC [ 6 n" escape sequence, then read stdin.
//config:
//config: This is not clean but helps a lot on serial lines and such.
//config:
//config:config FEATURE_LESS_DASHCMD
//config: bool "Enable flag changes ('-' command)"
//config: default y
//config: depends on LESS
//config: help
//config: This enables the ability to change command-line flags within
//config: less itself ('-' keyboard command).
//config:
//config:config FEATURE_LESS_LINENUMS
//config: bool "Enable dynamic switching of line numbers"
//config: default y
//config: depends on FEATURE_LESS_DASHCMD
//config: help
//config: Enables "-N" command.
//usage:#define less_trivial_usage //usage:#define less_trivial_usage
//usage: "[-EMNmh~I?] [FILE]..." //usage: "[-EMNmh~I?] [FILE]..."
//usage:#define less_full_usage "\n\n" //usage:#define less_full_usage "\n\n"
@ -107,6 +186,9 @@ struct globals {
int num_matches; int num_matches;
regex_t pattern; regex_t pattern;
smallint pattern_valid; smallint pattern_valid;
#endif
#if ENABLE_FEATURE_LESS_ASK_TERMINAL
smallint winsize_err;
#endif #endif
smallint terminated; smallint terminated;
struct termios term_orig, term_less; struct termios term_orig, term_less;
@ -815,12 +897,17 @@ static void reinitialize(void)
cur_fline = 0; cur_fline = 0;
max_lineno = 0; max_lineno = 0;
open_file_and_read_lines(); open_file_and_read_lines();
#if ENABLE_FEATURE_LESS_ASK_TERMINAL
if (G.winsize_err)
printf("\033[999;999H" "\033[6n");
#endif
buffer_fill_and_print(); buffer_fill_and_print();
} }
static int getch_nowait(void) static int64_t getch_nowait(void)
{ {
int rd; int rd;
int64_t key64;
struct pollfd pfd[2]; struct pollfd pfd[2];
pfd[0].fd = STDIN_FILENO; pfd[0].fd = STDIN_FILENO;
@ -868,8 +955,8 @@ static int getch_nowait(void)
/* We have kbd_fd in O_NONBLOCK mode, read inside read_key() /* We have kbd_fd in O_NONBLOCK mode, read inside read_key()
* would not block even if there is no input available */ * would not block even if there is no input available */
rd = read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); key64 = read_key(kbd_fd, kbd_input, /*timeout off:*/ -2);
if (rd == -1) { if ((int)key64 == -1) {
if (errno == EAGAIN) { if (errno == EAGAIN) {
/* No keyboard input available. Since poll() did return, /* No keyboard input available. Since poll() did return,
* we should have input on stdin */ * we should have input on stdin */
@ -881,25 +968,29 @@ static int getch_nowait(void)
less_exit(0); less_exit(0);
} }
set_tty_cooked(); set_tty_cooked();
return rd; return key64;
} }
/* Grab a character from input without requiring the return key. /* Grab a character from input without requiring the return key.
* May return KEYCODE_xxx values. * May return KEYCODE_xxx values.
* Note that this function works best with raw input. */ * Note that this function works best with raw input. */
static int less_getch(int pos) static int64_t less_getch(int pos)
{ {
int i; int64_t key64;
int key;
again: again:
less_gets_pos = pos; less_gets_pos = pos;
i = getch_nowait(); key = key64 = getch_nowait();
less_gets_pos = -1; less_gets_pos = -1;
/* Discard Ctrl-something chars */ /* Discard Ctrl-something chars.
if (i >= 0 && i < ' ' && i != 0x0d && i != 8) * (checking only lower 32 bits is a size optimization:
* upper 32 bits are used only by KEYCODE_CURSOR_POS)
*/
if (key >= 0 && key < ' ' && key != 0x0d && key != 8)
goto again; goto again;
return i; return key;
} }
static char* less_gets(int sz) static char* less_gets(int sz)
@ -1514,8 +1605,6 @@ static void sigwinch_handler(int sig UNUSED_PARAM)
int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int less_main(int argc, char **argv) int less_main(int argc, char **argv)
{ {
int keypress;
INIT_G(); INIT_G();
/* TODO: -x: do not interpret backspace, -xx: tab also */ /* TODO: -x: do not interpret backspace, -xx: tab also */
@ -1558,7 +1647,7 @@ int less_main(int argc, char **argv)
term_less.c_cc[VMIN] = 1; term_less.c_cc[VMIN] = 1;
term_less.c_cc[VTIME] = 0; term_less.c_cc[VTIME] = 0;
get_terminal_width_height(kbd_fd, &width, &max_displayed_line); IF_FEATURE_LESS_ASK_TERMINAL(G.winsize_err =) get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
/* 20: two tabstops + 4 */ /* 20: two tabstops + 4 */
if (width < 20 || max_displayed_line < 3) if (width < 20 || max_displayed_line < 3)
return bb_cat(argv); return bb_cat(argv);
@ -1573,11 +1662,14 @@ int less_main(int argc, char **argv)
buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
reinitialize(); reinitialize();
while (1) { while (1) {
int64_t keypress;
#if ENABLE_FEATURE_LESS_WINCH #if ENABLE_FEATURE_LESS_WINCH
while (WINCH_COUNTER) { while (WINCH_COUNTER) {
again: again:
winch_counter--; winch_counter--;
get_terminal_width_height(kbd_fd, &width, &max_displayed_line); IF_FEATURE_LESS_ASK_TERMINAL(G.winsize_err =) get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
IF_FEATURE_LESS_ASK_TERMINAL(got_size:)
/* 20: two tabstops + 4 */ /* 20: two tabstops + 4 */
if (width < 20) if (width < 20)
width = 20; width = 20;
@ -1597,8 +1689,18 @@ int less_main(int argc, char **argv)
/* This took some time. Loop back and check, /* This took some time. Loop back and check,
* were there another SIGWINCH? */ * were there another SIGWINCH? */
} }
#endif
keypress = less_getch(-1); /* -1: do not position cursor */ keypress = less_getch(-1); /* -1: do not position cursor */
# if ENABLE_FEATURE_LESS_ASK_TERMINAL
if ((int32_t)keypress == KEYCODE_CURSOR_POS) {
uint32_t rc = (keypress >> 32);
width = (rc & 0x7fff);
max_displayed_line = ((rc >> 16) & 0x7fff);
goto got_size;
}
# endif
#else
keypress = less_getch(-1); /* -1: do not position cursor */
#endif
keypress_process(keypress); keypress_process(keypress);
} }
} }