Merge branch 'nd/completion-negation'

Continuing with the idea to programmatically enumerate various
pieces of data required for command line completion, the codebase
has been taught to enumerate options prefixed with "--no-" to
negate them.

* nd/completion-negation:
  completion: collapse extra --no-.. options
  completion: suppress some -no- options
  parse-options: option to let --git-completion-helper show negative form
This commit is contained in:
Junio C Hamano 2018-06-28 12:53:32 -07:00
commit 6da2d95951
4 changed files with 136 additions and 34 deletions

View file

@ -1120,10 +1120,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
OPT_SET_INT('t', "track", &opts.track, N_("set upstream info for new branch"),
BRANCH_TRACK_EXPLICIT),
OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new-branch"), N_("new unparented branch")),
OPT_SET_INT('2', "ours", &opts.writeout_stage, N_("checkout our version for unmerged files"),
2),
OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"),
3),
OPT_SET_INT_F('2', "ours", &opts.writeout_stage,
N_("checkout our version for unmerged files"),
2, PARSE_OPT_NONEG),
OPT_SET_INT_F('3', "theirs", &opts.writeout_stage,
N_("checkout their version for unmerged files"),
3, PARSE_OPT_NONEG),
OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)"),
PARSE_OPT_NOCOMPLETE),
OPT_BOOL('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")),

View file

@ -330,9 +330,32 @@ __gitcomp ()
case "$cur_" in
--*=)
;;
--no-*)
local c i=0 IFS=$' \t\n'
for c in $1; do
if [[ $c == "--" ]]; then
continue
fi
c="$c${4-}"
if [[ $c == "$cur_"* ]]; then
case $c in
--*=*|*.) ;;
*) c="$c " ;;
esac
COMPREPLY[i++]="${2-}$c"
fi
done
;;
*)
local c i=0 IFS=$' \t\n'
for c in $1; do
if [[ $c == "--" ]]; then
c="--no-...${4-}"
if [[ $c == "$cur_"* ]]; then
COMPREPLY[i++]="${2-}$c "
fi
break
fi
c="$c${4-}"
if [[ $c == "$cur_"* ]]; then
case $c in
@ -1161,7 +1184,7 @@ _git_am ()
return
;;
--*)
__gitcomp_builtin am "--no-utf8" \
__gitcomp_builtin am "" \
"$__git_am_inprogress_options"
return
esac
@ -1261,9 +1284,7 @@ _git_branch ()
__git_complete_refs --cur="${cur##--set-upstream-to=}"
;;
--*)
__gitcomp_builtin branch "--no-color --no-abbrev
--no-track --no-column
"
__gitcomp_builtin branch
;;
*)
if [ $only_local_ref = "y" -a $has_r = "n" ]; then
@ -1304,7 +1325,7 @@ _git_checkout ()
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
;;
--*)
__gitcomp_builtin checkout "--no-track --no-recurse-submodules"
__gitcomp_builtin checkout
;;
*)
# check if --track, --no-track, or --no-guess was specified
@ -1367,7 +1388,7 @@ _git_clone ()
{
case "$cur" in
--*)
__gitcomp_builtin clone "--no-single-branch"
__gitcomp_builtin clone
return
;;
esac
@ -1400,7 +1421,7 @@ _git_commit ()
return
;;
--*)
__gitcomp_builtin commit "--no-edit --verify"
__gitcomp_builtin commit
return
esac
@ -1503,7 +1524,7 @@ _git_fetch ()
return
;;
--*)
__gitcomp_builtin fetch "--no-tags"
__gitcomp_builtin fetch
return
;;
esac
@ -1540,7 +1561,7 @@ _git_fsck ()
{
case "$cur" in
--*)
__gitcomp_builtin fsck "--no-reflogs"
__gitcomp_builtin fsck
return
;;
esac
@ -1646,7 +1667,7 @@ _git_ls_files ()
{
case "$cur" in
--*)
__gitcomp_builtin ls-files "--no-empty-directory"
__gitcomp_builtin ls-files
return
;;
esac
@ -1797,12 +1818,7 @@ _git_merge ()
case "$cur" in
--*)
__gitcomp_builtin merge "--no-rerere-autoupdate
--no-commit --no-edit --no-ff
--no-log --no-progress
--no-squash --no-stat
--no-verify-signatures
"
__gitcomp_builtin merge
return
esac
__git_complete_refs
@ -1901,10 +1917,7 @@ _git_pull ()
return
;;
--*)
__gitcomp_builtin pull "--no-autostash --no-commit --no-edit
--no-ff --no-log --no-progress --no-rebase
--no-squash --no-stat --no-tags
--no-verify-signatures"
__gitcomp_builtin pull
return
;;
@ -2095,7 +2108,7 @@ _git_status ()
return
;;
--*)
__gitcomp_builtin status "--no-column"
__gitcomp_builtin status
return
;;
esac
@ -2345,7 +2358,7 @@ _git_remote ()
case "$subcommand,$cur" in
add,--*)
__gitcomp_builtin remote_add "--no-tags"
__gitcomp_builtin remote_add
;;
add,*)
;;
@ -2425,7 +2438,7 @@ _git_revert ()
fi
case "$cur" in
--*)
__gitcomp_builtin revert "--no-edit" \
__gitcomp_builtin revert "" \
"$__git_revert_inprogress_options"
return
;;
@ -2495,7 +2508,7 @@ _git_show_branch ()
{
case "$cur" in
--*)
__gitcomp_builtin show-branch "--no-color"
__gitcomp_builtin show-branch
return
;;
esac

View file

@ -427,13 +427,59 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,
parse_options_check(options);
}
/*
* TODO: we are not completing the --no-XXX form yet because there are
* many options that do not suppress it properly.
*/
static void show_negated_gitcomp(const struct option *opts, int nr_noopts)
{
int printed_dashdash = 0;
for (; opts->type != OPTION_END; opts++) {
int has_unset_form = 0;
const char *name;
if (!opts->long_name)
continue;
if (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE))
continue;
if (opts->flags & PARSE_OPT_NONEG)
continue;
switch (opts->type) {
case OPTION_STRING:
case OPTION_FILENAME:
case OPTION_INTEGER:
case OPTION_MAGNITUDE:
case OPTION_CALLBACK:
case OPTION_BIT:
case OPTION_NEGBIT:
case OPTION_COUNTUP:
case OPTION_SET_INT:
has_unset_form = 1;
break;
default:
break;
}
if (!has_unset_form)
continue;
if (skip_prefix(opts->long_name, "no-", &name)) {
if (nr_noopts < 0)
printf(" --%s", name);
} else if (nr_noopts >= 0) {
if (nr_noopts && !printed_dashdash) {
printf(" --");
printed_dashdash = 1;
}
printf(" --no-%s", opts->long_name);
nr_noopts++;
}
}
}
static int show_gitcomp(struct parse_opt_ctx_t *ctx,
const struct option *opts)
{
const struct option *original_opts = opts;
int nr_noopts = 0;
for (; opts->type != OPTION_END; opts++) {
const char *suffix = "";
@ -463,8 +509,12 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,
}
if (opts->flags & PARSE_OPT_COMP_ARG)
suffix = "=";
if (starts_with(opts->long_name, "no-"))
nr_noopts++;
printf(" --%s%s", opts->long_name, suffix);
}
show_negated_gitcomp(original_opts, -1);
show_negated_gitcomp(original_opts, nr_noopts);
fputc('\n', stdout);
exit(0);
}

View file

@ -501,6 +501,42 @@ test_expect_success '__gitcomp - suffix' '
EOF
'
test_expect_success '__gitcomp - ignore optional negative options' '
test_gitcomp "--" "--abc --def --no-one -- --no-two" <<-\EOF
--abc Z
--def Z
--no-one Z
--no-... Z
EOF
'
test_expect_success '__gitcomp - ignore/narrow optional negative options' '
test_gitcomp "--a" "--abc --abcdef --no-one -- --no-two" <<-\EOF
--abc Z
--abcdef Z
EOF
'
test_expect_success '__gitcomp - ignore/narrow optional negative options' '
test_gitcomp "--n" "--abc --def --no-one -- --no-two" <<-\EOF
--no-one Z
--no-... Z
EOF
'
test_expect_success '__gitcomp - expand all negative options' '
test_gitcomp "--no-" "--abc --def --no-one -- --no-two" <<-\EOF
--no-one Z
--no-two Z
EOF
'
test_expect_success '__gitcomp - expand/narrow all negative options' '
test_gitcomp "--no-o" "--abc --def --no-one -- --no-two" <<-\EOF
--no-one Z
EOF
'
test_expect_success '__gitcomp - doesnt fail because of invalid variable name' '
__gitcomp "$invalid_variable_name"
'
@ -1398,8 +1434,8 @@ test_expect_success 'double dash "git checkout"' '
--ignore-other-worktrees Z
--recurse-submodules Z
--progress Z
--no-track Z
--no-recurse-submodules Z
--no-quiet Z
--no-... Z
EOF
'
@ -1607,6 +1643,7 @@ test_expect_success 'completion used <cmd> completion for alias: !f() { : git <c
test_expect_success 'completion without explicit _git_xxx function' '
test_completion "git version --" <<-\EOF
--build-options Z
--no-build-options Z
EOF
'