virsh: Introduce usage of option completers to auto-complete arguments

Call option completers if argument completion is requested using the
corresponding option completer, if it is defined.

Signed-off-by: Nishith Shah <nishithshah.2211@gmail.com>
This commit is contained in:
Nishith Shah 2016-09-05 09:45:09 +00:00 committed by Michal Privoznik
parent bae660869d
commit dcfdf341ea

View File

@ -2636,14 +2636,16 @@ vshReadlineParse(const char *text, int state)
vshCommandToken tk; vshCommandToken tk;
static const vshCmdDef *cmd; static const vshCmdDef *cmd;
const vshCmdOptDef *opt; const vshCmdOptDef *opt;
char *tkdata, *optstr, *const_tkdata; char *tkdata, *optstr, *const_tkdata, *completed_name;
char *res = NULL; char *res = NULL;
static char *ctext, *sanitized_text; 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; static uint64_t const_opts_need_arg, const_opts_required, const_opts_seen;
uint64_t opts_need_arg, opts_seen; uint64_t opts_need_arg, opts_seen;
size_t opt_index; size_t opt_index;
static bool cmd_exists, opts_filled, opt_exists; static bool cmd_exists, opts_filled, opt_exists;
static bool non_bool_opt_exists; static bool non_bool_opt_exists, data_complete;
if (!state) { if (!state) {
parser.pos = rl_line_buffer; parser.pos = rl_line_buffer;
@ -2658,6 +2660,9 @@ vshReadlineParse(const char *text, int state)
sanitized_text = NULL; sanitized_text = NULL;
optstr = NULL; optstr = NULL;
completed_list = NULL;
completed_list_index = 0;
/* Sanitize/de-quote the autocomplete text */ /* Sanitize/de-quote the autocomplete text */
tk = sanitizer.getNextArg(NULL, &sanitizer, &sanitized_text, false); tk = sanitizer.getNextArg(NULL, &sanitizer, &sanitized_text, false);
@ -2687,6 +2692,7 @@ vshReadlineParse(const char *text, int state)
cmd_exists = false; cmd_exists = false;
opts_filled = false; opts_filled = false;
non_bool_opt_exists = false; non_bool_opt_exists = false;
data_complete = false;
const_opts_need_arg = 0; const_opts_need_arg = 0;
const_opts_required = 0; const_opts_required = 0;
@ -2707,12 +2713,12 @@ vshReadlineParse(const char *text, int state)
if (vshCmddefOptFill(cmd, &const_opts_need_arg, if (vshCmddefOptFill(cmd, &const_opts_need_arg,
&const_opts_required) < 0) &const_opts_required) < 0)
goto error; goto error;
opts_need_arg = const_opts_need_arg;
opts_seen = const_opts_seen;
opts_filled = true; opts_filled = true;
} else if (tkdata[0] == '-' && tkdata[1] == '-' && } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
c_isalnum(tkdata[2])) { c_isalnum(tkdata[2])) {
/* Command retrieved successfully, move to options */ /* Command retrieved successfully, move to options */
opts_need_arg = const_opts_need_arg;
opts_seen = const_opts_seen;
optstr = strchr(tkdata + 2, '='); optstr = strchr(tkdata + 2, '=');
opt_index = 0; opt_index = 0;
@ -2728,6 +2734,7 @@ vshReadlineParse(const char *text, int state)
VIR_FREE(optstr); VIR_FREE(optstr);
goto error; goto error;
} }
opt_exists = true; opt_exists = true;
VIR_FREE(const_tkdata); VIR_FREE(const_tkdata);
if (opt->type != VSH_OT_BOOL) { if (opt->type != VSH_OT_BOOL) {
@ -2745,10 +2752,11 @@ vshReadlineParse(const char *text, int state)
goto error; goto error;
tkdata = const_tkdata; tkdata = const_tkdata;
if (STREQ(tkdata, sanitized_text)) { }
/* auto-complete non-bool option */ if (STREQ(tkdata, sanitized_text)) {
break; /* auto-complete non-bool option arg */
} data_complete = true;
break;
} }
if (opt->type != VSH_OT_ARGV) if (opt->type != VSH_OT_ARGV)
opts_need_arg &= ~(1ULL << opt_index); opts_need_arg &= ~(1ULL << opt_index);
@ -2760,17 +2768,19 @@ vshReadlineParse(const char *text, int state)
goto error; goto error;
} }
} }
} else { } else if (!opt_exists) {
/* No -- option provided and some other token given */ /* No -- option provided and some other token given
if (!opt_exists) { * Try to find the default option.
*/
if (!(opt = vshCmddefGetData(cmd, &opts_need_arg, &opts_seen))
&& opt->type == VSH_OT_BOOL)
goto error; goto error;
} else if (non_bool_opt_exists) { opt_exists = true;
/* TODO opts_need_arg = const_opts_need_arg;
* -- non bool option present, so parse the next arg opts_seen = const_opts_seen;
* or call completer on it if it is to be completed } else {
*/ /* In every other case, return NULL */
return NULL; goto error;
}
} }
VIR_FREE(const_tkdata); VIR_FREE(const_tkdata);
@ -2795,10 +2805,26 @@ vshReadlineParse(const char *text, int state)
VIR_FREE(const_tkdata); VIR_FREE(const_tkdata);
} }
if (!cmd_exists) if (!cmd_exists) {
res = vshReadlineCommandGenerator(sanitized_text, state); res = vshReadlineCommandGenerator(sanitized_text, state);
else if (opts_filled && !non_bool_opt_exists) } else if (opts_filled && !non_bool_opt_exists) {
res = vshReadlineOptionsGenerator(sanitized_text, state, cmd); res = vshReadlineOptionsGenerator(sanitized_text, state, cmd);
} else if (non_bool_opt_exists && data_complete && opt->completer) {
if (!completed_list)
completed_list = opt->completer(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;
virStringFreeList(completed_list);
completed_list_index = 0;
}
}
if (!res) { if (!res) {
VIR_FREE(sanitized_text); VIR_FREE(sanitized_text);