mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
vsh: Introduce complete command
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@redhat.com>
This commit is contained in:
parent
cc005fe5a8
commit
a0e1ada63c
@ -833,6 +833,7 @@ static const vshCmdDef virshCmds[] = {
|
|||||||
VSH_CMD_PWD,
|
VSH_CMD_PWD,
|
||||||
VSH_CMD_QUIT,
|
VSH_CMD_QUIT,
|
||||||
VSH_CMD_SELF_TEST,
|
VSH_CMD_SELF_TEST,
|
||||||
|
VSH_CMD_COMPLETE,
|
||||||
{.name = "connect",
|
{.name = "connect",
|
||||||
.handler = cmdConnect,
|
.handler = cmdConnect,
|
||||||
.opts = opts_connect,
|
.opts = opts_connect,
|
||||||
|
@ -1351,6 +1351,7 @@ static const vshCmdDef vshAdmCmds[] = {
|
|||||||
VSH_CMD_PWD,
|
VSH_CMD_PWD,
|
||||||
VSH_CMD_QUIT,
|
VSH_CMD_QUIT,
|
||||||
VSH_CMD_SELF_TEST,
|
VSH_CMD_SELF_TEST,
|
||||||
|
VSH_CMD_COMPLETE,
|
||||||
{.name = "uri",
|
{.name = "uri",
|
||||||
.handler = cmdURI,
|
.handler = cmdURI,
|
||||||
.opts = NULL,
|
.opts = NULL,
|
||||||
|
80
tools/vsh.c
80
tools/vsh.c
@ -3475,3 +3475,83 @@ cmdSelfTest(vshControl *ctl ATTRIBUTE_UNUSED,
|
|||||||
|
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
14
tools/vsh.h
14
tools/vsh.h
@ -382,6 +382,8 @@ extern const vshCmdInfo info_echo[];
|
|||||||
extern const vshCmdInfo info_pwd[];
|
extern const vshCmdInfo info_pwd[];
|
||||||
extern const vshCmdInfo info_quit[];
|
extern const vshCmdInfo info_quit[];
|
||||||
extern const vshCmdInfo info_selftest[];
|
extern const vshCmdInfo info_selftest[];
|
||||||
|
extern const vshCmdOptDef opts_complete[];
|
||||||
|
extern const vshCmdInfo info_complete[];
|
||||||
|
|
||||||
bool cmdHelp(vshControl *ctl, const vshCmd *cmd);
|
bool cmdHelp(vshControl *ctl, const vshCmd *cmd);
|
||||||
bool cmdCd(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 cmdPwd(vshControl *ctl, const vshCmd *cmd);
|
||||||
bool cmdQuit(vshControl *ctl, const vshCmd *cmd);
|
bool cmdQuit(vshControl *ctl, const vshCmd *cmd);
|
||||||
bool cmdSelfTest(vshControl *ctl, const vshCmd *cmd);
|
bool cmdSelfTest(vshControl *ctl, const vshCmd *cmd);
|
||||||
|
bool cmdComplete(vshControl *ctl, const vshCmd *cmd);
|
||||||
|
|
||||||
# define VSH_CMD_CD \
|
# define VSH_CMD_CD \
|
||||||
{ \
|
{ \
|
||||||
@ -454,6 +457,17 @@ bool cmdSelfTest(vshControl *ctl, const vshCmd *cmd);
|
|||||||
.alias = "self-test" \
|
.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 */
|
/* readline */
|
||||||
char * vshReadline(vshControl *ctl, const char *prompt);
|
char * vshReadline(vshControl *ctl, const char *prompt);
|
||||||
|
Loading…
Reference in New Issue
Block a user