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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list