vshReadlineParse: Escape list of candidates earlier

The way our completer callbacks work is that they return all
possible candidates and then vshCompleterFilter() is called to
prune the list of all candidates removing those which don't match
user's input. This allows us to have simpler completer callbacks
as their only job is to fetch all possible candidates.

Anyway, if the completion candidate we're returning contains a
space, it has to be escaped (shell like escaping), unless there
is already a quote character (single quote or double quote).

But ordering is critical. Completer callback returns string
without any escaping, but the filter function sees the user input
escaped. For instance, if user's input is "domain with
space<TAB>" then the filtering function gets "domain\ with\
space" as user's input but completer returns "domain with space".
Since these two strings don't match the filtering function
removes this candidate from the list. What we need to do is to
escape strings before calling the filtering function. This way,
the filtering function will see two same strings.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Michal Privoznik 2021-01-26 09:23:24 +01:00
parent c31e80c653
commit f61a4e91ef

View File

@ -2751,10 +2751,26 @@ vshReadlineParse(const char *text, int state)
partial,
opt->completer_flags);
/* Escape completions, if needed (i.e. argument
* we are completing wasn't started with a quote
* character). This also enables filtering done
* below to work properly. */
if (completer_list &&
!rl_completion_quote_character) {
size_t i;
for (i = 0; completer_list[i]; i++) {
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
virBufferEscape(&buf, '\\', " ", "%s", completer_list[i]);
VIR_FREE(completer_list[i]);
completer_list[i] = virBufferContentAndReset(&buf);
}
}
/* For string list returned by completer we have to do
* filtering based on @text because completer returns all
* possible strings. */
if (completer_list &&
(vshCompleterFilter(&completer_list, text) < 0 ||
virStringListMerge(&list, &completer_list) < 0)) {
@ -2770,14 +2786,6 @@ vshReadlineParse(const char *text, int state)
list_index++;
}
if (ret &&
!rl_completion_quote_character) {
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
virBufferEscape(&buf, '\\', " ", "%s", ret);
VIR_FREE(ret);
ret = virBufferContentAndReset(&buf);
}
cleanup:
if (!ret) {
g_strfreev(list);