diff --git a/kitty/launcher/cli-parser.h b/kitty/launcher/cli-parser.h index caa732e13..55b7491eb 100644 --- a/kitty/launcher/cli-parser.h +++ b/kitty/launcher/cli-parser.h @@ -122,10 +122,49 @@ alloc_for_cli(CLISpec *spec, size_t sz) { snprintf(buf, sz + 4, fmt, __VA_ARGS__); spec->errmsg = buf; \ } +static bool +add_to_listval(CLISpec *spec, CLIValue *v, const char *val) { + if (v->listval.count + 1 >= v->listval.capacity) { + size_t cap = MAX(64, v->listval.capacity * 2); + char **new = alloc_for_cli(spec, cap * sizeof(v->listval.items[0])); + if (!new) return false; + v->listval.capacity = cap; + if (v->listval.count) memcpy(new, v->listval.items, sizeof(new[0]) * v->listval.count); + v->listval.items = (void*)new; + } + v->listval.items[v->listval.count++] = val; + return true; +} + static const char* dest_for_alias(CLISpec *spec, const char *alias) { alias_hash_itr itr = vt_get(&spec->alias_map, alias); if (vt_is_end(itr)) { + const char *match_key = NULL, *match_val = NULL; + size_t total = 0, count = 0; + alias_hash matches; vt_init(&matches); + alias_map_for_loop(&spec->alias_map) { + if (strstr(itr.data->key, alias) == itr.data->key) { + total += strlen(itr.data->key) + 8; + if (!match_key) { match_key = itr.data->key; match_val = itr.data->val; } + if (vt_is_end(vt_insert(&matches, itr.data->val, itr.data->key))) OOM; + count++; + } + } + if (match_key) { + if (count == 1) return match_val; + total += 256 + total; + char *buf = alloc_for_cli(spec, total); + if (!buf) OOM; + int n = snprintf(buf, total, "The flag %s is ambiguous. Possible matches:", alias); + alias_map_for_loop(&matches) { + n += snprintf(buf + n, total - n, " %s,", itr.data->val); + } + buf[n-1] = '.'; + spec->errmsg = buf; + return NULL; + } + set_err("Unknown flag: %s use --help.", alias); return NULL; } @@ -145,15 +184,7 @@ add_list_value(CLISpec *spec, const char *dest, const char *val) { cli_hash_itr itr = vt_get_or_insert(&spec->value_map, dest, (CLIValue){.type=CLI_VALUE_LIST}); if (vt_is_end(itr)) OOM; CLIValue v = itr.data->val; - if (v.listval.count + 1 >= v.listval.capacity) { - size_t cap = MAX(64, v.listval.capacity * 2); - char **new = alloc_for_cli(spec, cap * sizeof(v.listval.items[0])); - if (!new) OOM; - v.listval.capacity = cap; - if (v.listval.count) memcpy(new, v.listval.items, sizeof(new[0]) * v.listval.count); - v.listval.items = (void*)new; - } - v.listval.items[v.listval.count++] = val; + if (!add_to_listval(spec, &v, val)) OOM; if (vt_is_end(vt_insert(&spec->value_map, dest, v))) OOM; } @@ -184,8 +215,9 @@ process_cli_arg(CLISpec* spec, const char *alias, const char *payload) { if (strcmp(payload, flag->defval.listval.items[c]) == 0) { val.strval = payload; break; } } if (!val.strval) { - size_t bufsz = 128 + strlen(alias) + strlen(payload); + size_t bufsz = 0; for (size_t c = 0; c < flag->defval.listval.count; c++) bufsz += strlen(flag->defval.listval.items[c]) + 8; + bufsz += 256 + strlen(alias) + strlen(payload) + bufsz; char *buf = alloc_for_cli(spec, bufsz); int n = snprintf(buf, bufsz, "%s is an invalid value for %s. Valid values are:", payload[0] ? payload : "", alias); diff --git a/kitty_tests/options.py b/kitty_tests/options.py index dd6ca52b8..73643d007 100644 --- a/kitty_tests/options.py +++ b/kitty_tests/options.py @@ -106,13 +106,14 @@ version t('-01=y', bool_reset=False, bool_set=True) t('-01=n', bool_reset=False, bool_set=False) t('--simple-string xx moo -1', leftover=['moo', '-1'], simple_string='xx') - t('--simple-string -0 -- -1', leftover=['-1'], simple_string='-0') + t('--si -0 -- -1', leftover=['-1'], simple_string='-0') t('--simple-string=-0 -- -1', leftover=['-1'], simple_string='-0') t('--simple-string=--help -- -1', leftover=['-1'], simple_string='--help') t('--simple-string --help -- -1', leftover=['-1'], simple_string='--help') t('-1l=a --list=b -c b --list c', bool_set=True, choice='b', list=list('abc')) t('-1s= -l "" --list= x', leftover=['x'], bool_set=True, simple_string='', list=['', '']) t('--choice moo', fails='a, b, c') + t('--bool', fails='mbiguous') t('-1c moo', fails='a, b, c') t('-10c=moo', fails='a, b, c') t('-1 -h', fails=True, help_called=True)