1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
/*
* virsh-completer.c: virsh completer callbacks
*
* Copyright (C) 2017 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "virsh-completer.h"
/**
* A completer callback is a function that accepts three arguments:
*
* @ctl: virsh control structure
* @cmd: parsed input
* @flags: optional flags to alter completer's behaviour
*
* The @ctl contains connection to the daemon (should the
* completer need it). Any completer that requires a connection
* must check whether connection is still alive.
*
* The @cmd contains parsed user input which might be missing
* some arguments (if user is still typing the command), but may
* already contain important data. For instance if the completer
* needs domain XML it may inspect @cmd to find --domain. Using
* existing wrappers is advised. If @cmd does not contain all
* necessary bits, completer might return sensible defaults (i.e.
* generic values not tailored to specific use case) or return
* NULL (i.e. no strings are offered to the user for completion).
*
* The @flags contains a .completer_flags value defined for each
* use or 0 if no .completer_flags were specified. If a completer
* is generic enough @flags can be used to alter its behaviour.
* For instance, a completer to fetch names of domains can use
* @flags to return names of only domains in a particular state
* that the command accepts.
*
* Under no circumstances should a completer output anything.
* Neither to stdout nor to stderr. This would harm the user
* experience.
*/
/**
* virshEnumComplete:
* @last: The number of element in enum (pass VIR_XXX_LAST)
* @intToStr: integer to string conversion (pass virXXXTypeToString)
*
* Convenient function to generate completions across all values
* of given enum. The enum, or values we want to generate, must
* start at 0 and be continuous until @last.
*
* Returns: string list of completions.
*/
char **
virshEnumComplete(unsigned int last,
const char *(*intToStr)(int))
{
char **ret = NULL;
size_t i;
ret = g_new0(char *, last + 1);
for (i = 0; i < last; i++)
ret[i] = g_strdup(intToStr(i));
return ret;
}
/**
* virshCommaStringListComplete:
* @input: user input so far
* @options: ALL options available for argument
*
* Some arguments to our commands accept the following form:
*
* virsh command --arg str1,str2,str3
*
* This does not play nicely with our completer functions, because
* they have to return strings prepended with user's input. For
* instance:
*
* str1,str2,str3,strA
* str1,str2,str3,strB
* str1,str2,str3,strC
*
* This helper function takes care of that. In this specific case
* it would be called as follows:
*
* virshCommaStringListComplete("str1,str2,str3",
* {"strA", "strB", "strC", NULL});
*
* Returns: string list of completions on success,
* NULL otherwise.
*/
char **
virshCommaStringListComplete(const char *input,
const char **options)
{
const size_t optionsLen = g_strv_length((char **) options);
g_autofree char *inputCopy = NULL;
g_auto(GStrv) inputList = NULL;
g_auto(GStrv) ret = NULL;
size_t nret = 0;
size_t i;
if (STREQ_NULLABLE(input, " "))
input = NULL;
if (input) {
char *comma = NULL;
inputCopy = g_strdup(input);
if ((comma = strrchr(inputCopy, ',')))
*comma = '\0';
else
g_clear_pointer(&inputCopy, g_free);
}
if (inputCopy && !(inputList = g_strsplit(inputCopy, ",", 0)))
return NULL;
ret = g_new0(char *, optionsLen + 1);
for (i = 0; i < optionsLen; i++) {
if (inputList &&
g_strv_contains((const char **)inputList, options[i]))
continue;
if (inputCopy)
ret[nret] = g_strdup_printf("%s,%s", inputCopy, options[i]);
else
ret[nret] = g_strdup(options[i]);
nret++;
}
return g_steal_pointer(&ret);
}
/**
* virshCompletePathLocalExisting:
*
* Complete a path to a existing file used as input. The file is used as input
* for virsh so only local files are considered.
*
* Note: For now this is a no-op. Readline does the correct thing.
*/
char **
virshCompletePathLocalExisting(vshControl *ctl G_GNUC_UNUSED,
const vshCmd *cmd G_GNUC_UNUSED,
unsigned int completerflags G_GNUC_UNUSED)
{
return NULL;
}
/**
* virshCompleteEmpty:
*
* Complete nothing. For cases where an user input is required and we can't
* suggest anything.
*
* TODO: This is currently just an annotation, readline still completes local
* file list.
*/
char **
virshCompleteEmpty(vshControl *ctl G_GNUC_UNUSED,
const vshCmd *cmd G_GNUC_UNUSED,
unsigned int completerflags G_GNUC_UNUSED)
{
return NULL;
}
|