From f1da85d44ed96ed85c1463cf3d416fd6bc48b50c Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Tue, 21 Nov 2017 17:45:50 +0100 Subject: [PATCH] vsh: Call vshCmdOptDef completer Now that we have everything prepared we can call options' completer again. At the same time, pass partially parsed input to the completer callback - it will help the callbacks to narrow down the list of returned options based on user's input. For instance, if the completer is supposed to return list of interfaces depending on user input it may return just those interfaces defined for already specified domain. Of course, completers might ignore this parameter. Signed-off-by: Michal Privoznik --- tools/vsh.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- tools/vsh.h | 1 + 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/tools/vsh.c b/tools/vsh.c index 2d1be20bd6..9fbbfb4767 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -2708,6 +2708,36 @@ vshReadlineOptionsGenerator(const char *text, const vshCmdDef *cmd) return ret; } + +static const vshCmdOptDef * +vshReadlineCommandFindOpt(const vshCmd *partial, + const char *text) +{ + const vshCmd *tmp = partial; + + while (tmp && tmp->next) { + if (tmp->def == tmp->next->def && + !tmp->next->opts) + break; + tmp = tmp->next; + } + + if (tmp && tmp->opts) { + const vshCmdOpt *opt = tmp->opts; + + while (opt) { + if (STREQ_NULLABLE(opt->data, text) || + STREQ_NULLABLE(opt->data, " ")) + return opt->def; + + opt = opt->next; + } + } + + return NULL; +} + + static char * vshReadlineParse(const char *text, int state) { @@ -2715,6 +2745,7 @@ vshReadlineParse(const char *text, int state) static char **list; static size_t list_index; const vshCmdDef *cmd = NULL; + const vshCmdOptDef *opt = NULL; char *ret = NULL; if (!state) { @@ -2732,8 +2763,10 @@ vshReadlineParse(const char *text, int state) VIR_FREE(buf); - if (partial) + if (partial) { cmd = partial->def; + partial->skipChecks = true; + } if (cmd && STREQ(cmd->name, text)) { /* Corner case - some commands share prefix (e.g. @@ -2745,13 +2778,26 @@ vshReadlineParse(const char *text, int state) */ cmd = NULL; } + + opt = vshReadlineCommandFindOpt(partial, text); } if (!list) { if (!cmd) { list = vshReadlineCommandGenerator(text); } else { - list = vshReadlineOptionsGenerator(text, cmd); + if (!opt || (opt->type != VSH_OT_DATA && opt->type != VSH_OT_STRING)) + list = vshReadlineOptionsGenerator(text, cmd); + + if (opt && opt->completer) { + char **completer_list = opt->completer(autoCompleteOpaque, + partial, + opt->completer_flags); + if (virStringListMerge(&list, &completer_list) < 0) { + virStringListFree(completer_list); + goto cleanup; + } + } } } @@ -2768,6 +2814,7 @@ vshReadlineParse(const char *text, int state) ret = virBufferContentAndReset(&buf); } + cleanup: if (!ret) { vshCommandFree(partial); partial = NULL; diff --git a/tools/vsh.h b/tools/vsh.h index 51f8ef2135..ae40fb4e8e 100644 --- a/tools/vsh.h +++ b/tools/vsh.h @@ -124,6 +124,7 @@ typedef struct _vshCmdOptDef vshCmdOptDef; typedef struct _vshControl vshControl; typedef char **(*vshCompleter)(vshControl *ctl, + const vshCmd *cmd, unsigned int flags); /*