This patch introduces a way for completers to retrieve the current vshControl object by using the vshGetCompleterCtl() macro. When readline is enabled, the main method stores the vshControl pointer in a variable that is file-global to virsh.c. Then, that pointer can be retrieved by the _vshGetCompleterCtl() function, which is mapped to by the macro. If readline is not enabled, the macro simply maps to NULL. --- tests/virshtest.c | 13 +++++++++++++ tools/virsh.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- tools/virsh.h | 8 ++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/tests/virshtest.c b/tests/virshtest.c index 0c698fa..d068e5e 100644 --- a/tests/virshtest.c +++ b/tests/virshtest.c @@ -333,6 +333,15 @@ static int testCompletionInArgvMode(const void *data ATTRIBUTE_UNUSED) return testCompareOutputLit(exp, NULL, argv); } +static int testCompletionRequiringCtl(const void *data ATTRIBUTE_UNUSED) +{ + const char *const argv[] = { VIRSH_CUSTOM, "complete", + "fake-command --string3 ", NULL }; + const char *exp = ("test:///home/directxman12/dev/libvirt" + "/tests/../examples/xml/test/testnode.xml\n\n"); + return testCompareOutputLit(exp, NULL, argv); +} + # endif /* WITH_READLINE */ @@ -575,6 +584,10 @@ mymain(void) testCompletionInArgvMode, NULL) != 0) ret = -1; + if (virtTestRun("virsh completion (completer requiring control object)", + testCompletionRequiringCtl, NULL) != 0) + ret = -1; + # endif /* WITH_READLINE */ /* It's a bit awkward listing result before argument, but that's a diff --git a/tools/virsh.c b/tools/virsh.c index 808a125..71076dc 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -96,6 +96,16 @@ static char *progname; static const vshCmdGrp cmdGroups[]; +#if WITH_READLINE +static vshControl *completer_ctl; + +vshControl * +_vshGetCompleterCtl(void) +{ + return completer_ctl; +} +#endif + /* Bypass header poison */ #undef strdup @@ -1033,6 +1043,21 @@ VSH_STRING_COMPLETER(NULL, FakeCommandStr2, "value a", "value b"); VSH_STRING_COMPLETER(NULL, FakeCommandData1, "ab", "cd"); VSH_STRING_COMPLETER(NULL, FakeCommandData2, "i e f", "i g h"); +static char ** +vshCompleteFakeCommandStr3(unsigned int flags) +{ + virCheckFlags(0, NULL); + + vshControl *ctl = vshGetCompleterCtl(); + char *uri = virConnectGetURI(ctl->conn); + char **res = vshCalloc(NULL, 2, sizeof(char*)); + + res[0] = uri; + res[1] = NULL; + + return res; +} + static const vshCmdOptDef opts_fake_command[] = { {.name = "abool", .type = VSH_OT_BOOL, @@ -1060,6 +1085,7 @@ static const vshCmdOptDef opts_fake_command[] = { }, {.name = "string3", .type = VSH_OT_STRING, + .completer = vshCompleteFakeCommandStr3, .help = N_("another string") }, {.name = "file", @@ -3112,7 +3138,7 @@ vshReadlineCommandGenerator(const char *text, int state) } static char * -vshDelegateToCustomCompleter(const vshCmdOptDef *opt, +vshDelegateToCustomCompleter(const vshCmdOptDef *opt, bool reconnect, const char *text, int state) { static int list_index; @@ -3125,6 +3151,10 @@ vshDelegateToCustomCompleter(const vshCmdOptDef *opt, return NULL; if (opt->completer) { + vshControl *ctl = completer_ctl; + if ((!ctl->conn || disconnected) && reconnect) + vshReconnect(ctl); + list_index = 0; completions = opt->completer(opt->completer_flags); } @@ -3276,10 +3306,13 @@ vshReadlineOptionsGenerator(const char *text, int state) if (waiting_for_flag_arg) { char* res; + bool may_connect = !(cmd->flags & VSH_CMD_FLAG_NOCONNECT); if (continue_from_error) - res = vshDelegateToCustomCompleter(curr_opt, last_tok, substate); + res = vshDelegateToCustomCompleter(curr_opt, may_connect, + last_tok, substate); else - res = vshDelegateToCustomCompleter(curr_opt, text, substate); + res = vshDelegateToCustomCompleter(curr_opt, may_connect, + text, substate); substate++; /* if we're in a flag's argument, we don't @@ -3343,10 +3376,14 @@ vshReadlineOptionsGenerator(const char *text, int state) /* we don't need to ignore args without custom completers, * since vshDelegateToCustomCompleter will do this for us */ + bool may_connect = !(cmd->flags & VSH_CMD_FLAG_NOCONNECT); if (continue_from_error) - res = vshDelegateToCustomCompleter(opt, last_tok, substate); + res = vshDelegateToCustomCompleter(opt, may_connect, + last_tok, substate); else - res = vshDelegateToCustomCompleter(opt, text, substate); + res = vshDelegateToCustomCompleter(opt, may_connect, + text, substate); + substate++; if (res) { if (strchr(res, ' ')) { @@ -4134,9 +4171,14 @@ int main(int argc, char **argv) { vshControl _ctl, *ctl = &_ctl; + const char *defaultConn; bool ret = true; +#if WITH_READLINE + completer_ctl = ctl; +#endif + memset(ctl, 0, sizeof(vshControl)); ctl->imode = true; /* default is interactive mode */ ctl->log_fd = -1; /* Initialize log file descriptor */ diff --git a/tools/virsh.h b/tools/virsh.h index 227e4e8..38f3663 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -180,6 +180,14 @@ struct _vshCmdOptDef { * readline file completer */ # define VSH_COMPLETE_AS_FILE (1 << 8) +vshControl * _vshGetCompleterCtl(void); + +# if WITH_READLINE +# define vshGetCompleterCtl() _vshGetCompleterCtl() +# else +# define vshGetCompleterCtl() NULL +# endif + /* * vshCmdOpt - command options * -- 1.8.3.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list