diff options
-rw-r--r-- | contrib/completion/git-completion.bash | 75 | ||||
-rw-r--r-- | git.c | 122 | ||||
-rwxr-xr-x | t/t9902-completion.sh | 6 |
3 files changed, 127 insertions, 76 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index b09c8a2362..a757073945 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -29,6 +29,8 @@ # tell the completion to use commit completion. This also works with aliases # of form "!sh -c '...'". For example, "!sh -c ': git commit ; ... '". # +# Compatible with bash 3.2.57. +# # You can set the following environment variables to influence the behavior of # the completion routines: # @@ -1284,6 +1286,12 @@ _git_checkout () _git_cherry () { + case "$cur" in + --*) + __gitcomp_builtin cherry + return + esac + __git_complete_refs } @@ -1503,16 +1511,6 @@ _git_fsck () esac } -_git_gc () -{ - case "$cur" in - --*) - __gitcomp_builtin gc - return - ;; - esac -} - _git_gitk () { _gitk @@ -1637,6 +1635,13 @@ _git_ls_remote () _git_ls_tree () { + case "$cur" in + --*) + __gitcomp_builtin ls-tree + return + ;; + esac + __git_complete_file } @@ -1812,11 +1817,6 @@ _git_mv () fi } -_git_name_rev () -{ - __gitcomp_builtin name-rev -} - _git_notes () { local subcommands='add append copy edit get-ref list merge prune remove show' @@ -3036,6 +3036,45 @@ _git_worktree () fi } +__git_complete_common () { + local command="$1" + + case "$cur" in + --*) + __gitcomp_builtin "$command" + ;; + esac +} + +__git_cmds_with_parseopt_helper= +__git_support_parseopt_helper () { + test -n "$__git_cmds_with_parseopt_helper" || + __git_cmds_with_parseopt_helper="$(__git --list-parseopt-builtins)" + + case " $__git_cmds_with_parseopt_helper " in + *" $1 "*) + return 0 + ;; + *) + return 1 + ;; + esac +} + +__git_complete_command () { + local command="$1" + local completion_func="_git_${command//-/_}" + if declare -f $completion_func >/dev/null 2>/dev/null; then + $completion_func + return 0 + elif __git_support_parseopt_helper "$command"; then + __git_complete_common "$command" + return 0 + else + return 1 + fi +} + __git_main () { local i c=1 command __git_dir __git_repo_path @@ -3095,14 +3134,12 @@ __git_main () return fi - local completion_func="_git_${command//-/_}" - declare -f $completion_func >/dev/null 2>/dev/null && $completion_func && return + __git_complete_command "$command" && return local expansion=$(__git_aliased_command "$command") if [ -n "$expansion" ]; then words[1]=$expansion - completion_func="_git_${expansion//-/_}" - declare -f $completion_func >/dev/null 2>/dev/null && $completion_func + __git_complete_command "$expansion" fi } @@ -4,6 +4,24 @@ #include "help.h" #include "run-command.h" +#define RUN_SETUP (1<<0) +#define RUN_SETUP_GENTLY (1<<1) +#define USE_PAGER (1<<2) +/* + * require working tree to be present -- anything uses this needs + * RUN_SETUP for reading from the configuration file. + */ +#define NEED_WORK_TREE (1<<3) +#define SUPPORT_SUPER_PREFIX (1<<4) +#define DELAY_PAGER_CONFIG (1<<5) +#define NO_PARSEOPT (1<<6) /* parse-options is not used */ + +struct cmd_struct { + const char *cmd; + int (*fn)(int, const char **, const char *); + unsigned int option; +}; + const char git_usage_string[] = N_("git [--version] [--help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" @@ -18,7 +36,7 @@ const char git_more_info_string[] = static int use_pager = -1; -static void list_builtins(void); +static void list_builtins(unsigned int exclude_option, char sep); static void commit_pager_choice(void) { switch (use_pager) { @@ -206,7 +224,10 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) (*argv)++; (*argc)--; } else if (!strcmp(cmd, "--list-builtins")) { - list_builtins(); + list_builtins(0, '\n'); + exit(0); + } else if (!strcmp(cmd, "--list-parseopt-builtins")) { + list_builtins(NO_PARSEOPT, ' '); exit(0); } else { fprintf(stderr, _("unknown option: %s\n"), cmd); @@ -288,23 +309,6 @@ static int handle_alias(int *argcp, const char ***argv) return ret; } -#define RUN_SETUP (1<<0) -#define RUN_SETUP_GENTLY (1<<1) -#define USE_PAGER (1<<2) -/* - * require working tree to be present -- anything uses this needs - * RUN_SETUP for reading from the configuration file. - */ -#define NEED_WORK_TREE (1<<3) -#define SUPPORT_SUPER_PREFIX (1<<4) -#define DELAY_PAGER_CONFIG (1<<5) - -struct cmd_struct { - const char *cmd; - int (*fn)(int, const char **, const char *); - int option; -}; - static int run_builtin(struct cmd_struct *p, int argc, const char **argv) { int status, help; @@ -367,18 +371,18 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) static struct cmd_struct commands[] = { { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE }, { "am", cmd_am, RUN_SETUP | NEED_WORK_TREE }, - { "annotate", cmd_annotate, RUN_SETUP }, + { "annotate", cmd_annotate, RUN_SETUP | NO_PARSEOPT }, { "apply", cmd_apply, RUN_SETUP_GENTLY }, { "archive", cmd_archive, RUN_SETUP_GENTLY }, { "bisect--helper", cmd_bisect__helper, RUN_SETUP }, { "blame", cmd_blame, RUN_SETUP }, { "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG }, - { "bundle", cmd_bundle, RUN_SETUP_GENTLY }, + { "bundle", cmd_bundle, RUN_SETUP_GENTLY | NO_PARSEOPT }, { "cat-file", cmd_cat_file, RUN_SETUP }, { "check-attr", cmd_check_attr, RUN_SETUP }, { "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE }, { "check-mailmap", cmd_check_mailmap, RUN_SETUP }, - { "check-ref-format", cmd_check_ref_format }, + { "check-ref-format", cmd_check_ref_format, NO_PARSEOPT }, { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE }, { "checkout-index", cmd_checkout_index, RUN_SETUP | NEED_WORK_TREE}, @@ -388,30 +392,30 @@ static struct cmd_struct commands[] = { { "clone", cmd_clone }, { "column", cmd_column, RUN_SETUP_GENTLY }, { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE }, - { "commit-tree", cmd_commit_tree, RUN_SETUP }, + { "commit-tree", cmd_commit_tree, RUN_SETUP | NO_PARSEOPT }, { "config", cmd_config, RUN_SETUP_GENTLY | DELAY_PAGER_CONFIG }, { "count-objects", cmd_count_objects, RUN_SETUP }, - { "credential", cmd_credential, RUN_SETUP_GENTLY }, + { "credential", cmd_credential, RUN_SETUP_GENTLY | NO_PARSEOPT }, { "describe", cmd_describe, RUN_SETUP }, - { "diff", cmd_diff }, - { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE }, - { "diff-index", cmd_diff_index, RUN_SETUP }, - { "diff-tree", cmd_diff_tree, RUN_SETUP }, + { "diff", cmd_diff, NO_PARSEOPT }, + { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, + { "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT }, + { "diff-tree", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT }, { "difftool", cmd_difftool, RUN_SETUP | NEED_WORK_TREE }, { "fast-export", cmd_fast_export, RUN_SETUP }, { "fetch", cmd_fetch, RUN_SETUP }, - { "fetch-pack", cmd_fetch_pack, RUN_SETUP }, + { "fetch-pack", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT }, { "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP }, { "for-each-ref", cmd_for_each_ref, RUN_SETUP }, { "format-patch", cmd_format_patch, RUN_SETUP }, { "fsck", cmd_fsck, RUN_SETUP }, { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, - { "get-tar-commit-id", cmd_get_tar_commit_id }, + { "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT }, { "grep", cmd_grep, RUN_SETUP_GENTLY }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, - { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY }, + { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY | NO_PARSEOPT }, { "init", cmd_init_db }, { "init-db", cmd_init_db }, { "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY }, @@ -419,27 +423,27 @@ static struct cmd_struct commands[] = { { "ls-files", cmd_ls_files, RUN_SETUP }, { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, { "ls-tree", cmd_ls_tree, RUN_SETUP }, - { "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY }, - { "mailsplit", cmd_mailsplit }, + { "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY | NO_PARSEOPT }, + { "mailsplit", cmd_mailsplit, NO_PARSEOPT }, { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE }, { "merge-base", cmd_merge_base, RUN_SETUP }, { "merge-file", cmd_merge_file, RUN_SETUP_GENTLY }, - { "merge-index", cmd_merge_index, RUN_SETUP }, - { "merge-ours", cmd_merge_ours, RUN_SETUP }, - { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, - { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, - { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, - { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE }, - { "merge-tree", cmd_merge_tree, RUN_SETUP }, - { "mktag", cmd_mktag, RUN_SETUP }, + { "merge-index", cmd_merge_index, RUN_SETUP | NO_PARSEOPT }, + { "merge-ours", cmd_merge_ours, RUN_SETUP | NO_PARSEOPT }, + { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, + { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, + { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, + { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT }, + { "merge-tree", cmd_merge_tree, RUN_SETUP | NO_PARSEOPT }, + { "mktag", cmd_mktag, RUN_SETUP | NO_PARSEOPT }, { "mktree", cmd_mktree, RUN_SETUP }, { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE }, { "name-rev", cmd_name_rev, RUN_SETUP }, { "notes", cmd_notes, RUN_SETUP }, { "pack-objects", cmd_pack_objects, RUN_SETUP }, - { "pack-redundant", cmd_pack_redundant, RUN_SETUP }, + { "pack-redundant", cmd_pack_redundant, RUN_SETUP | NO_PARSEOPT }, { "pack-refs", cmd_pack_refs, RUN_SETUP }, - { "patch-id", cmd_patch_id, RUN_SETUP_GENTLY }, + { "patch-id", cmd_patch_id, RUN_SETUP_GENTLY | NO_PARSEOPT }, { "pickaxe", cmd_blame, RUN_SETUP }, { "prune", cmd_prune, RUN_SETUP }, { "prune-packed", cmd_prune_packed, RUN_SETUP }, @@ -450,14 +454,14 @@ static struct cmd_struct commands[] = { { "receive-pack", cmd_receive_pack }, { "reflog", cmd_reflog, RUN_SETUP }, { "remote", cmd_remote, RUN_SETUP }, - { "remote-ext", cmd_remote_ext }, - { "remote-fd", cmd_remote_fd }, + { "remote-ext", cmd_remote_ext, NO_PARSEOPT }, + { "remote-fd", cmd_remote_fd, NO_PARSEOPT }, { "repack", cmd_repack, RUN_SETUP }, { "replace", cmd_replace, RUN_SETUP }, { "rerere", cmd_rerere, RUN_SETUP }, { "reset", cmd_reset, RUN_SETUP }, - { "rev-list", cmd_rev_list, RUN_SETUP }, - { "rev-parse", cmd_rev_parse }, + { "rev-list", cmd_rev_list, RUN_SETUP | NO_PARSEOPT }, + { "rev-parse", cmd_rev_parse, NO_PARSEOPT }, { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE }, { "rm", cmd_rm, RUN_SETUP }, { "send-pack", cmd_send_pack, RUN_SETUP }, @@ -468,23 +472,23 @@ static struct cmd_struct commands[] = { { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE }, { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE }, { "stripspace", cmd_stripspace }, - { "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX}, + { "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX | NO_PARSEOPT }, { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP }, { "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG }, - { "unpack-file", cmd_unpack_file, RUN_SETUP }, - { "unpack-objects", cmd_unpack_objects, RUN_SETUP }, + { "unpack-file", cmd_unpack_file, RUN_SETUP | NO_PARSEOPT }, + { "unpack-objects", cmd_unpack_objects, RUN_SETUP | NO_PARSEOPT }, { "update-index", cmd_update_index, RUN_SETUP }, { "update-ref", cmd_update_ref, RUN_SETUP }, { "update-server-info", cmd_update_server_info, RUN_SETUP }, - { "upload-archive", cmd_upload_archive }, - { "upload-archive--writer", cmd_upload_archive_writer }, - { "var", cmd_var, RUN_SETUP_GENTLY }, + { "upload-archive", cmd_upload_archive, NO_PARSEOPT }, + { "upload-archive--writer", cmd_upload_archive_writer, NO_PARSEOPT }, + { "var", cmd_var, RUN_SETUP_GENTLY | NO_PARSEOPT }, { "verify-commit", cmd_verify_commit, RUN_SETUP }, { "verify-pack", cmd_verify_pack }, { "verify-tag", cmd_verify_tag, RUN_SETUP }, { "version", cmd_version }, { "whatchanged", cmd_whatchanged, RUN_SETUP }, - { "worktree", cmd_worktree, RUN_SETUP }, + { "worktree", cmd_worktree, RUN_SETUP | NO_PARSEOPT }, { "write-tree", cmd_write_tree, RUN_SETUP }, }; @@ -504,11 +508,15 @@ int is_builtin(const char *s) return !!get_builtin(s); } -static void list_builtins(void) +static void list_builtins(unsigned int exclude_option, char sep) { int i; - for (i = 0; i < ARRAY_SIZE(commands); i++) - printf("%s\n", commands[i].cmd); + for (i = 0; i < ARRAY_SIZE(commands); i++) { + if (exclude_option && + (commands[i].option & exclude_option)) + continue; + printf("%s%c", commands[i].cmd, sep); + } } #ifdef STRIP_EXTENSION diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index b7f5b1e632..1b34caa1e1 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -1454,6 +1454,12 @@ test_expect_success 'completion used <cmd> completion for alias: !f() { : git <c EOF ' +test_expect_success 'completion without explicit _git_xxx function' ' + test_completion "git version --" <<-\EOF + --build-options Z + EOF +' + test_expect_failure 'complete with tilde expansion' ' git init tmp && cd tmp && test_when_finished "cd .. && rm -rf tmp" && |