[libvirt] [PATCH v2 08/12] vsh: Introduce complete command

Michal Privoznik mprivozn at redhat.com
Mon Nov 13 16:06:28 UTC 2017


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 at redhat.com>
---
 tools/virsh.c      |  1 +
 tools/virt-admin.c |  1 +
 tools/vsh.c        | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/vsh.h        | 14 ++++++++++
 4 files changed, 94 insertions(+)

diff --git a/tools/virsh.c b/tools/virsh.c
index d0c135016..0d44eb301 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -831,6 +831,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 9cf85b180..2f0914c59 100644
--- a/tools/vsh.c
+++ b/tools/vsh.c
@@ -3446,3 +3446,81 @@ 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, *tmp = 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;
+
+    if (!(matches = vshReadlineCompletion(arg, 0, 0)))
+        goto cleanup;
+
+    for (iter = matches; *iter; iter++)
+        printf("%s\n", *iter);
+
+    ret = true;
+ cleanup:
+    virBufferFreeAndReset(&buf);
+    for (iter = matches; iter && *iter; iter++)
+        VIR_FREE(*iter);
+    VIR_FREE(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




More information about the libvir-list mailing list