[libvirt] [PATCH 07/11] vsh: Introduce complete command

Martin Kletzander mkletzan at redhat.com
Wed Nov 8 15:16:16 UTC 2017


On Wed, Nov 08, 2017 at 04:00:35PM +0100, Michal Privoznik wrote:
>On 11/08/2017 03:23 PM, Martin Kletzander wrote:
>> 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 at 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.
>
>Yes we do need readline unfortunately. vshReadlineCompletion() calls
>rl_completion_matches() which filters strings returned by
>vshReadlineParse() so that list of strings presented to user corresponds
>to their input. We could reimplement the rl_* function ourselves if we
>really want to be readline independent. On the other hand - readline is
>everywhere, so why should we bother?
>

Sure, I agree, my question was if this is using it just for filtering strings,
looks like yes :D

>Michal
>
>--
>libvir-list mailing list
>libvir-list at redhat.com
>https://www.redhat.com/mailman/listinfo/libvir-list
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: Digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20171108/e6960a24/attachment-0001.sig>


More information about the libvir-list mailing list