On 08.08.2013 16:38, Tomas Meszaros wrote:
New completion generators responsible for advances command
and command options completions.
vshReadlineCommandCompletionGenerator - generator for advanced
command completions. This function will call some vshCmdCompleter
function (e.g. vshDomainCompleter), which will return relevant
data used for autocompletion (e.g. domain names).
vshReadlineOptionsCompletionGenerator - almost the same as the
vshReadlineCommandCompletionGenerator, but this one completes
cmd options.
vshReadlineCompletion() has become much more complex because we
now have more generator functions and therefore more states to
choose from.
---
tools/virsh.c | 398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 376 insertions(+), 22 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 13d66c7..aec26b4 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2610,6 +2610,25 @@ cleanup:
* -----------------
*/
+static const vshCmdDef *
+vshDetermineCommandName(void)
+{
+ const vshCmdDef *cmd = NULL;
+ char *p;
+ char *cmdname;
+
+ if (!(p = strchr(rl_line_buffer, ' ')))
+ return NULL;
+
+ cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1);
so this is effectively vshMalloc().
+ memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
+
+ cmd = vshCmddefSearch(cmdname);
+ VIR_FREE(cmdname);
+
+ return cmd;
+}
+
/*
* Generator function for command completion. STATE lets us
* know whether to start from scratch; without any state
@@ -2657,25 +2676,14 @@ vshReadlineCommandGenerator(const char *text, int state)
static char *
vshReadlineOptionsGenerator(const char *text, int state)
{
- static int list_index, len;
static const vshCmdDef *cmd = NULL;
+ static int list_index, len;
const char *name;
if (!state) {
- /* determine command name */
- char *p;
- char *cmdname;
-
- if (!(p = strchr(rl_line_buffer, ' ')))
- return NULL;
-
- cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1);
- memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
-
- cmd = vshCmddefSearch(cmdname);
+ cmd = vshDetermineCommandName();
list_index = 0;
len = strlen(text);
- VIR_FREE(cmdname);
}
if (!cmd)
@@ -2707,22 +2715,368 @@ vshReadlineOptionsGenerator(const char *text, int state)
return NULL;
}
+/*
+ * Generator function for command completion, but unlike
+ * the vshRaadlineCommandGenerator which completes command name, this function
+ * provides more advanced completion for commands by calling specific command
+ * completers (e.g. vshDomainCompleter).
+ */
+static char *
+vshReadlineCommandCompletionGenerator(const char *text, int state)
+{
+ static const vshCmdDef *cmd = NULL;
+ static int list_index, len;
+ char **completed_names = NULL;
+ char *name;
+
+ if (!state) {
+ cmd = vshDetermineCommandName();
+ list_index = 0;
+ len = strlen(text);
+ }
+
+ if (!cmd)
+ return NULL;
+
+ if (!cmd->completer)
+ return NULL;
+
+ completed_names = cmd->completer(cmd->completer_flags);
+
+ if (!completed_names)
+ return NULL;
+
+ while ((name = completed_names[list_index])) {
+ char *res;
+ list_index++;
+
+ if (STRNEQLEN(name, text, len))
+ /* Skip irrelevant names */
+ continue;
+
+ res = vshMalloc(NULL, strlen(name) + 1);
+ snprintf(res, strlen(name) + 1, "%s", name);
Consider using vshStrdup() instead of these two lines.
+ VIR_FREE(name);
+ return res;
+ }
+ VIR_FREE(completed_names);
+
+ return NULL;
+}
+
+/*
+ * Generator function for command option completion. Provides advances
+ * completion for command options.
+ */
+static char *
+vshReadlineOptionsCompletionGenerator(const char *text ATTRIBUTE_UNUSED,
+ int state ATTRIBUTE_UNUSED)
+{
+ static const vshCmdDef *cmd = NULL;
+ static const vshCmdOptDef *opt = NULL;
+ static int list_index, len;
+ unsigned long int opt_index = 0;
+ size_t i;
+ char **completed_names = NULL;
+ char *name;
+ char *ptr = NULL;
+
+ if (!state) {
+ cmd = vshDetermineCommandName();
+ list_index = 0;
+ len = strlen(text);
+ }
+
+ if (!cmd)
+ return NULL;
+
+ if (!cmd->opts)
+ return NULL;
+
+ for (i = 0; cmd->opts[i].name; i++) {
+ if ((ptr = strstr(rl_line_buffer, cmd->opts[i].name))) {
+ if (opt_index < (ptr - rl_line_buffer)) {
These to if's can be joined into one.
+ opt_index = ptr - rl_line_buffer;
+ opt = &cmd->opts[i];
+ }
+ }
+ }
+
+ if (!opt)
+ return NULL;
+
+ if (!opt->completer)
+ return NULL;
+
+ completed_names = opt->completer(opt->completer_flags);
+
+ if (!completed_names)
+ return NULL;
+
+ while ((name = completed_names[list_index])) {
+ char *res;
+ list_index++;
+
+ if (STRNEQLEN(name, text, len))
+ /* Skip irrelevant names */
+ continue;
+
+ res = vshMalloc(NULL, strlen(name) + 1);
+ snprintf(res, strlen(name) + 1, "%s", name);
Again, nice candidate to be replaced by vshStrdup().
+ VIR_FREE(name);
+ return res;
+ }
+ VIR_FREE(completed_names);
+
+ return NULL;
+}
+
Michal