From 9e2a5668fd38db169d9d91b13089a99df4c9bd37 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 21 Jan 2020 16:01:58 +0000 Subject: [PATCH] ash,hush: allow builtins to be tab-completed, closes 7532 function old new delta complete_cmd_dir_file 678 830 +152 get_builtin_name - 35 +35 optschanged 125 132 +7 hush_main 1069 1076 +7 save_command_ps_at_cur_history 76 78 +2 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 4/0 up/down: 203/0) Total: 203 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- include/libbb.h | 13 +++++++++++++ libbb/lineedit.c | 17 ++++++++++++++--- shell/ash.c | 19 ++++++++++++++++++- shell/hush.c | 17 +++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 05a560977..392c0443d 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1818,10 +1818,19 @@ unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC; # else # define MAX_HISTORY 0 # endif +typedef const char *get_exe_name_t(int i) FAST_FUNC; typedef struct line_input_t { int flags; int timeout; const char *path_lookup; +# if ENABLE_FEATURE_TAB_COMPLETION \ +&& (ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH \ +|| ENABLE_HUSH || ENABLE_SH_IS_HUSH || ENABLE_BASH_IS_HUSH \ +) + /* function to fetch additional application-specific names to match */ + get_exe_name_t *get_exe_name; +# define EDITING_HAS_get_exe_name 1 +# endif # if MAX_HISTORY int cnt_history; int cur_history; @@ -1868,6 +1877,10 @@ int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; read_line_input(prompt, command, maxsize) #endif +#ifndef EDITING_HAS_get_exe_name +# define EDITING_HAS_get_exe_name 0 +#endif + #ifndef COMM_LEN # ifdef TASK_COMM_LEN diff --git a/libbb/lineedit.c b/libbb/lineedit.c index b1ec52b88..de236dea0 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -813,18 +813,29 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) } pf_len = strlen(pfind); -# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 if (type == FIND_EXE_ONLY && !dirbuf) { +# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 const char *p = applet_names; - while (*p) { if (strncmp(pfind, p, pf_len) == 0) add_match(xstrdup(p)); while (*p++ != '\0') continue; } - } # endif +# if EDITING_HAS_get_exe_name + if (state->get_exe_name) { + i = 0; + for (;;) { + const char *b = state->get_exe_name(i++); + if (!b) + break; + if (strncmp(pfind, b, pf_len) == 0) + add_match(xstrdup(b)); + } + } +# endif + } for (i = 0; i < npaths; i++) { DIR *dir; diff --git a/shell/ash.c b/shell/ash.c index d6040f47e..fb4028219 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -9523,6 +9523,11 @@ evalpipe(union node *n, int flags) return status; } +/* setinteractive needs this forward reference */ +#if EDITING_HAS_get_exe_name +static const char *get_builtin_name(int i) FAST_FUNC; +#endif + /* * Controls whether the shell is interactive or not. */ @@ -9554,8 +9559,12 @@ setinteractive(int on) } #endif #if ENABLE_FEATURE_EDITING - if (!line_input_state) + if (!line_input_state) { line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); +# if EDITING_HAS_get_exe_name + line_input_state->get_exe_name = get_builtin_name; +# endif + } #endif } } @@ -10023,6 +10032,14 @@ find_builtin(const char *name) return bp; } +#if EDITING_HAS_get_exe_name +static const char * FAST_FUNC +get_builtin_name(int i) +{ + return /*i >= 0 &&*/ i < ARRAY_SIZE(builtintab) ? builtintab[i].name + 1 : NULL; +} +#endif + /* * Execute a simple command. */ diff --git a/shell/hush.c b/shell/hush.c index 97202b953..6e44d4e11 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7889,6 +7889,20 @@ static const struct built_in_command *find_builtin(const char *name) return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); } +#if EDITING_HAS_get_exe_name +static const char * FAST_FUNC get_builtin_name(int i) +{ + if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { + return bltins1[i].b_cmd; + } + i -= ARRAY_SIZE(bltins1); + if (i < ARRAY_SIZE(bltins2)) { + return bltins2[i].b_cmd; + } + return NULL; +} +#endif + static void remove_nested_vars(void) { struct variable *cur; @@ -10268,6 +10282,9 @@ int hush_main(int argc, char **argv) # if ENABLE_FEATURE_EDITING G.line_input_state = new_line_input_t(FOR_SHELL); +# if EDITING_HAS_get_exe_name + G.line_input_state->get_exe_name = get_builtin_name; +# endif # endif # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 {