From 211f8bf76d4491383c754038bfcf4a37148bec41 Mon Sep 17 00:00:00 2001 From: Nghia Ho Date: Sun, 1 Nov 2015 01:41:01 -0700 Subject: [PATCH] bug fix:: Never reach readline_prompt() in nsh_initialize, moved it up to the top. Works now. enhancement: TAB completion now works like Unix, it will autocomplete as much as possible for multiple matches. --- nshlib/nsh_init.c | 24 +++++++------- system/readline/readline_common.c | 53 ++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/nshlib/nsh_init.c b/nshlib/nsh_init.c index 2bd29b8c5..8e185b601 100644 --- a/nshlib/nsh_init.c +++ b/nshlib/nsh_init.c @@ -101,6 +101,18 @@ static const struct extmatch_vtable_s g_nsh_extmatch = void nsh_initialize(void) { +#if defined(CONFIG_NSH_READLINE) && defined(CONFIG_READLINE_TABCOMPLETION) + /* Configure the NSH prompt */ + + (void)readline_prompt(g_nshprompt); + +#ifdef CONFIG_READLINE_HAVE_EXTMATCH + /* Set up for tab completion on NSH commands */ + + (void)readline_extmatch(&g_nsh_extmatch); +#endif +#endif + /* Mount the /etc filesystem */ (void)nsh_romfsetc(); @@ -114,16 +126,4 @@ void nsh_initialize(void) /* Bring up the network */ (void)nsh_netinit(); - -#if defined(CONFIG_NSH_READLINE) && defined(CONFIG_READLINE_TABCOMPLETION) - /* Configure the NSH prompt */ - - (void)readline_prompt(g_nshprompt); - -#ifdef CONFIG_READLINE_HAVE_EXTMATCH - /* Set up for tab completion on NSH commands */ - - (void)readline_extmatch(&g_nsh_extmatch); -#endif -#endif } diff --git a/system/readline/readline_common.c b/system/readline/readline_common.c index 3aa6faa9a..5cf0b8638 100644 --- a/system/readline/readline_common.c +++ b/system/readline/readline_common.c @@ -147,6 +147,8 @@ static void tab_completion(FAR struct rl_common_s *vtbl, char *buf, int len = *nch; int i; int j; + int name_len; + char tmp_name[CONFIG_TASK_NAME_SIZE+1]; if (len >= 1) { @@ -177,8 +179,6 @@ static void tab_completion(FAR struct rl_common_s *vtbl, char *buf, if (nr_matches == 1) { - int name_len; - /* Yes... that that is the one we want. Was it a match with a * builtin command? Or with an external command. */ @@ -229,18 +229,40 @@ static void tab_completion(FAR struct rl_common_s *vtbl, char *buf, { RL_PUTC(vtbl, '\n'); + /* See how many characters we can auto complete for the user + * For example, if we have the following commands: + * - prog1 + * - prog2 + * - prog3 + * then it should automatically complete up to prog. + * We do this in one pass using a temp */ + + memset(tmp_name, 0, sizeof(tmp_name)); #ifdef CONFIG_READLINE_HAVE_EXTMATCH /* Show the possible external completions */ for (i = 0; i < nr_ext_matches; i++) { name = g_extmatch_vtbl->getname(ext_matches[i]); + /* initialize temp */ + + if (tmp_name[0] == '\0') + { + strcpy(tmp_name, name); + } RL_PUTC(vtbl, ' '); RL_PUTC(vtbl, ' '); for (j = 0; j < strlen(name); j++) { + /* removing characters that aren't common to all the + * matches */ + + if (name[j] != tmp_name[j]) + { + tmp_name[j] = '\0'; + } RL_PUTC(vtbl, name[j]); } @@ -254,18 +276,34 @@ static void tab_completion(FAR struct rl_common_s *vtbl, char *buf, for (i = 0; i < nr_builtin_matches; i++) { name = builtin_getname(builtin_matches[i]); + /* initialize temp */ + + if (tmp_name[0] == '\0') + { + strcpy(tmp_name, name); + } RL_PUTC(vtbl, ' '); RL_PUTC(vtbl, ' '); for (j = 0; j < strlen(name); j++) { + /* removing characters that aren't common to all the + * matches */ + + if (name[j] != tmp_name[j]) + { + tmp_name[j] = '\0'; + } RL_PUTC(vtbl, name[j]); } RL_PUTC(vtbl, '\n'); } #endif + strcpy(buf, tmp_name); + + name_len = strlen(tmp_name); /* Output the original prompt */ @@ -277,10 +315,17 @@ static void tab_completion(FAR struct rl_common_s *vtbl, char *buf, } } - for (i = 0; i < len; i++) + for (i = 0; i < name_len; i++) { RL_PUTC(vtbl, buf[i]); } + + /* Don't remove extra characters after the completed word, if any. */ + + if (len < name_len) + { + *nch = name_len; + } } } } @@ -341,7 +386,7 @@ FAR const char *readline_prompt(FAR const char *prompt) * Assumptions: * The vtbl string is statically allocated a global. readline() will * simply remember the pointer to the structure. The structure must stay - * allocated and available. Only one instance of such a structure is + * allocated and available. Only one instance of such a structure is * supported. If there are multiple clients of readline(), they must all * share the same tab-completion logic (with exceptions in the case of * the kernel build).