On a Tuesday in 2021, Michal Privoznik wrote:
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@xxxxxxxxxx> --- tools/vsh.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/tools/vsh.c b/tools/vsh.c index abbd323e24..27c201389d 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -2751,10 +2751,26 @@ vshReadlineParse(const char *text, int state) partial, opt->completer_flags); + /* Escape completions, if needed (i.e. argument + * we completing wasn't started with a quote
we are completing Jano
+ * 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)) {
Attachment:
signature.asc
Description: PGP signature