[PATCH] libbb/lineedit: tab completion pager
Fryderyk Wrobel
frd1996 at gmail.com
Mon Jul 15 13:30:57 UTC 2019
Hi there,
This patch adds a TAB-completion pager to the lineedit feature of libbb.
Below is the bloat-o-meter output and the patch for 1_31_stable branch.
Kind Regards,
Fryderyk
$ ./scripts/bloat-o-meter busybox_unstripped.1_31_stable
busybox_unstripped.1_31_completion_pager
function old new delta
input_tab 1126 1391 +265
.rodata 158112 158127 +15
read_line_input 2741 2753 +12
cmdedit_setwidth 56 55 -1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/1 up/down: 292/-1) Total: 291 bytes
---
libbb/Config.src | 5 ++++
libbb/lineedit.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 76 insertions(+), 2 deletions(-)
diff --git a/libbb/Config.src b/libbb/Config.src
index 312aa1831..af4b4b846 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -153,6 +153,11 @@ config FEATURE_USERNAME_COMPLETION
default y
depends on FEATURE_TAB_COMPLETION
+config FEATURE_TAB_COMPLETION_PAGER
+ bool "Use pager for large amount of completion results"
+ default n
+ depends on FEATURE_TAB_COMPLETION
+
config FEATURE_EDITING_FANCY_PROMPT
bool "Fancy shell prompts"
default y
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index fbabc6c12..6eb51f964 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -50,6 +50,7 @@
# define ENABLE_FEATURE_EDITING 0
# define ENABLE_FEATURE_TAB_COMPLETION 0
# define ENABLE_FEATURE_USERNAME_COMPLETION 0
+# define ENABLE_FEATURE_TAB_COMPLETION_PAGER 0
#endif
@@ -115,6 +116,7 @@ static bool BB_isalnum_or_underscore(CHAR_T c)
#define ESC "\033"
#define SEQ_CLEAR_TILL_END_OF_SCREEN ESC"[J"
+#define SEQ_CLEAR_TILL_BEGIN_OF_LINE ESC"[1K"
//#define SEQ_CLEAR_TILL_END_OF_LINE ESC"[K"
@@ -133,6 +135,7 @@ struct lineedit_statics {
line_input_t *state;
unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
+ unsigned cmdedit_termh; /* = 25; */ /* actual terminal height (lines) */
unsigned cmdedit_x; /* real x (col) terminal position */
unsigned cmdedit_y; /* pseudoreal y (row) terminal position */
@@ -186,6 +189,7 @@ extern struct lineedit_statics *const
lineedit_ptr_to_statics;
#define S (*lineedit_ptr_to_statics)
#define state (S.state )
#define cmdedit_termw (S.cmdedit_termw )
+#define cmdedit_termh (S.cmdedit_termh )
#define cmdedit_x (S.cmdedit_x )
#define cmdedit_y (S.cmdedit_y )
#define cmdedit_prmt_len (S.cmdedit_prmt_len)
@@ -206,6 +210,7 @@ extern struct lineedit_statics *const
lineedit_ptr_to_statics;
(*(struct lineedit_statics**)&lineedit_ptr_to_statics) = xzalloc(sizeof(S)); \
barrier(); \
cmdedit_termw = 80; \
+ cmdedit_termh = 25; \
IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \
IF_FEATURE_EDITING_VI(delptr = delbuf;) \
} while (0)
@@ -1055,6 +1060,43 @@ static NOINLINE int build_match_prefix(char *match_buf)
return command_mode;
}
+
+# if ENABLE_FEATURE_TAB_COMPLETION_PAGER
+
+static int lineedit_read_key(char *read_key_buffer, int timeout);
+
+/* Display the pager line and wait for the user */
+static int pager_wait(int nlines)
+{
+ char read_key_buffer[KEYCODE_BUFFER_SIZE];
+ int ic;
+
+ read_key_buffer[0] = 0;
+ while (1) {
+ printf("--More--");
+ ic = lineedit_read_key(read_key_buffer, -1); /* Calls fflush_all() */
+ printf(SEQ_CLEAR_TILL_BEGIN_OF_LINE "\r");
+
+ switch (ic) {
+ case -1: /* Error */
+ case 0: /* Timeout? */
+ case 3: /* ETX - result of CTRL+C */
+ case 'Q':
+ case 'q':
+ return 0; /* Don't print more */
+ case '\n':
+ return 1; /* Print one line */
+ case ' ':
+ return nlines; /* Print one page */
+ case 'R':
+ case 'r':
+ return -1; /* Print the rest */
+ }
+ }
+}
+
+# endif
+
/*
* Display by column (original idea from ls applet,
* very optimized by me [Vladimir] :)
@@ -1066,6 +1108,13 @@ static void showfiles(void)
int nfiles = num_matches;
int nrows = nfiles;
int l;
+# if ENABLE_FEATURE_TAB_COMPLETION_PAGER
+ int nlines, sl;
+
+ nlines = cmdedit_termh - 2;
+ if (nlines < 2)
+ nlines = -1; /* Disable paging for a really small terminals */
+# endif
/* find the longest file name - use that as the column width */
for (row = 0; row < nrows; row++) {
@@ -1083,7 +1132,12 @@ static void showfiles(void)
} else {
ncols = 1;
}
+
+# if ENABLE_FEATURE_TAB_COMPLETION_PAGER
+ for (row = 0, sl = nlines; row < nrows; row++, sl--) {
+# else
for (row = 0; row < nrows; row++) {
+# endif
int n = row;
int nc;
@@ -1096,6 +1150,20 @@ static void showfiles(void)
puts(printable_string(matches[n]));
else
puts(matches[n]);
+
+# if ENABLE_FEATURE_TAB_COMPLETION_PAGER
+ if (sl == 0) {
+ sl = pager_wait(nlines);
+ if (sl == 0)
+ break;
+ /*
+ * NB: When sl bcomes -1 then it is getting decreased
+ * every time the loop iterates. It will eventually
+ * overflow. Tht means the pager will kick in again
+ * after full range of 'int' type.
+ */
+ }
+# endif
}
}
@@ -2049,7 +2117,8 @@ static void cmdedit_setwidth(void)
{
int new_y;
- cmdedit_termw = get_terminal_width(STDIN_FILENO);
+ get_terminal_width_height(STDIN_FILENO, &cmdedit_termw, &cmdedit_termh);
+
/* new y for current cursor */
new_y = (cursor + cmdedit_prmt_len) / cmdedit_termw;
/* redraw */
@@ -2432,7 +2501,7 @@ int FAST_FUNC read_line_input(line_input_t *st,
const char *prompt, char *comman
#endif
/* Get width (before printing prompt) */
- cmdedit_termw = get_terminal_width(STDIN_FILENO);
+ get_terminal_width_height(STDIN_FILENO, &cmdedit_termw, &cmdedit_termh);
/* Print out the command prompt, optionally ask where cursor is */
parse_and_put_prompt(prompt);
ask_terminal();
--
2.16.4
More information about the busybox
mailing list