Now that we have a way of retrieving partly parsed command we
don't need duplicate code that parses the user's input.
Yes, this code removes call of opt's completer, but:
a) current implementation is broken anyway, and
b) it will be added back shortly
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
tools/vsh.c | 214 +++++++-----------------------------------------------------
1 file changed, 24 insertions(+), 190 deletions(-)
diff --git a/tools/vsh.c b/tools/vsh.c
index 34eb592ef..c3423d6e3 100644
--- a/tools/vsh.c
+++ b/tools/vsh.c
@@ -2697,216 +2697,50 @@ vshReadlineOptionsGenerator(const char *text, int state, const
vshCmdDef *cmd_pa
static char *
vshReadlineParse(const char *text, int state)
{
- static vshCommandParser parser, sanitizer;
- vshCommandToken tk;
+ static vshCmd *partial;
static const vshCmdDef *cmd;
- const vshCmdOptDef *opt = NULL;
- char *tkdata, *optstr, *const_tkdata, *completed_name;
char *res = NULL;
- static char *ctext, *sanitized_text;
- static char **completed_list;
- static unsigned int completed_list_index;
- static uint64_t const_opts_need_arg, const_opts_required, const_opts_seen;
- uint64_t opts_seen;
- size_t opt_index;
- static bool cmd_exists, opts_filled, opt_exists;
- static bool non_bool_opt_exists, data_complete;
if (!state) {
- parser.pos = rl_line_buffer;
- parser.getNextArg = vshCommandStringGetArg;
-
- ctext = vshStrdup(NULL, text);
- sanitizer.pos = ctext;
- sanitizer.getNextArg = vshCommandStringGetArg;
-
- const_tkdata = NULL;
- tkdata = NULL;
- sanitized_text = NULL;
- optstr = NULL;
-
- completed_list = NULL;
- completed_list_index = 0;
-
- /* Sanitize/de-quote the autocomplete text */
- tk = sanitizer.getNextArg(NULL, &sanitizer, &sanitized_text, false);
-
- /* No autocomplete if sanitized text is a token error or token end */
- if (tk == VSH_TK_ERROR)
- goto error;
-
- tk = parser.getNextArg(NULL, &parser, &const_tkdata, false);
-
- if (tk == VSH_TK_ERROR)
- goto error;
-
- /* Free-ing purposes */
- tkdata = const_tkdata;
- /* Skip leading space */
- virSkipSpaces((const char**)&tkdata);
-
- /* Handle ';'s */
- while (tk == VSH_TK_SUBCMD_END) {
- tk = parser.getNextArg(NULL, &parser, &const_tkdata, false);
- tkdata = const_tkdata;
- }
-
- /* Skip trailing space after ;*/
- virSkipSpaces((const char**)&tkdata);
-
- cmd_exists = false;
- opts_filled = false;
- non_bool_opt_exists = false;
- data_complete = false;
-
- const_opts_need_arg = 0;
- const_opts_required = 0;
- const_opts_seen = 0;
-
- opt_index = 0;
+ char *buf = vshStrdup(NULL, rl_line_buffer);
+ vshCommandFree(partial);
+ partial = NULL;
cmd = NULL;
- opt = NULL;
- /* Parse till text to be auto-completed is reached */
- while (STRNEQ(tkdata, sanitized_text)) {
- if (!cmd) {
- if (!(cmd = vshCmddefSearch(tkdata)))
- goto error;
- if (cmd->flags & VSH_CMD_FLAG_ALIAS)
- cmd = vshCmddefSearch(cmd->alias);
+ *(buf + rl_point) = '\0';
- cmd_exists = true;
- if (vshCmddefOptParse(cmd, &const_opts_need_arg,
- &const_opts_required) < 0)
- goto error;
- opts_seen = const_opts_seen;
- opts_filled = true;
- } else if (tkdata[0] == '-' && tkdata[1] == '-'
&&
- c_isalnum(tkdata[2])) {
- /* Command retrieved successfully, move to options */
- optstr = strchr(tkdata + 2, '=');
- opt_index = 0;
+ vshCommandStringParse(NULL, buf, &partial);
- if (optstr) {
- *optstr = '\0';
- optstr = vshStrdup(NULL, optstr + 1);
- }
+ VIR_FREE(buf);
- if (!(opt = vshCmddefGetOption(NULL, cmd, tkdata + 2,
- &opts_seen, &opt_index,
- &optstr, false))) {
- /* Parsing failed wrt autocomplete */
- VIR_FREE(optstr);
- goto error;
- }
+ if (partial)
+ cmd = partial->def;
- opts_seen = const_opts_seen;
- opt_exists = true;
- VIR_FREE(const_tkdata);
- if (opt->type != VSH_OT_BOOL) {
- non_bool_opt_exists = true;
- /* Opt exists and check for option data */
- if (optstr) {
- const_tkdata = optstr;
- tkdata = const_tkdata;
- } else {
- VIR_FREE(const_tkdata);
- tk = parser.getNextArg(NULL, &parser, &const_tkdata,
- false);
-
- if (tk == VSH_TK_ERROR)
- goto error;
-
- tkdata = const_tkdata;
- virSkipSpaces((const char **)&tkdata);
- }
- if (STREQ(tkdata, sanitized_text)) {
- /* auto-complete non-bool option arg */
- data_complete = true;
- break;
- }
- non_bool_opt_exists = false;
- } else {
- tkdata = NULL;
- /* opt type is BOOL */
- if (optstr) {
- VIR_FREE(optstr);
- goto error;
- }
- }
- } else if (!opt_exists) {
- /* No -- option provided and some other token given
- * Try to find the default option.
- */
- if (!(opt = vshCmddefGetData(cmd, &const_opts_need_arg,
- &const_opts_seen))
- || opt->type == VSH_OT_BOOL)
- goto error;
- opt_exists = true;
- opts_seen = const_opts_seen;
- } else {
- /* In every other case, return NULL */
- goto error;
- }
-
- VIR_FREE(const_tkdata);
- tk = parser.getNextArg(NULL, &parser, &const_tkdata, false);
-
- if (tk == VSH_TK_ERROR)
- goto error;
-
- while (tk == VSH_TK_SUBCMD_END) {
- cmd = NULL;
- cmd_exists = false;
- opts_filled = false;
- opt = NULL;
- non_bool_opt_exists = false;
- tk = parser.getNextArg(NULL, &parser, &const_tkdata, false);
- }
-
- tkdata = const_tkdata;
-
- virSkipSpaces((const char**)&tkdata);
+ if (cmd && STREQ(cmd->name, text)) {
+ /* Corner case - some commands share prefix (e.g.
+ * dump and dumpxml). If user typed 'dump<TAB><TAB>',
+ * then @text = "dump" and we want to offer command
+ * completion. If they typed 'dump <TAB><TAB>' then
+ * @text = "" (the space after the command) and we
+ * want to offer options completion for dump command.
+ */
+ cmd = NULL;
}
- VIR_FREE(const_tkdata);
}
- if (!cmd_exists) {
- res = vshReadlineCommandGenerator(sanitized_text, state);
- } else if (opts_filled && !non_bool_opt_exists) {
- res = vshReadlineOptionsGenerator(sanitized_text, state, cmd);
- } else if (non_bool_opt_exists && data_complete && opt &&
opt->completer) {
- if (!completed_list)
- completed_list = opt->completer(autoCompleteOpaque,
- opt->completer_flags);
- if (completed_list) {
- while ((completed_name = completed_list[completed_list_index])) {
- completed_list_index++;
- if (!STRPREFIX(completed_name, sanitized_text))
- continue;
- res = vshStrdup(NULL, completed_name);
- return res;
- }
- res = NULL;
- virStringListFree(completed_list);
- completed_list_index = 0;
- }
+ if (!cmd) {
+ res = vshReadlineCommandGenerator(text, state);
+ } else {
+ res = vshReadlineOptionsGenerator(text, state, cmd);
}
if (!res) {
- VIR_FREE(sanitized_text);
- VIR_FREE(ctext);
+ vshCommandFree(partial);
+ partial = NULL;
}
return res;
-
- error:
- VIR_FREE(const_tkdata);
- VIR_FREE(sanitized_text);
- VIR_FREE(ctext);
- return NULL;
-
}
static char **
--
2.13.6