By default we show porcelain, external commands and a couple others
that are also popular. If you are not happy with this list, you can
now customize it. See the big comment block for details.

PS. perhaps I should make aliases a group too, which makes it possible
to _not_ complete aliases by omitting this special group in
$GIT_COMPLETION_CMD_GROUPS
---
 contrib/completion/git-completion.bash | 35 ++++++++++++++++++++++++++
 git.c                                  |  2 ++
 help.c                                 | 33 ++++++++++++++++++++++++
 help.h                                 |  1 +
 4 files changed, 71 insertions(+)

diff --git a/contrib/completion/git-completion.bash 
b/contrib/completion/git-completion.bash
index 908692ea52..0fd29803d5 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -38,6 +38,38 @@
 #
 #     When set to "1", do not include "DWIM" suggestions in git-checkout
 #     completion (e.g., completing "foo" when "origin/foo" exists).
+#
+#   GIT_COMPLETION_CMD_GROUPS
+#
+#     When set, "git --list-cmds=$GIT_COMPLETION_CMD_GROUPS" will be
+#     used to get the list of completable commands. The default is
+#     "mainporcelain,others,list-complete" (in English: all porcelain
+#     commands and external ones are included. Certain non-porcelain
+#     commands are also marked for completion in command-list.txt).
+#     You could for example complete all commands with
+#
+#         GIT_COMPLETION_CMD_GROUPS=main,others
+#
+#     Or you could go with defaults add some extra commands specified
+#     in the configuration variable completion.commands [1] with
+#
+#         GIT_COMPLETION_CMD_GROUPS=mainporcelain,others,list-complete,config
+#
+#     Or go completely custom group with
+#
+#         GIT_COMPLETION_CMD_GROUPS=config
+#
+#     Or you could even play with other command categories found in
+#     command-list.txt.
+#
+#     [1] Note that completion.commands should not be per-repository
+#         since the command list is generated once and cached.
+#
+#         completion.commands could be used to exclude commands as
+#         well.  If a command in this list begins with '-', then it
+#         will be excluded from the list of commands gathered by the
+#         groups specified before "config" in
+#         $GIT_COMPLETION_CMD_GROUPS.
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -840,6 +872,9 @@ __git_commands () {
                if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
                then
                        printf "%s" "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
+               elif test -n "$GIT_COMPLETION_CMD_GROUPS"
+               then
+                       git --list-cmds="$GIT_COMPLETION_CMD_GROUPS"
                else
                        git --list-cmds=list-mainporcelain,others,list-complete
                fi
diff --git a/git.c b/git.c
index 67f3e20ae9..fd08911e11 100644
--- a/git.c
+++ b/git.c
@@ -53,6 +53,8 @@ static int list_cmds(const char *spec)
                        list_all_main_cmds(&list);
                else if (len == 6 && !strncmp(spec, "others", 6))
                        list_all_other_cmds(&list);
+               else if (len == 6 && !strncmp(spec, "config", 6))
+                       list_cmds_by_config(&list);
                else if (len > 5 && !strncmp(spec, "list-", 5)) {
                        struct strbuf sb = STRBUF_INIT;
 
diff --git a/help.c b/help.c
index 23924dd300..abf87205b2 100644
--- a/help.c
+++ b/help.c
@@ -366,6 +366,39 @@ void list_cmds_by_category(struct string_list *list,
        }
 }
 
+void list_cmds_by_config(struct string_list *list)
+{
+       const char *cmd_list;
+
+       /*
+        * There's no actual repository setup at this point (and even
+        * if there is, we don't really care; only global config
+        * matters). If we accidentally set up a repository, it's ok
+        * too since the caller (git --list-cmds=) should exit shortly
+        * anyway.
+        */
+       if (git_config_get_string_const("completion.commands", &cmd_list))
+               return;
+
+       string_list_sort(list);
+       string_list_remove_duplicates(list, 0);
+
+       while (*cmd_list) {
+               struct strbuf sb = STRBUF_INIT;
+               const char *p = strchrnul(cmd_list, ' ');
+
+               strbuf_add(&sb, cmd_list, p - cmd_list);
+               if (*cmd_list == '-')
+                       string_list_remove(list, cmd_list + 1, 0);
+               else
+                       string_list_insert(list, sb.buf);
+               strbuf_release(&sb);
+               while (*p == ' ')
+                       p++;
+               cmd_list = p;
+       }
+}
+
 void list_common_guides_help(void)
 {
        struct category_description catdesc[] = {
diff --git a/help.h b/help.h
index b2293e99be..3b38292a1b 100644
--- a/help.h
+++ b/help.h
@@ -26,6 +26,7 @@ extern void list_all_main_cmds(struct string_list *list);
 extern void list_all_other_cmds(struct string_list *list);
 extern void list_cmds_by_category(struct string_list *list,
                                  const char *category);
+extern void list_cmds_by_config(struct string_list *list);
 extern const char *help_unknown_cmd(const char *cmd);
 extern void load_command_list(const char *prefix,
                              struct cmdnames *main_cmds,
-- 
2.17.0.705.g3525833791

Reply via email to