ctl->imode = false;
if (argc - optind == 1) {
vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
- return vshCommandStringParse(ctl, argv[optind], NULL);
+ return vshCommandStringParse(ctl, argv[optind], NULL, 0);
} else {
return vshCommandArgvParse(ctl, argc - optind, argv + optind);
}
if (*ctl->cmdstr) {
vshReadlineHistoryAdd(ctl->cmdstr);
- if (vshCommandStringParse(ctl, ctl->cmdstr, NULL))
+ if (vshCommandStringParse(ctl, ctl->cmdstr, NULL, 0))
vshCommandRun(ctl, ctl->cmd);
}
VIR_FREE(ctl->cmdstr);
ctl->imode = false;
if (argc - optind == 1) {
vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
- return vshCommandStringParse(ctl, argv[optind], NULL);
+ return vshCommandStringParse(ctl, argv[optind], NULL, 0);
} else {
return vshCommandArgvParse(ctl, argc - optind, argv + optind);
}
if (*ctl->cmdstr) {
vshReadlineHistoryAdd(ctl->cmdstr);
- if (vshCommandStringParse(ctl, ctl->cmdstr, NULL))
+ if (vshCommandStringParse(ctl, ctl->cmdstr, NULL, 0))
vshCommandRun(ctl, ctl->cmd);
}
VIR_FREE(ctl->cmdstr);
char **, bool);
/* vshCommandStringGetArg() */
char *pos;
+ const char *originalLine;
+ size_t point;
/* vshCommandArgvGetArg() */
char **arg_pos;
char **arg_end;
arg->data = tkdata;
tkdata = NULL;
arg->next = NULL;
+
+ if (parser->pos - parser->originalLine == parser->point - 1)
+ arg->completeThis = true;
+
if (!first)
first = arg;
if (last)
arg->next = NULL;
tkdata = NULL;
+ if (parser->pos - parser->originalLine == parser->point)
+ arg->completeThis = true;
+
if (!first)
first = arg;
if (last)
bool
vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
{
- vshCommandParser parser;
+ vshCommandParser parser = { 0 };
if (nargs <= 0)
return false;
return VSH_TK_ARG;
}
+
+/**
+ * vshCommandStringParse:
+ * @ctl virsh control structure
+ * @cmdstr: string to parse
+ * @partial: store partially parsed command here
+ * @point: position of cursor (rl_point)
+ *
+ * Parse given string @cmdstr as a command and store it under
+ * @ctl->cmd. For readline completion, if @partial is not NULL on
+ * the input then errors in parsing are ignored (because user is
+ * still in progress of writing the command string) and partially
+ * parsed command is stored at *@partial (caller has to free it
+ * afterwards). Among with @partial, caller must set @point which
+ * is the position of cursor in @cmdstr (offset, numbered from 1).
+ * Parser will then set @completeThis attribute to true for the
+ * vshCmdOpt that appeared under the cursor.
+ */
bool
-vshCommandStringParse(vshControl *ctl, char *cmdstr, vshCmd **partial)
+vshCommandStringParse(vshControl *ctl,
+ char *cmdstr,
+ vshCmd **partial,
+ size_t point)
{
- vshCommandParser parser;
+ vshCommandParser parser = { 0 };
if (cmdstr == NULL || *cmdstr == '\0')
return false;
parser.pos = cmdstr;
+ parser.originalLine = cmdstr;
+ parser.point = point;
parser.getNextArg = vshCommandStringGetArg;
return vshCommandParse(ctl, &parser, partial);
}
static const vshCmdOptDef *
-vshReadlineCommandFindOpt(const vshCmd *partial,
- const char *text)
+vshReadlineCommandFindOpt(const vshCmd *partial)
{
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) {
+ while (tmp) {
const vshCmdOpt *opt = tmp->opts;
while (opt) {
- if (STREQ_NULLABLE(opt->data, text) ||
- STREQ_NULLABLE(opt->data, " "))
+ if (opt->completeThis)
return opt->def;
opt = opt->next;
}
+ tmp = tmp->next;
}
return NULL;
*(line + rl_point) = '\0';
- vshCommandStringParse(NULL, line, &partial);
+ vshCommandStringParse(NULL, line, &partial, rl_point);
if (partial) {
cmd = partial->def;
cmd = NULL;
}
- opt = vshReadlineCommandFindOpt(partial, text);
+ opt = vshReadlineCommandFindOpt(partial);
if (!cmd) {
list = vshReadlineCommandGenerator(text);
struct _vshCmdOpt {
const vshCmdOptDef *def; /* non-NULL pointer to option definition */
char *data; /* allocated data, or NULL for bool option */
+ bool completeThis; /* true if this is the option user's wishing to
+ autocomplete */
vshCmdOpt *next;
};
unsigned long *bandwidth);
bool vshCommandOptBool(const vshCmd *cmd, const char *name);
bool vshCommandRun(vshControl *ctl, const vshCmd *cmd);
-bool vshCommandStringParse(vshControl *ctl, char *cmdstr, vshCmd **partial);
+bool vshCommandStringParse(vshControl *ctl, char *cmdstr,
+ vshCmd **partial, size_t point);
const vshCmdOpt *vshCommandOptArgv(vshControl *ctl, const vshCmd *cmd,
const vshCmdOpt *opt);