mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-22 08:18:08 +02:00
Allow partial option matches in C CLI parser as well
Matches behavior of Go parser and is nice to have
This commit is contained in:
@@ -122,10 +122,49 @@ alloc_for_cli(CLISpec *spec, size_t sz) {
|
|||||||
snprintf(buf, sz + 4, fmt, __VA_ARGS__); spec->errmsg = buf; \
|
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*
|
static const char*
|
||||||
dest_for_alias(CLISpec *spec, const char *alias) {
|
dest_for_alias(CLISpec *spec, const char *alias) {
|
||||||
alias_hash_itr itr = vt_get(&spec->alias_map, alias);
|
alias_hash_itr itr = vt_get(&spec->alias_map, alias);
|
||||||
if (vt_is_end(itr)) {
|
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);
|
set_err("Unknown flag: %s use --help.", alias);
|
||||||
return NULL;
|
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});
|
cli_hash_itr itr = vt_get_or_insert(&spec->value_map, dest, (CLIValue){.type=CLI_VALUE_LIST});
|
||||||
if (vt_is_end(itr)) OOM;
|
if (vt_is_end(itr)) OOM;
|
||||||
CLIValue v = itr.data->val;
|
CLIValue v = itr.data->val;
|
||||||
if (v.listval.count + 1 >= v.listval.capacity) {
|
if (!add_to_listval(spec, &v, val)) OOM;
|
||||||
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 (vt_is_end(vt_insert(&spec->value_map, dest, v))) 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 (strcmp(payload, flag->defval.listval.items[c]) == 0) { val.strval = payload; break; }
|
||||||
}
|
}
|
||||||
if (!val.strval) {
|
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;
|
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);
|
char *buf = alloc_for_cli(spec, bufsz);
|
||||||
int n = snprintf(buf, bufsz, "%s is an invalid value for %s. Valid values are:",
|
int n = snprintf(buf, bufsz, "%s is an invalid value for %s. Valid values are:",
|
||||||
payload[0] ? payload : "<empty>", alias);
|
payload[0] ? payload : "<empty>", alias);
|
||||||
|
|||||||
@@ -106,13 +106,14 @@ version
|
|||||||
t('-01=y', bool_reset=False, bool_set=True)
|
t('-01=y', bool_reset=False, bool_set=True)
|
||||||
t('-01=n', bool_reset=False, bool_set=False)
|
t('-01=n', bool_reset=False, bool_set=False)
|
||||||
t('--simple-string xx moo -1', leftover=['moo', '-1'], simple_string='xx')
|
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=-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('--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('-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('-1s= -l "" --list= x', leftover=['x'], bool_set=True, simple_string='', list=['', ''])
|
||||||
t('--choice moo', fails='a, b, c')
|
t('--choice moo', fails='a, b, c')
|
||||||
|
t('--bool', fails='mbiguous')
|
||||||
t('-1c moo', fails='a, b, c')
|
t('-1c moo', fails='a, b, c')
|
||||||
t('-10c=moo', fails='a, b, c')
|
t('-10c=moo', fails='a, b, c')
|
||||||
t('-1 -h', fails=True, help_called=True)
|
t('-1 -h', fails=True, help_called=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user