parse-options: add parse_options_takes_argument()

Whether an option takes a value, and therefore consumes the next
argument when that value is not stuck to it with an '=', is decided by
its type and its flags. That rule is currently open-coded in
show_gitcomp(), which needs it to decide if it should append an '=' to
the option it completes.

A following commit will need the same rule to find out which options an
early scan of the command line has to skip along with their value.

So let's factor that rule out into a new parse_options_takes_argument()
function, and let's use it in show_gitcomp().

Note that an option with PARSE_OPT_LASTARG_DEFAULT only consumes the
next argument when it isn't the last one. It is considered as taking a
value by parse_options_takes_argument(), as an early scan can easily
check whether there is a next argument, and would otherwise wrongly
take that argument for an option. show_gitcomp() keeps not appending
an '=' to such an option though, as it already did, since its value is
optional.

Signed-off-by: Christian Couder <christian.couder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Christian Couder authored and Junio C Hamano committed 2026-11-02 11:02:27 -08:00
1 parent 1630431f32
commit 6aa1fb2271
2 files changed
+33 -13

No files matched your search

+22 -13
View File
@@ -841,6 +841,25 @@ static void show_negated_gitcomp(const struct option *opts, int show_all,
}
}
int parse_options_takes_argument(const struct option *opt)
{
switch (opt->type) {
case OPTION_STRING:
case OPTION_FILENAME:
case OPTION_INTEGER:
case OPTION_UNSIGNED:
case OPTION_CALLBACK:
break;
default:
return 0;
}
if (opt->flags & (PARSE_OPT_NOARG | PARSE_OPT_OPTARG))
return 0;
return 1;
}
static int show_gitcomp(const struct option *opts, int show_all)
{
const struct option *original_opts = opts;
@@ -862,20 +881,10 @@ static int show_gitcomp(const struct option *opts, int show_all)
break;
case OPTION_GROUP:
continue;
case OPTION_STRING:
case OPTION_FILENAME:
case OPTION_INTEGER:
case OPTION_UNSIGNED:
case OPTION_CALLBACK:
if (opts->flags & PARSE_OPT_NOARG)
break;
if (opts->flags & PARSE_OPT_OPTARG)
break;
if (opts->flags & PARSE_OPT_LASTARG_DEFAULT)
break;
suffix = "=";
break;
default:
if (parse_options_takes_argument(opts) &&
!(opts->flags & PARSE_OPT_LASTARG_DEFAULT))
suffix = "=";
break;
}
if (opts->flags & PARSE_OPT_COMP_ARG)
+11
View File
@@ -420,6 +420,17 @@ int parse_options(int argc, const char **argv, const char *prefix,
const char * const usagestr[],
enum parse_opt_flags flags);
/*
* Return non-zero if `opt` takes a value, which means that it consumes
* the next argument when that value is not stuck to it with an '='.
*
* Note that an option with PARSE_OPT_LASTARG_DEFAULT is considered as
* taking a value here, even though it only consumes the next argument
* when it isn't the last one. Callers that care have to check for that
* flag themselves.
*/
int parse_options_takes_argument(const struct option *opt);
NORETURN void usage_with_options(const char * const *usagestr,
const struct option *options);