Skip to content

Commit

Permalink
Merge branch 'rs/parse-options-negation-help' into next
Browse files Browse the repository at this point in the history
"git cmd -h" learned to signal which options can be negated by
listing such options like "--[no-]opt".

* rs/parse-options-negation-help:
  parse-options: simplify usage_padding()
  parse-options: no --[no-]no-...
  parse-options: factor out usage_indent() and usage_padding()
  parse-options: show negatability of options in short help
  t1502: test option negation
  t1502: move optionspec help output to a file
  t1502, docs: disallow --no-help
  subtree: disallow --no-{help,quiet,debug,branch,message}
  • Loading branch information
gitster committed Aug 18, 2023
2 parents b4bdf1a + 311c8ff commit 9d37b5f
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 125 deletions.
10 changes: 5 additions & 5 deletions Documentation/git-rev-parse.txt
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ some-command [<options>] <args>...

some-command does foo and bar!
--
h,help show the help
h,help! show the help

foo some nifty option --foo
bar= some cool option --bar with an argument
Expand All @@ -424,10 +424,10 @@ usage: some-command [<options>] <args>...
some-command does foo and bar!

-h, --help show the help
--foo some nifty option --foo
--bar ... some cool option --bar with an argument
--baz <arg> another cool option --baz with a named argument
--qux[=<path>] qux may take a path argument but has meaning by itself
--[no-]foo some nifty option --foo
--[no-]bar ... some cool option --bar with an argument
--[no-]baz <arg> another cool option --baz with a named argument
--[no-]qux[=<path>] qux may take a path argument but has meaning by itself

An option group Header
-C[...] option C with an optional argument
Expand Down
10 changes: 5 additions & 5 deletions contrib/subtree/git-subtree.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@ git subtree split --prefix=<prefix> [<commit>]
git subtree pull --prefix=<prefix> <repository> <ref>
git subtree push --prefix=<prefix> <repository> <refspec>
--
h,help show the help
q,quiet quiet
d,debug show debug messages
h,help! show the help
q,quiet! quiet
d,debug! show debug messages
P,prefix= the name of the subdir to split out
options for 'split' (also: 'push')
annotate= add a prefix to commit message of new commits
b,branch= create a new branch from the split subtree
b,branch!= create a new branch from the split subtree
ignore-joins ignore prior --rejoin commits
onto= try connecting new tree to an existing one
rejoin merge the new branch back into HEAD
options for 'add' and 'merge' (also: 'pull', 'split --rejoin', and 'push --rejoin')
squash merge subtree changes as a single commit
m,message= use the given message as the commit message for the merge commit
m,message!= use the given message as the commit message for the merge commit
"

indent=0
Expand Down
2 changes: 1 addition & 1 deletion contrib/subtree/t/t7900-subtree.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ test_expect_success 'shows short help text for -h' '
test_expect_code 129 git subtree -h >out 2>err &&
test_must_be_empty err &&
grep -e "^ *or: git subtree pull" out &&
grep -e --annotate out
grep -F -e "--[no-]annotate" out
'

#
Expand Down
69 changes: 50 additions & 19 deletions parse-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -1023,14 +1023,37 @@ static int usage_argh(const struct option *opts, FILE *outfile)
return utf8_fprintf(outfile, s, opts->argh ? _(opts->argh) : _("..."));
}

#define USAGE_OPTS_WIDTH 24
#define USAGE_GAP 2
static int usage_indent(FILE *outfile)
{
return fprintf(outfile, " ");
}

#define USAGE_OPTS_WIDTH 26

static void usage_padding(FILE *outfile, size_t pos)
{
if (pos < USAGE_OPTS_WIDTH)
fprintf(outfile, "%*s", USAGE_OPTS_WIDTH - (int)pos, "");
else
fprintf(outfile, "\n%*s", USAGE_OPTS_WIDTH, "");
}

static const struct option *find_option_by_long_name(const struct option *opts,
const char *long_name)
{
for (; opts->type != OPTION_END; opts++) {
if (opts->long_name && !strcmp(opts->long_name, long_name))
return opts;
}
return NULL;
}

static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t *ctx,
const char * const *usagestr,
const struct option *opts,
int full, int err)
{
const struct option *all_opts = opts;
FILE *outfile = err ? stderr : stdout;
int need_newline;

Expand Down Expand Up @@ -1111,8 +1134,8 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t

for (; opts->type != OPTION_END; opts++) {
size_t pos;
int pad;
const char *cp, *np;
const char *positive_name = NULL;

if (opts->type == OPTION_SUBCOMMAND)
continue;
Expand All @@ -1131,7 +1154,7 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
need_newline = 0;
}

pos = fprintf(outfile, " ");
pos = usage_indent(outfile);
if (opts->short_name) {
if (opts->flags & PARSE_OPT_NODASH)
pos += fprintf(outfile, "%c", opts->short_name);
Expand All @@ -1140,38 +1163,46 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
}
if (opts->long_name && opts->short_name)
pos += fprintf(outfile, ", ");
if (opts->long_name)
pos += fprintf(outfile, "--%s", opts->long_name);
if (opts->long_name) {
const char *long_name = opts->long_name;
if ((opts->flags & PARSE_OPT_NONEG) ||
skip_prefix(long_name, "no-", &positive_name))
pos += fprintf(outfile, "--%s", long_name);
else
pos += fprintf(outfile, "--[no-]%s", long_name);
}

if (opts->type == OPTION_NUMBER)
pos += utf8_fprintf(outfile, _("-NUM"));

if ((opts->flags & PARSE_OPT_LITERAL_ARGHELP) ||
!(opts->flags & PARSE_OPT_NOARG))
pos += usage_argh(opts, outfile);

if (pos == USAGE_OPTS_WIDTH + 1)
pad = -1;
else if (pos <= USAGE_OPTS_WIDTH)
pad = USAGE_OPTS_WIDTH - pos;
else {
fputc('\n', outfile);
pad = USAGE_OPTS_WIDTH;
}
if (opts->type == OPTION_ALIAS) {
fprintf(outfile, "%*s", pad + USAGE_GAP, "");
usage_padding(outfile, pos);
fprintf_ln(outfile, _("alias of --%s"),
(const char *)opts->value);
continue;
}

for (cp = _(opts->help); *cp; cp = np) {
np = strchrnul(cp, '\n');
fprintf(outfile,
"%*s%.*s\n", pad + USAGE_GAP, "",
(int)(np - cp), cp);
usage_padding(outfile, pos);
fprintf(outfile, "%.*s\n", (int)(np - cp), cp);
if (*np)
np++;
pad = USAGE_OPTS_WIDTH;
pos = 0;
}

if (positive_name) {
if (find_option_by_long_name(all_opts, positive_name))
continue;
pos = usage_indent(outfile);
pos += fprintf(outfile, "--%s", positive_name);
usage_padding(outfile, pos);
fprintf_ln(outfile, _("opposite of --no-%s"),
positive_name);
}
}
fputc('\n', outfile);
Expand Down
44 changes: 25 additions & 19 deletions t/t0040-parse-options.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,35 @@ usage: test-tool parse-options <options>
A helper function for the parse-options API.
--yes get a boolean
--[no-]yes get a boolean
-D, --no-doubt begins with 'no-'
--doubt opposite of --no-doubt
-B, --no-fear be brave
-b, --boolean increment by one
-4, --or4 bitwise-or boolean with ...0100
--neg-or4 same as --no-or4
-b, --[no-]boolean increment by one
-4, --[no-]or4 bitwise-or boolean with ...0100
--[no-]neg-or4 same as --no-or4
-i, --integer <n> get a integer
-i, --[no-]integer <n>
get a integer
-j <n> get a integer, too
-m, --magnitude <n> get a magnitude
--set23 set integer to 23
--[no-]set23 set integer to 23
--mode1 set integer to 1 (cmdmode option)
--mode2 set integer to 2 (cmdmode option)
-L, --length <str> get length of <str>
-F, --file <file> set file to <file>
-L, --[no-]length <str>
get length of <str>
-F, --[no-]file <file>
set file to <file>
String options
-s, --string <string> get a string
--string2 <str> get another string
--st <st> get another string (pervert ordering)
-s, --[no-]string <string>
get a string
--[no-]string2 <str> get another string
--[no-]st <st> get another string (pervert ordering)
-o <str> get another string
--longhelp help text of this entry
spans multiple lines
--list <str> add str to list
--[no-]list <str> add str to list
Magic arguments
-NUM set integer to NUM
Expand All @@ -45,16 +50,17 @@ Magic arguments
--no-ambiguous negative ambiguity
Standard options
--abbrev[=<n>] use <n> digits to display object names
-v, --verbose be verbose
-n, --dry-run dry run
-q, --quiet be quiet
--expect <string> expected output in the variable dump
--[no-]abbrev[=<n>] use <n> digits to display object names
-v, --[no-]verbose be verbose
-n, --[no-]dry-run dry run
-q, --[no-]quiet be quiet
--[no-]expect <string>
expected output in the variable dump
Alias
-A, --alias-source <string>
-A, --[no-]alias-source <string>
get a string
-Z, --alias-target <string>
-Z, --[no-]alias-target <string>
alias of --alias-source
EOF
Expand Down
Loading

0 comments on commit 9d37b5f

Please sign in to comment.