On Tue, Nov 07, 2017 at 01:22:55PM +0100, Michal Privoznik wrote:
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 | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/vsh.h | 14 +++++++++++
4 files changed, 84 insertions(+)
diff --git a/tools/virsh.c b/tools/virsh.c
index 7d6dc2620..f830331f6 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -846,6 +846,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 5d7ef7988..c24ed95c0 100644
--- a/tools/virt-admin.c
+++ b/tools/virt-admin.c
@@ -1356,6 +1356,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 121669574..136acb0ab 100644
--- a/tools/vsh.c
+++ b/tools/vsh.c
@@ -3419,3 +3419,71 @@ 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 = NULL;
+ char **matches = NULL, *tmp = NULL, **iter;
+
+ 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,
true)))
+ goto cleanup;
+
+ autoCompleteOpaque = ctl;
+
+ rl_basic_word_break_characters = " \t\n\\`@$><=;|&{(";
+ if (VIR_STRDUP(rl_line_buffer, arg) < 0)
+ goto cleanup;
+
+ while ((tmp = strpbrk(arg, rl_basic_word_break_characters)))
+ arg = tmp + 1;
+
+ if (!(matches = vshReadlineCompletion(arg, 0, 0)))
+ goto cleanup;
+
+ for (iter = matches; *iter; iter++)
+ printf("%s\n", *iter);
+
+ ret = true;
+ cleanup:
+ for (iter = matches; iter && *iter; iter++)
+ VIR_FREE(*iter);
+ VIR_FREE(matches);
+#endif /* WITH_READLINE */
Do we really need readline for it? Did I miss something or are we
really just using it here just so we don't have to split the
vshReadlineParse() in some way? Don't get me wrong, I'm OK with that,
the split would be too complicated and who doesn't use readline, right?
It just feels weird.