completion: add and use --list-cmds=alias

By providing aliases via --list-cmds=, we could simplify command collection code in the script. We only issue one git command. Before this patch that is "git config", after it's "git --list-cmds=". In "git help" completion case we actually reduce one "git" process (for getting guides) but that call was added in this series so it does not really count. A couple of bash functions are removed because they are not needed anymore. __git_compute_all_commands() and $__git_all_commands stay because they are still needed for completing pager.* config and without "alias" group, the result is still cacheable. There is a slight (good) change in _git_help() with this patch: before "git help <tab>" shows external commands (as in _not_ part of git) as well as part of $__git_all_commands. We have finer control over command listing now and can exclude that because we can't provide a man page for external commands anyway. 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 May 20, 2018 at 20:40 UTC 3301d36b29467a05107340e4d9688ebf74335021
6 files changed +40 -81
Documentation/git.txt
+1 -1
@@ -170,7 +170,7 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config
170 parse-options), main (all commands in libexec directory),
171 others (all other commands in `$PATH` that have git- prefix),
172 list-<category> (see categories in command-list.txt),
173 - nohelpers (exclude helper commands).
173 + nohelpers (exclude helper commands) and alias.
174
175 GIT COMMANDS
176 ------------
alias.c
+19 -2
@@ -1,10 +1,12 @@
1 #include "cache.h"
2 #include "alias.h"
3 #include "config.h"
4 +#include "string-list.h"
5
6 struct config_alias_data {
7 const char *alias;
8 char *v;
9 + struct string_list *list;
10 };
11
12 static int config_alias_cb(const char *key, const char *value, void *d)
@@ -12,8 +14,16 @@ static int config_alias_cb(const char *key, const char *value, void *d)
14 struct config_alias_data *data = d;
15 const char *p;
16
15 - if (skip_prefix(key, "alias.", &p) && !strcasecmp(p, data->alias))
16 - return git_config_string((const char **)&data->v, key, value);
17 + if (!skip_prefix(key, "alias.", &p))
18 + return 0;
19 +
20 + if (data->alias) {
21 + if (!strcasecmp(p, data->alias))
22 + return git_config_string((const char **)&data->v,
23 + key, value);
24 + } else if (data->list) {
25 + string_list_append(data->list, p);
26 + }
27
28 return 0;
29 }
@@ -27,6 +37,13 @@ char *alias_lookup(const char *alias)
37 return data.v;
38 }
39
40 +void list_aliases(struct string_list *list)
41 +{
42 + struct config_alias_data data = { NULL, NULL, list };
43 +
44 + read_early_config(config_alias_cb, &data);
45 +}
46 +
47 #define SPLIT_CMDLINE_BAD_ENDING 1
48 #define SPLIT_CMDLINE_UNCLOSED_QUOTE 2
49 static const char *split_cmdline_errors[] = {
alias.h
+3
@@ -1,9 +1,12 @@
1 #ifndef __ALIAS_H__
2 #define __ALIAS_H__
3
4 +struct string_list;
5 +
6 char *alias_lookup(const char *alias);
7 int split_cmdline(char *cmdline, const char ***argv);
8 /* Takes a negative value returned by split_cmdline */
9 const char *split_cmdline_strerror(int cmdline_errno);
10 +void list_aliases(struct string_list *list);
11
12 #endif
contrib/completion/git-completion.bash
+15 -60
@@ -834,51 +834,11 @@ __git_complete_strategy ()
834 return 1
835 }
836
837 -# __git_commands requires 1 argument:
838 -# 1: the command group, either "all" or "porcelain"
839 -__git_commands () {
840 - case "$1" in
841 - porcelain)
842 - if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
843 - then
844 - printf "%s" "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
845 - else
846 - git --list-cmds=list-mainporcelain,others,nohelpers,list-complete
847 - fi
848 - ;;
849 - all)
850 - if test -n "$GIT_TESTING_ALL_COMMAND_LIST"
851 - then
852 - printf "%s" "$GIT_TESTING_ALL_COMMAND_LIST"
853 - else
854 - git --list-cmds=main,others,nohelpers
855 - fi
856 - ;;
857 - esac
858 -}
859 -
860 -__git_list_all_commands ()
861 -{
862 - __git_commands all
863 -}
864 -
837 __git_all_commands=
838 __git_compute_all_commands ()
839 {
840 test -n "$__git_all_commands" ||
869 - __git_all_commands=$(__git_list_all_commands)
870 -}
871 -
872 -__git_list_porcelain_commands ()
873 -{
874 - __git_commands porcelain
875 -}
876 -
877 -__git_porcelain_commands=
878 -__git_compute_porcelain_commands ()
879 -{
880 - test -n "$__git_porcelain_commands" ||
881 - __git_porcelain_commands=$(__git_list_porcelain_commands)
841 + __git_all_commands=$(git --list-cmds=main,others,alias,nohelpers)
842 }
843
844 # Lists all set config variables starting with the given section prefix,
@@ -896,11 +856,6 @@ __git_pretty_aliases ()
856 __git_get_config_variables "pretty"
857 }
858
899 -__git_aliases ()
900 -{
901 - __git_get_config_variables "alias"
902 -}
903 -
859 # __git_aliased_command requires 1 argument
860 __git_aliased_command ()
861 {
@@ -1500,13 +1455,6 @@ _git_grep ()
1455 __git_complete_refs
1456 }
1457
1503 -__git_all_guides=
1504 -__git_compute_all_guides ()
1505 -{
1506 - test -n "$__git_all_guides" ||
1507 - __git_all_guides=$(git --list-cmds=list-guide)
1508 -}
1509 -
1458 _git_help ()
1459 {
1460 case "$cur" in
@@ -1515,11 +1463,12 @@ _git_help ()
1463 return
1464 ;;
1465 esac
1518 - __git_compute_all_commands
1519 - __git_compute_all_guides
1520 - __gitcomp "$__git_all_commands $(__git_aliases) $__git_all_guides
1521 - gitk
1522 - "
1466 + if test -n "$GIT_TESTING_ALL_COMMAND_LIST"
1467 + then
1468 + __gitcomp "$GIT_TESTING_ALL_COMMAND_LIST $(git --list-cmds=alias,list-guide) gitk"
1469 + else
1470 + __gitcomp "$(git --list-cmds=main,nohelpers,alias,list-guide) gitk"
1471 + fi
1472 }
1473
1474 _git_init ()
@@ -3058,8 +3007,14 @@ __git_main ()
3007 --help
3008 "
3009 ;;
3061 - *) __git_compute_porcelain_commands
3062 - __gitcomp "$__git_porcelain_commands $(__git_aliases)" ;;
3010 + *)
3011 + if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
3012 + then
3013 + __gitcomp "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
3014 + else
3015 + __gitcomp "$(git --list-cmds=list-mainporcelain,others,nohelpers,alias,list-complete)"
3016 + fi
3017 + ;;
3018 esac
3019 return
3020 fi
git.c
+2
@@ -75,6 +75,8 @@ static int list_cmds(const char *spec)
75 list_all_other_cmds(&list);
76 else if (match_token(spec, len, "nohelpers"))
77 exclude_helpers_from_list(&list);
78 + else if (match_token(spec, len, "alias"))
79 + list_aliases(&list);
80 else if (len > 5 && !strncmp(spec, "list-", 5)) {
81 struct strbuf sb = STRBUF_INIT;
82
t/t9902-completion.sh
-18
@@ -1192,17 +1192,6 @@ test_expect_success '__git_pretty_aliases' '
1192 test_cmp expect actual
1193 '
1194
1195 -test_expect_success '__git_aliases' '
1196 - cat >expect <<-EOF &&
1197 - ci
1198 - co
1199 - EOF
1200 - test_config alias.ci commit &&
1201 - test_config alias.co checkout &&
1202 - __git_aliases >actual &&
1203 - test_cmp expect actual
1204 -'
1205 -
1195 test_expect_success 'basic' '
1196 run_completion "git " &&
1197 # built-in
@@ -1511,13 +1500,6 @@ test_expect_success 'sourcing the completion script clears cached commands' '
1500 verbose test -z "$__git_all_commands"
1501 '
1502
1514 -test_expect_success 'sourcing the completion script clears cached porcelain commands' '
1515 - __git_compute_porcelain_commands &&
1516 - verbose test -n "$__git_porcelain_commands" &&
1517 - . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
1518 - verbose test -z "$__git_porcelain_commands"
1519 -'
1520 -
1503 test_expect_success !GETTEXT_POISON 'sourcing the completion script clears cached merge strategies' '
1504 __git_compute_merge_strategies &&
1505 verbose test -n "$__git_merge_strategies" &&