ash,hush: allow builtins to be tab-completed, closes 7532
authorRon Yorston <rmy@pobox.com>
Tue, 21 Jan 2020 16:01:58 +0000 (16:01 +0000)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 29 Jan 2020 14:23:17 +0000 (15:23 +0100)
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 <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
include/libbb.h
libbb/lineedit.c
shell/ash.c
shell/hush.c

index 05a5609776e882c699d3dc63e825c2ad17cc0e4b..392c0443d324e271bf561c02424f9489d92e1160 100644 (file)
@@ -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
index b1ec52b88c19034acac96b297246320689733c11..de236dea0223f9b9845fd5c544652fc69fb1f594 100644 (file)
@@ -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;
index d6040f47ec4288dda1208f26ed0e2398aab09246..fb4028219452d4d3639e826c6473dca1c1e8c3ef 100644 (file)
@@ -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.
  */
index 97202b9532a312aff1d4f39bb1e35ed260e9c758..6e44d4e115f1fc18a5d3d5f38c9488ec89930a9e 100644 (file)
@@ -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
                {