parse-options: support --git-completion-helper

This option is designed to be used by git-completion.bash. For many simple cases, what we do in there is usually __gitcomp "lots of completion options" which has to be manually updated when a new user-visible option is added. With support from parse-options, we can write __gitcomp "$(git command --git-completion-helper)" and get that list directly from the parser for free. Dangerous/Unpopular options could be hidden with the new "NOCOMPLETE" flag. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Feb 9, 2018 at 18:01 UTC b9d7f4b4dbebea34ca8d02be8889884fc3fb90c7
2 files changed +48 -1
parse-options.c
+44
@@ -425,6 +425,46 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,
425 parse_options_check(options);
426 }
427
428 +/*
429 + * TODO: we are not completing the --no-XXX form yet because there are
430 + * many options that do not suppress it properly.
431 + */
432 +static int show_gitcomp(struct parse_opt_ctx_t *ctx,
433 + const struct option *opts)
434 +{
435 + for (; opts->type != OPTION_END; opts++) {
436 + const char *suffix = "";
437 +
438 + if (!opts->long_name)
439 + continue;
440 + if (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE))
441 + continue;
442 +
443 + switch (opts->type) {
444 + case OPTION_GROUP:
445 + continue;
446 + case OPTION_STRING:
447 + case OPTION_FILENAME:
448 + case OPTION_INTEGER:
449 + case OPTION_MAGNITUDE:
450 + case OPTION_CALLBACK:
451 + if (opts->flags & PARSE_OPT_NOARG)
452 + break;
453 + if (opts->flags & PARSE_OPT_OPTARG)
454 + break;
455 + if (opts->flags & PARSE_OPT_LASTARG_DEFAULT)
456 + break;
457 + suffix = "=";
458 + break;
459 + default:
460 + break;
461 + }
462 + printf(" --%s%s", opts->long_name, suffix);
463 + }
464 + fputc('\n', stdout);
465 + exit(0);
466 +}
467 +
468 static int usage_with_options_internal(struct parse_opt_ctx_t *,
469 const char * const *,
470 const struct option *, int, int);
@@ -455,6 +495,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
495 if (internal_help && ctx->total == 1 && !strcmp(arg + 1, "h"))
496 goto show_usage;
497
498 + /* lone --git-completion-helper is asked by git-completion.bash */
499 + if (ctx->total == 1 && !strcmp(arg + 1, "-git-completion-helper"))
500 + return show_gitcomp(ctx, options);
501 +
502 if (arg[1] != '-') {
503 ctx->opt = arg + 1;
504 switch (parse_short_opt(ctx, options)) {
parse-options.h
+4 -1
@@ -38,7 +38,8 @@ enum parse_opt_option_flags {
38 PARSE_OPT_LASTARG_DEFAULT = 16,
39 PARSE_OPT_NODASH = 32,
40 PARSE_OPT_LITERAL_ARGHELP = 64,
41 - PARSE_OPT_SHELL_EVAL = 256
41 + PARSE_OPT_SHELL_EVAL = 256,
42 + PARSE_OPT_NOCOMPLETE = 512
43 };
44
45 struct option;
@@ -89,6 +90,8 @@ typedef int parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
90 * PARSE_OPT_LITERAL_ARGHELP: says that argh shouldn't be enclosed in brackets
91 * (i.e. '<argh>') in the help message.
92 * Useful for options with multiple parameters.
93 + * PARSE_OPT_NOCOMPLETE: by default all visible options are completable
94 + * by git-completion.bash. This option suppresses that.
95 *
96 * `callback`::
97 * pointer to the callback to use for OPTION_CALLBACK or