This command is going to be called from bash completion script in
the following form:
virsh complete -- start --domain
Its only purpose is to return list of possible strings for
completion. Note that this is a 'hidden', unlisted command and
therefore there's no documentation to it.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
tools/virsh.c | 1 +
tools/virt-admin.c | 1 +
tools/vsh.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/vsh.h | 14 ++++++++++
4 files changed, 96 insertions(+)
diff --git a/tools/virsh.c b/tools/virsh.c
index 933d6b4c9..5f8352e86 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -833,6 +833,7 @@ static const vshCmdDef virshCmds[] = {
VSH_CMD_PWD,
VSH_CMD_QUIT,
VSH_CMD_SELF_TEST,
+ VSH_CMD_COMPLETE,
{.name = "connect",
.handler = cmdConnect,
.opts = opts_connect,
diff --git a/tools/virt-admin.c b/tools/virt-admin.c
index b8b33af19..ef5bada63 100644
--- a/tools/virt-admin.c
+++ b/tools/virt-admin.c
@@ -1351,6 +1351,7 @@ static const vshCmdDef vshAdmCmds[] = {
VSH_CMD_PWD,
VSH_CMD_QUIT,
VSH_CMD_SELF_TEST,
+ VSH_CMD_COMPLETE,
{.name = "uri",
.handler = cmdURI,
.opts = NULL,
diff --git a/tools/vsh.c b/tools/vsh.c
index f061783e0..9f4805b3d 100644
--- a/tools/vsh.c
+++ b/tools/vsh.c
@@ -3472,3 +3472,83 @@ cmdSelfTest(vshControl *ctl ATTRIBUTE_UNUSED,
return true;
}
+
+/* ----------------------
+ * Autocompletion command
+ * ---------------------- */
+
+const vshCmdOptDef opts_complete[] = {
+ {.name = "string",
+ .type = VSH_OT_ARGV,
+ .flags = VSH_OFLAG_EMPTY_OK,
+ .help = N_("partial string to autocomplete")
+ },
+ {.name = NULL}
+};
+
+const vshCmdInfo info_complete[] = {
+ {.name = "help",
+ .data = N_("internal command for autocompletion")
+ },
+ {.name = "desc",
+ .data = N_("internal use only")
+ },
+ {.name = NULL}
+};
+
+bool
+cmdComplete(vshControl *ctl, const vshCmd *cmd)
+{
+ bool ret = false;
+#ifdef WITH_READLINE
+ const vshClientHooks *hooks = ctl->hooks;
+ int stdin_fileno = STDIN_FILENO;
+ const char *arg = "";
+ const vshCmdOpt *opt = NULL;
+ char **matches = NULL, **iter;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (vshCommandOptStringQuiet(ctl, cmd, "string", &arg) <= 0)
+ goto cleanup;
+
+ /* This command is flagged VSH_CMD_FLAG_NOCONNECT because we
+ * need to prevent auth hooks reading any input. Therefore, we
+ * have to close stdin and then connect ourselves. */
+ VIR_FORCE_CLOSE(stdin_fileno);
+
+ if (!(hooks && hooks->connHandler && hooks->connHandler(ctl)))
+ goto cleanup;
+
+ while ((opt = vshCommandOptArgv(ctl, cmd, opt))) {
+ if (virBufferUse(&buf) != 0)
+ virBufferAddChar(&buf, ' ');
+ virBufferAddStr(&buf, opt->data);
+ arg = opt->data;
+ }
+
+ if (virBufferCheckError(&buf) < 0)
+ goto cleanup;
+
+ vshReadlineInit(ctl);
+
+ if (!(rl_line_buffer = virBufferContentAndReset(&buf)) &&
+ VIR_STRDUP(rl_line_buffer, "") < 0)
+ goto cleanup;
+
+ /* rl_point is current cursor position in rl_line_buffer.
+ * In our case it's at the end of the whole line. */
+ rl_point = strlen(rl_line_buffer);
+
+ if (!(matches = vshReadlineCompletion(arg, 0, 0)))
+ goto cleanup;
+
+ for (iter = matches; *iter; iter++)
+ printf("%s\n", *iter);
+
+ ret = true;
+ cleanup:
+ virBufferFreeAndReset(&buf);
+ virStringListFree(matches);
+#endif /* WITH_READLINE */
+ return ret;
+}
diff --git a/tools/vsh.h b/tools/vsh.h
index ae40fb4e8..6894700d9 100644
--- a/tools/vsh.h
+++ b/tools/vsh.h
@@ -382,6 +382,8 @@ extern const vshCmdInfo info_echo[];
extern const vshCmdInfo info_pwd[];
extern const vshCmdInfo info_quit[];
extern const vshCmdInfo info_selftest[];
+extern const vshCmdOptDef opts_complete[];
+extern const vshCmdInfo info_complete[];
bool cmdHelp(vshControl *ctl, const vshCmd *cmd);
bool cmdCd(vshControl *ctl, const vshCmd *cmd);
@@ -389,6 +391,7 @@ bool cmdEcho(vshControl *ctl, const vshCmd *cmd);
bool cmdPwd(vshControl *ctl, const vshCmd *cmd);
bool cmdQuit(vshControl *ctl, const vshCmd *cmd);
bool cmdSelfTest(vshControl *ctl, const vshCmd *cmd);
+bool cmdComplete(vshControl *ctl, const vshCmd *cmd);
# define VSH_CMD_CD \
{ \
@@ -454,6 +457,17 @@ bool cmdSelfTest(vshControl *ctl, const vshCmd *cmd);
.alias = "self-test" \
}
+# define VSH_CMD_COMPLETE \
+ { \
+ .name = "complete", \
+ .handler = cmdComplete, \
+ .opts = opts_complete, \
+ .info = info_complete, \
+ .flags = VSH_CMD_FLAG_NOCONNECT | VSH_CMD_FLAG_ALIAS, \
+ .alias = "complete" \
+ }
+
+
/* readline */
char * vshReadline(vshControl *ctl, const char *prompt);
--
2.13.6