From 66c9b8f39acbba587eda0cababa3de37e89b8dff Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 10 Apr 2023 10:20:15 +0100 Subject: ash,hush: tab completion of functions and aliases Rework the 'get_exe_name' functions in ash and hush so functions and aliases are considered when tab-completing a command. function old new delta ash_command_name - 188 +188 hush_command_name - 118 +118 complete_cmd_dir_file 876 880 +4 ash_builtin_name 17 - -17 hush_builtin_name 38 - -38 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 1/0 up/down: 310/-55) Total: 255 bytes (GitHub issue #301) Signed-off-by: Ron Yorston --- include/libbb.h | 9 ++++++++- libbb/lineedit.c | 8 ++++++-- shell/ash.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- shell/hush.c | 34 +++++++++++++++++++++++++++------- 4 files changed, 84 insertions(+), 15 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 6191debb1..66781da4f 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1924,7 +1924,14 @@ 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 exe_state { + int e_type; /* type of tab completion: builtin, alias, function */ + int e_index; /* index of current table entry or hash bucket */ +# if ENABLE_SHELL_ASH || (ENABLE_SHELL_HUSH && ENABLE_HUSH_FUNCTIONS) + void *e_ptr; /* current position in linked list */ +# endif +} exe_state; +typedef const char *get_exe_name_t(exe_state *e) FAST_FUNC; typedef const char *sh_get_var_t(const char *name) FAST_FUNC; typedef struct line_input_t { int flags; diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 625884adf..5daceff16 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -875,9 +875,13 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) # endif # if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH if (state->get_exe_name) { - i = 0; +# if ENABLE_SHELL_ASH || (ENABLE_SHELL_HUSH && ENABLE_HUSH_FUNCTIONS) + exe_state e = { 0, 0, NULL }; +# else + exe_state e = { 0, 0 }; +# endif for (;;) { - const char *b = state->get_exe_name(i++); + const char *b = state->get_exe_name(&e); if (!b) break; if (strncmp(basecmd, b, baselen) == 0) diff --git a/shell/ash.c b/shell/ash.c index 26239ff09..c77ee8620 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -9732,7 +9732,7 @@ evalpipe(union node *n, int flags) /* setinteractive needs this forward reference */ #if ENABLE_FEATURE_TAB_COMPLETION -static const char *ash_builtin_name(int i) FAST_FUNC; +static const char *ash_command_name(exe_state *e) FAST_FUNC; #endif /* @@ -9769,7 +9769,7 @@ setinteractive(int on) if (!line_input_state) { line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); # if ENABLE_FEATURE_TAB_COMPLETION - line_input_state->get_exe_name = ash_builtin_name; + line_input_state->get_exe_name = ash_command_name; # endif # if EDITING_HAS_sh_get_var line_input_state->sh_get_var = lookupvar; @@ -10284,9 +10284,47 @@ find_builtin(const char *name) #if ENABLE_FEATURE_TAB_COMPLETION static const char * FAST_FUNC -ash_builtin_name(int i) -{ - return /*i >= 0 &&*/ i < ARRAY_SIZE(builtintab) ? builtintab[i].name + 1 : NULL; +ash_command_name(struct exe_state *e) +{ + if (e->e_type == 0) { + if (/*e->e_index >= 0 &&*/ e->e_index < ARRAY_SIZE(builtintab)) { + return builtintab[e->e_index++].name + 1; + } + e->e_type++; + e->e_index = 0; + e->e_ptr = cmdtable[0]; + } + if (e->e_type == 1) { + struct tblentry *cmdp = (struct tblentry *)e->e_ptr; + while (e->e_index < CMDTABLESIZE) { + while (cmdp) { + if (cmdp->cmdtype == CMDFUNCTION) { + e->e_ptr = cmdp->next; + return cmdp->cmdname; + } + cmdp = cmdp->next; + } + cmdp = cmdtable[++e->e_index]; + } +# if ENABLE_ASH_ALIAS + e->e_type++; + e->e_index = 0; + e->e_ptr = atab[0]; +# endif + } +# if ENABLE_ASH_ALIAS + if (e->e_type == 2) { + struct alias *ap = (struct alias *)e->e_ptr; + while (e->e_index < ATABSIZE) { + while (ap) { + e->e_ptr = ap->next; + return ap->name; + } + ap = atab[++e->e_index]; + } + } +# endif + return NULL; } #endif diff --git a/shell/hush.c b/shell/hush.c index 330a0aa79..443bdeccf 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -8220,15 +8220,35 @@ static const struct built_in_command *find_builtin(const char *name) } #if ENABLE_HUSH_JOB && ENABLE_FEATURE_TAB_COMPLETION -static const char * FAST_FUNC hush_builtin_name(int i) +static const char * FAST_FUNC hush_command_name(exe_state *e) { - if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { - return bltins1[i].b_cmd; + if (e->e_type == 0) { + if (/*e->e_index >= 0 && */ e->e_index < ARRAY_SIZE(bltins1)) { + return bltins1[e->e_index++].b_cmd; + } + e->e_type++; + e->e_index = 0; + /* e->e_ptr = NULL; */ + } + if (e->e_type == 1) { + if (e->e_index < ARRAY_SIZE(bltins2)) { + return bltins2[e->e_index++].b_cmd; + } +# if ENABLE_HUSH_FUNCTIONS + e->e_type++; + /* e->e_index = 0; */ + e->e_ptr = G.top_func; +# endif } - i -= ARRAY_SIZE(bltins1); - if (i < ARRAY_SIZE(bltins2)) { - return bltins2[i].b_cmd; +# if ENABLE_HUSH_FUNCTIONS + if (e->e_type == 2) { + struct function *funcp = (struct function *)e->e_ptr; + while (funcp) { + e->e_ptr = funcp->next; + return funcp->name; + } } +# endif return NULL; } #endif @@ -10716,7 +10736,7 @@ int hush_main(int argc, char **argv) # if ENABLE_FEATURE_EDITING G.line_input_state = new_line_input_t(FOR_SHELL); # if ENABLE_FEATURE_TAB_COMPLETION - G.line_input_state->get_exe_name = hush_builtin_name; + G.line_input_state->get_exe_name = hush_command_name; # endif # if EDITING_HAS_sh_get_var G.line_input_state->sh_get_var = get_local_var_value; -- cgit v1.2.3-55-g6feb