From: Jan Kiszka <jan.kis...@siemens.com> This enables command line completion inside option strings. A list of expected key names and their completion type can be appended to the 'O' inside parentheses ('O(key:type,...)'). The first use case is block device completion for the 'drive' option of 'device_add'.
Signed-off-by: Jan Kiszka <jan.kis...@siemens.com> --- monitor.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++--------- qemu-monitor.hx | 2 +- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/monitor.c b/monitor.c index c1006b4..3e0d862 100644 --- a/monitor.c +++ b/monitor.c @@ -68,6 +68,9 @@ * 'O' option string of the form NAME=VALUE,... * parsed according to QemuOptsList given by its name * Example: 'device:O' uses qemu_device_opts. + * Command completion for specific keys can be requested via + * appending '(NAME:TYPE,...)' with 'F', 'B' as type. + * Example: 'device:O(bus:Q)' to expand 'bus=...' as qtree path. * Restriction: only lists with empty desc are supported * TODO lift the restriction * 'i' 32 bit integer @@ -3353,6 +3356,11 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, QemuOptsList *opts_list; QemuOpts *opts; + if (*typestr == '(') { + while (*typestr++ != ')') { + assert(*typestr != '\0'); + } + } opts_list = qemu_find_opts(key); if (!opts_list || opts_list->desc->name) { goto bad_type; @@ -3857,12 +3865,30 @@ static const char *next_arg_type(const char *typestr) return (p != NULL ? ++p : typestr); } +static bool process_completion_type(char type, const char *str) +{ + switch(type) { + case 'F': + /* file completion */ + readline_set_completion_index(cur_mon->rs, strlen(str)); + file_completion(str); + return true; + case 'B': + /* block device name completion */ + readline_set_completion_index(cur_mon->rs, strlen(str)); + bdrv_iterate(block_completion_it, (void *)str); + return true; + default: + return false; + } +} + static void monitor_find_completion(const char *cmdline) { const char *cmdname; char *args[MAX_ARGS]; int nb_args, i, len; - const char *ptype, *str; + const char *ptype, *str, *opt, *sep; const mon_cmd_t *cmd; const KeyDef *key; @@ -3915,16 +3941,31 @@ static void monitor_find_completion(const char *cmdline) if (*ptype == '-' && ptype[1] != '\0') { ptype = next_arg_type(ptype); } + if (process_completion_type(*ptype, str)) { + goto cleanup; + } switch(*ptype) { - case 'F': - /* file completion */ - readline_set_completion_index(cur_mon->rs, strlen(str)); - file_completion(str); - break; - case 'B': - /* block device name completion */ - readline_set_completion_index(cur_mon->rs, strlen(str)); - bdrv_iterate(block_completion_it, (void *)str); + case 'O': + sep = strrchr(str, ','); + opt = sep ? sep + 1 : str; + sep = strchr(opt, '='); + if (!sep) { + break; + } + len = sep - opt; + str = sep + 1; + ptype += 2; + while (*ptype != ')') { + if (strlen(ptype) > len+1 && ptype[len] == ':' && + strncmp(ptype, opt, len) == 0) { + process_completion_type(ptype[len+1], str); + } + while (*ptype++ != ',') { + if (*ptype == ')') { + break; + } + } + } break; case 's': /* XXX: more generic ? */ @@ -3934,7 +3975,7 @@ static void monitor_find_completion(const char *cmdline) cmd_completion(str, cmd->name); } } else if (!strcmp(cmd->name, "sendkey")) { - char *sep = strrchr(str, '-'); + sep = strrchr(str, '-'); if (sep) str = sep + 1; readline_set_completion_index(cur_mon->rs, strlen(str)); @@ -4114,6 +4155,11 @@ static int monitor_check_qmp_args(const mon_cmd_t *cmd, QDict *args) cmd_args.flag = *p++; cmd_args.optional = 1; } else if (cmd_args.type == 'O') { + if (*p == '(') { + while (*p++ != ')') { + assert(*p != '\0'); + } + } opts_list = qemu_find_opts(qstring_get_str(cmd_args.name)); assert(opts_list); } else if (*p == '?') { diff --git a/qemu-monitor.hx b/qemu-monitor.hx index 0ea0555..b5d0f6d 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -660,7 +660,7 @@ ETEXI { .name = "device_add", - .args_type = "device:O", + .args_type = "device:O(drive:B)", .params = "driver[,prop=value][,...]", .help = "add device, like -device on the command line", .user_print = monitor_user_noop, -- 1.6.0.2