From 75ba897e3059da44ad0cf27d1e4d12dc03e54001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Thu, 10 May 2018 10:46:40 +0200 Subject: generate-cmds.sh: factor out synopsis extract code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it easier to reuse the same code in another place (very soon). Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index eeea4b6..31b6d88 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -1,5 +1,15 @@ #!/bin/sh +get_synopsis () { + sed -n ' + /^NAME/,/'"$1"'/H + ${ + x + s/.*'"$1"' - \(.*\)/N_("\1")/ + p + }' "Documentation/$1.txt" +} + echo "/* Automatically generated by generate-cmdlist.sh */ struct cmdname_help { char name[16]; @@ -39,12 +49,6 @@ sort | while read cmd tags do tag=$(echo "$tags" | sed "$substnum; s/[^0-9]//g") - sed -n ' - /^NAME/,/git-'"$cmd"'/H - ${ - x - s/.*git-'"$cmd"' - \(.*\)/ {"'"$cmd"'", N_("\1"), '$tag'},/ - p - }' "Documentation/git-$cmd.txt" + echo " {\"$cmd\", $(get_synopsis git-$cmd), $tag}," done echo "};" -- cgit v0.10.2-6-g49f6 From f318d7391592f153d1682d01ebaa2d35e3b6ede7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Thu, 10 May 2018 10:46:41 +0200 Subject: generate-cmds.sh: export all commands to command-list.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current generate-cmds.sh generates just enough to print "git help" output. That is, it only extracts help text for common commands. The script is now updated to extract help text for all commands and keep command classification a new file, command-list.h. This will be useful later: - "git help -a" could print a short summary of all commands instead of just the common ones. - "git" could produce a list of commands of one or more category. One of its use is to reduce another command classification embedded in git-completion.bash. The new file can be generated but is not used anywhere yet. The plan is we migrate away from common-cmds.h. Then we can kill off common-cmds.h build rules and generation code (and also delete duplicate content in command-list.h which we keep for now to not mess generate-cmds.sh up too much). PS. The new fixed column requirement on command-list.txt is technically not needed. But it helps simplify the code a bit at this stage. We could lift this restriction later if we want to. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/.gitignore b/.gitignore index 833ef3b..d4c3914 100644 --- a/.gitignore +++ b/.gitignore @@ -180,6 +180,7 @@ /gitweb/static/gitweb.js /gitweb/static/gitweb.min.* /common-cmds.h +/command-list.h *.tar.gz *.dsc *.deb diff --git a/Makefile b/Makefile index f181687..2a8913e 100644 --- a/Makefile +++ b/Makefile @@ -757,7 +757,7 @@ LIB_FILE = libgit.a XDIFF_LIB = xdiff/lib.a VCSSVN_LIB = vcs-svn/lib.a -GENERATED_H += common-cmds.h +GENERATED_H += common-cmds.h command-list.h LIB_H = $(shell $(FIND) . \ -name .git -prune -o \ @@ -1938,6 +1938,11 @@ $(BUILT_INS): git$X common-cmds.h: generate-cmdlist.sh command-list.txt common-cmds.h: $(wildcard Documentation/git-*.txt) + $(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt COMMON >$@+ && mv $@+ $@ + +command-list.h: generate-cmdlist.sh command-list.txt + +command-list.h: $(wildcard Documentation/git-*.txt) $(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@ SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\ @@ -2148,7 +2153,7 @@ else # Dependencies on header files, for platforms that do not support # the gcc -MMD option. # -# Dependencies on automatically generated headers such as common-cmds.h +# Dependencies on automatically generated headers such as common-cmds.h or command-list.h # should _not_ be included here, since they are necessary even when # building an object for the first time. @@ -2527,7 +2532,7 @@ sparse: $(SP_OBJ) style: git clang-format --style file --diff --extensions c,h -check: common-cmds.h +check: common-cmds.h command-list.h @if sparse; \ then \ echo >&2 "Use 'make sparse' instead"; \ @@ -2775,7 +2780,7 @@ clean: profile-clean coverage-clean $(RM) $(TEST_PROGRAMS) $(NO_INSTALL) $(RM) -r bin-wrappers $(dep_dirs) $(RM) -r po/build/ - $(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope* + $(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h command-list.h $(ETAGS_TARGET) tags cscope* $(RM) -r $(GIT_TARNAME) .doc-tmp-dir $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz $(RM) $(htmldocs).tar.gz $(manpages).tar.gz diff --git a/command-list.txt b/command-list.txt index a1fad28..786536a 100644 --- a/command-list.txt +++ b/command-list.txt @@ -8,8 +8,8 @@ info examine the history and state (see also: git help revisions) history grow, mark and tweak your common history remote collaborate (see also: git help workflows) -### command list (do not change this line) -# command name category [deprecated] [common] +### command list (do not change this line, also do not change alignment) +# command name category [category] [category] git-add mainporcelain worktree git-am mainporcelain git-annotate ancillaryinterrogators diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index 31b6d88..870d3b6 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -1,5 +1,27 @@ #!/bin/sh +die () { + echo "$@" >&2 + exit 1 +} + +command_list () { + sed '1,/^### command list/d;/^#/d' "$1" +} + +get_categories () { + tr ' ' '\n'| + grep -v '^$' | + sort | + uniq +} + +category_list () { + command_list "$1" | + cut -c 40- | + get_categories +} + get_synopsis () { sed -n ' /^NAME/,/'"$1"'/H @@ -10,14 +32,51 @@ get_synopsis () { }' "Documentation/$1.txt" } +define_categories () { + echo + echo "/* Command categories */" + bit=0 + category_list "$1" | + while read cat + do + echo "#define CAT_$cat (1UL << $bit)" + bit=$(($bit+1)) + done + test "$bit" -gt 32 && die "Urgh.. too many categories?" +} + +print_command_list () { + echo "static struct cmdname_help command_list[] = {" + + command_list "$1" | + while read cmd rest + do + printf " { \"$cmd\", $(get_synopsis $cmd), 0" + for cat in $(echo "$rest" | get_categories) + do + printf " | CAT_$cat" + done + echo " }," + done + echo "};" +} + echo "/* Automatically generated by generate-cmdlist.sh */ struct cmdname_help { - char name[16]; - char help[80]; - unsigned char group; + const char *name; + const char *help; + uint32_t group; }; +" +if test -z "$2" +then + define_categories "$1" + echo + print_command_list "$1" + exit 0 +fi -static const char *common_cmd_groups[] = {" +echo "static const char *common_cmd_groups[] = {" grps=grps$$.tmp match=match$$.tmp -- cgit v0.10.2-6-g49f6 From cfb22a02ab52a5e8b74139efad8e0a10bd95f149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Thu, 10 May 2018 10:46:42 +0200 Subject: help: use command-list.h for common command list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit added code generation for all_cmd_desc[] which includes almost everything we need to generate common command list. Convert help code to use that array instead and drop common_cmds[] array. The description of each common command group is removed from command-list.txt. This keeps this file format simpler. common-cmds.h will not be generated correctly after this change due to the command-list.txt format change. But it does not matter and common-cmds.h will be removed. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/Makefile b/Makefile index 2a8913e..5c58b0b 100644 --- a/Makefile +++ b/Makefile @@ -1914,9 +1914,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \ $(filter %.o,$^) $(LIBS) -help.sp help.s help.o: common-cmds.h +help.sp help.s help.o: common-cmds.h command-list.h -builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX +builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \ '-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \ '-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \ diff --git a/command-list.txt b/command-list.txt index 786536a..3bd2320 100644 --- a/command-list.txt +++ b/command-list.txt @@ -1,13 +1,3 @@ -# common commands are grouped by themes -# these groups are output by 'git help' in the order declared here. -# map each common command in the command list to one of these groups. -### common groups (do not change this line) -init start a working area (see also: git help tutorial) -worktree work on the current change (see also: git help everyday) -info examine the history and state (see also: git help revisions) -history grow, mark and tweak your common history -remote collaborate (see also: git help workflows) - ### command list (do not change this line, also do not change alignment) # command name category [category] [category] git-add mainporcelain worktree diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index 870d3b6..9eb22c4 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -6,7 +6,7 @@ die () { } command_list () { - sed '1,/^### command list/d;/^#/d' "$1" + grep -v '^#' "$1" } get_categories () { @@ -65,7 +65,7 @@ echo "/* Automatically generated by generate-cmdlist.sh */ struct cmdname_help { const char *name; const char *help; - uint32_t group; + uint32_t category; }; " if test -z "$2" diff --git a/help.c b/help.c index 60071a9..2d6a315 100644 --- a/help.c +++ b/help.c @@ -5,13 +5,114 @@ #include "run-command.h" #include "levenshtein.h" #include "help.h" -#include "common-cmds.h" +#include "command-list.h" #include "string-list.h" #include "column.h" #include "version.h" #include "refs.h" #include "parse-options.h" +struct category_description { + uint32_t category; + const char *desc; +}; +static uint32_t common_mask = + CAT_init | CAT_worktree | CAT_info | + CAT_history | CAT_remote; +static struct category_description common_categories[] = { + { CAT_init, N_("start a working area (see also: git help tutorial)") }, + { CAT_worktree, N_("work on the current change (see also: git help everyday)") }, + { CAT_info, N_("examine the history and state (see also: git help revisions)") }, + { CAT_history, N_("grow, mark and tweak your common history") }, + { CAT_remote, N_("collaborate (see also: git help workflows)") }, + { 0, NULL } +}; + +static const char *drop_prefix(const char *name) +{ + const char *new_name; + + if (skip_prefix(name, "git-", &new_name)) + return new_name; + return name; + +} + +static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask) +{ + int i, nr = 0; + struct cmdname_help *cmds; + + if (ARRAY_SIZE(command_list) == 0) + BUG("empty command_list[] is a sign of broken generate-cmdlist.sh"); + + ALLOC_ARRAY(cmds, ARRAY_SIZE(command_list) + 1); + + for (i = 0; i < ARRAY_SIZE(command_list); i++) { + const struct cmdname_help *cmd = command_list + i; + + if (!(cmd->category & mask)) + continue; + + cmds[nr] = *cmd; + cmds[nr].name = drop_prefix(cmd->name); + + nr++; + } + cmds[nr].name = NULL; + *p_cmds = cmds; +} + +static void print_command_list(const struct cmdname_help *cmds, + uint32_t mask, int longest) +{ + int i; + + for (i = 0; cmds[i].name; i++) { + if (cmds[i].category & mask) { + printf(" %s ", cmds[i].name); + mput_char(' ', longest - strlen(cmds[i].name)); + puts(_(cmds[i].help)); + } + } +} + +static int cmd_name_cmp(const void *elem1, const void *elem2) +{ + const struct cmdname_help *e1 = elem1; + const struct cmdname_help *e2 = elem2; + + return strcmp(e1->name, e2->name); +} + +static void print_cmd_by_category(const struct category_description *catdesc) +{ + struct cmdname_help *cmds; + int longest = 0; + int i, nr = 0; + uint32_t mask = 0; + + for (i = 0; catdesc[i].desc; i++) + mask |= catdesc[i].category; + + extract_cmds(&cmds, mask); + + for (i = 0; cmds[i].name; i++, nr++) { + if (longest < strlen(cmds[i].name)) + longest = strlen(cmds[i].name); + } + QSORT(cmds, nr, cmd_name_cmp); + + for (i = 0; catdesc[i].desc; i++) { + uint32_t mask = catdesc[i].category; + const char *desc = catdesc[i].desc; + + printf("\n%s\n", _(desc)); + print_command_list(cmds, mask, longest); + } + free(cmds); +} + void add_cmdname(struct cmdnames *cmds, const char *name, int len) { struct cmdname *ent; @@ -190,42 +291,10 @@ void list_commands(unsigned int colopts, } } -static int cmd_group_cmp(const void *elem1, const void *elem2) -{ - const struct cmdname_help *e1 = elem1; - const struct cmdname_help *e2 = elem2; - - if (e1->group < e2->group) - return -1; - if (e1->group > e2->group) - return 1; - return strcmp(e1->name, e2->name); -} - void list_common_cmds_help(void) { - int i, longest = 0; - int current_grp = -1; - - for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { - if (longest < strlen(common_cmds[i].name)) - longest = strlen(common_cmds[i].name); - } - - QSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp); - puts(_("These are common Git commands used in various situations:")); - - for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { - if (common_cmds[i].group != current_grp) { - printf("\n%s\n", _(common_cmd_groups[common_cmds[i].group])); - current_grp = common_cmds[i].group; - } - - printf(" %s ", common_cmds[i].name); - mput_char(' ', longest - strlen(common_cmds[i].name)); - puts(_(common_cmds[i].help)); - } + print_cmd_by_category(common_categories); } int is_in_cmdlist(struct cmdnames *c, const char *s) @@ -285,6 +354,7 @@ const char *help_unknown_cmd(const char *cmd) { int i, n, best_similarity = 0; struct cmdnames main_cmds, other_cmds; + struct cmdname_help *common_cmds; memset(&main_cmds, 0, sizeof(main_cmds)); memset(&other_cmds, 0, sizeof(other_cmds)); @@ -299,6 +369,8 @@ const char *help_unknown_cmd(const char *cmd) QSORT(main_cmds.names, main_cmds.cnt, cmdname_compare); uniq(&main_cmds); + extract_cmds(&common_cmds, common_mask); + /* This abuses cmdname->len for levenshtein distance */ for (i = 0, n = 0; i < main_cmds.cnt; i++) { int cmp = 0; /* avoid compiler stupidity */ @@ -313,10 +385,10 @@ const char *help_unknown_cmd(const char *cmd) die(_(bad_interpreter_advice), cmd, cmd); /* Does the candidate appear in common_cmds list? */ - while (n < ARRAY_SIZE(common_cmds) && + while (common_cmds[n].name && (cmp = strcmp(common_cmds[n].name, candidate)) < 0) n++; - if ((n < ARRAY_SIZE(common_cmds)) && !cmp) { + if (common_cmds[n].name && !cmp) { /* Yes, this is one of the common commands */ n++; /* use the entry from common_cmds[] */ if (starts_with(candidate, cmd)) { @@ -329,6 +401,7 @@ const char *help_unknown_cmd(const char *cmd) main_cmds.names[i]->len = levenshtein(cmd, candidate, 0, 2, 1, 3) + 1; } + FREE_AND_NULL(common_cmds); QSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare); diff --git a/t/t0012-help.sh b/t/t0012-help.sh index 487b92a..c096f33 100755 --- a/t/t0012-help.sh +++ b/t/t0012-help.sh @@ -49,6 +49,15 @@ test_expect_success "--help does not work for guides" " test_i18ncmp expect actual " +test_expect_success 'git help' ' + git help >help.output && + test_i18ngrep "^ clone " help.output && + test_i18ngrep "^ add " help.output && + test_i18ngrep "^ log " help.output && + test_i18ngrep "^ commit " help.output && + test_i18ngrep "^ fetch " help.output +' + test_expect_success 'generate builtin list' ' git --list-builtins >builtins ' -- cgit v0.10.2-6-g49f6 From 60f487ac0ef1165932211ede29ea661c79984b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Thu, 10 May 2018 10:46:43 +0200 Subject: Remove common-cmds.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the last patch, common-cmds.h is no longer used (and it was actually broken). Remove all related code. command-list.h will take its place from now on. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/.gitignore b/.gitignore index d4c3914..0836083 100644 --- a/.gitignore +++ b/.gitignore @@ -179,7 +179,6 @@ /gitweb/gitweb.cgi /gitweb/static/gitweb.js /gitweb/static/gitweb.min.* -/common-cmds.h /command-list.h *.tar.gz *.dsc diff --git a/Makefile b/Makefile index 5c58b0b..a60a78e 100644 --- a/Makefile +++ b/Makefile @@ -757,7 +757,7 @@ LIB_FILE = libgit.a XDIFF_LIB = xdiff/lib.a VCSSVN_LIB = vcs-svn/lib.a -GENERATED_H += common-cmds.h command-list.h +GENERATED_H += command-list.h LIB_H = $(shell $(FIND) . \ -name .git -prune -o \ @@ -1914,9 +1914,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \ $(filter %.o,$^) $(LIBS) -help.sp help.s help.o: common-cmds.h command-list.h +help.sp help.s help.o: command-list.h -builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX +builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \ '-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \ '-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \ @@ -1935,11 +1935,6 @@ $(BUILT_INS): git$X ln -s $< $@ 2>/dev/null || \ cp $< $@ -common-cmds.h: generate-cmdlist.sh command-list.txt - -common-cmds.h: $(wildcard Documentation/git-*.txt) - $(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt COMMON >$@+ && mv $@+ $@ - command-list.h: generate-cmdlist.sh command-list.txt command-list.h: $(wildcard Documentation/git-*.txt) @@ -2153,7 +2148,7 @@ else # Dependencies on header files, for platforms that do not support # the gcc -MMD option. # -# Dependencies on automatically generated headers such as common-cmds.h or command-list.h +# Dependencies on automatically generated headers such as command-list.h # should _not_ be included here, since they are necessary even when # building an object for the first time. @@ -2532,7 +2527,7 @@ sparse: $(SP_OBJ) style: git clang-format --style file --diff --extensions c,h -check: common-cmds.h command-list.h +check: command-list.h @if sparse; \ then \ echo >&2 "Use 'make sparse' instead"; \ @@ -2780,7 +2775,7 @@ clean: profile-clean coverage-clean $(RM) $(TEST_PROGRAMS) $(NO_INSTALL) $(RM) -r bin-wrappers $(dep_dirs) $(RM) -r po/build/ - $(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h command-list.h $(ETAGS_TARGET) tags cscope* + $(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope* $(RM) -r $(GIT_TARNAME) .doc-tmp-dir $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz $(RM) $(htmldocs).tar.gz $(manpages).tar.gz diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index 9eb22c4..3bcc1ee 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -68,46 +68,6 @@ struct cmdname_help { uint32_t category; }; " -if test -z "$2" -then - define_categories "$1" - echo - print_command_list "$1" - exit 0 -fi - -echo "static const char *common_cmd_groups[] = {" - -grps=grps$$.tmp -match=match$$.tmp -trap "rm -f '$grps' '$match'" 0 1 2 3 15 - -sed -n ' - 1,/^### common groups/b - /^### command list/q - /^#/b - /^[ ]*$/b - h;s/^[^ ][^ ]*[ ][ ]*\(.*\)/ N_("\1"),/p - g;s/^\([^ ][^ ]*\)[ ].*/\1/w '$grps' - ' "$1" -printf '};\n\n' - -n=0 -substnum= -while read grp -do - echo "^git-..*[ ]$grp" - substnum="$substnum${substnum:+;}s/[ ]$grp/$n/" - n=$(($n+1)) -done <"$grps" >"$match" - -printf 'static struct cmdname_help common_cmds[] = {\n' -grep -f "$match" "$1" | -sed 's/^git-//' | -sort | -while read cmd tags -do - tag=$(echo "$tags" | sed "$substnum; s/[^0-9]//g") - echo " {\"$cmd\", $(get_synopsis git-$cmd), $tag}," -done -echo "};" +define_categories "$1" +echo +print_command_list "$1" -- cgit v0.10.2-6-g49f6 From 0089521cacd99db8018b7a31e205dad0bf0738c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:39:57 +0200 Subject: git.c: convert --list-* to --list-cmds=* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even if these are hidden options, let's make them a bit more generic since we're introducing more listing types shortly. The code is structured to allow combining multiple listing types together because we will soon add more types the 'builtins'. 'parseopt' remains separate because it has separate (SPC) to match git-completion.bash needs and will not combine with others. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/Documentation/git.txt b/Documentation/git.txt index 4767860..2800e3d 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -163,6 +163,12 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config Do not perform optional operations that require locks. This is equivalent to setting the `GIT_OPTIONAL_LOCKS` to `0`. +--list-cmds=group[,group...]:: + List commands by group. This is an internal/experimental + option and may change or be removed in the future. Supported + groups are: builtins, parseopt (builtin commands that use + parse-options). + GIT COMMANDS ------------ diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index a757073..3556838 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -3049,7 +3049,7 @@ __git_complete_common () { __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)" + __git_cmds_with_parseopt_helper="$(__git --list-cmds=parseopt)" case " $__git_cmds_with_parseopt_helper " in *" $1 "*) diff --git a/git.c b/git.c index 3a89893..cd85355 100644 --- a/git.c +++ b/git.c @@ -38,6 +38,30 @@ static int use_pager = -1; static void list_builtins(unsigned int exclude_option, char sep); +static int match_token(const char *spec, int len, const char *token) +{ + int token_len = strlen(token); + + return len == token_len && !strncmp(spec, token, token_len); +} + +static int list_cmds(const char *spec) +{ + while (*spec) { + const char *sep = strchrnul(spec, ','); + int len = sep - spec; + + if (match_token(spec, len, "builtins")) + list_builtins(0, '\n'); + else + die(_("unsupported command listing type '%s'"), spec); + spec += len; + if (*spec == ',') + spec++; + } + return 0; +} + static void commit_pager_choice(void) { switch (use_pager) { case 0: @@ -223,12 +247,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) } (*argv)++; (*argc)--; - } else if (!strcmp(cmd, "--list-builtins")) { - list_builtins(0, '\n'); - exit(0); - } else if (!strcmp(cmd, "--list-parseopt-builtins")) { - list_builtins(NO_PARSEOPT, ' '); - exit(0); + } else if (skip_prefix(cmd, "--list-cmds=", &cmd)) { + if (!strcmp(cmd, "parseopt")) { + list_builtins(NO_PARSEOPT, ' '); + exit(0); + } else { + exit(list_cmds(cmd)); + } } else { fprintf(stderr, _("unknown option: %s\n"), cmd); usage(git_usage_string); diff --git a/t/t0012-help.sh b/t/t0012-help.sh index c096f33..3c91a90 100755 --- a/t/t0012-help.sh +++ b/t/t0012-help.sh @@ -59,7 +59,7 @@ test_expect_success 'git help' ' ' test_expect_success 'generate builtin list' ' - git --list-builtins >builtins + git --list-cmds=builtins >builtins ' while read builtin -- cgit v0.10.2-6-g49f6 From e5d7a61953c236fbc468bc1bb01383766d2cb55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:39:58 +0200 Subject: git --list-cmds: collect command list in a string_list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of printing the command directly one by one, keep them in a list and print at the end. This allows more modification before we print out (e.g. sorting, removing duplicates or even excluding some items). Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/git.c b/git.c index cd85355..376a59b 100644 --- a/git.c +++ b/git.c @@ -36,7 +36,7 @@ const char git_more_info_string[] = static int use_pager = -1; -static void list_builtins(unsigned int exclude_option, char sep); +static void list_builtins(struct string_list *list, unsigned int exclude_option); static int match_token(const char *spec, int len, const char *token) { @@ -47,18 +47,24 @@ static int match_token(const char *spec, int len, const char *token) static int list_cmds(const char *spec) { + struct string_list list = STRING_LIST_INIT_DUP; + int i; + while (*spec) { const char *sep = strchrnul(spec, ','); int len = sep - spec; if (match_token(spec, len, "builtins")) - list_builtins(0, '\n'); + list_builtins(&list, 0); else die(_("unsupported command listing type '%s'"), spec); spec += len; if (*spec == ',') spec++; } + for (i = 0; i < list.nr; i++) + puts(list.items[i].string); + string_list_clear(&list, 0); return 0; } @@ -249,7 +255,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) (*argc)--; } else if (skip_prefix(cmd, "--list-cmds=", &cmd)) { if (!strcmp(cmd, "parseopt")) { - list_builtins(NO_PARSEOPT, ' '); + struct string_list list = STRING_LIST_INIT_DUP; + int i; + + list_builtins(&list, NO_PARSEOPT); + for (i = 0; i < list.nr; i++) + printf("%s ", list.items[i].string); + string_list_clear(&list, 0); exit(0); } else { exit(list_cmds(cmd)); @@ -533,14 +545,14 @@ int is_builtin(const char *s) return !!get_builtin(s); } -static void list_builtins(unsigned int exclude_option, char sep) +static void list_builtins(struct string_list *out, unsigned int exclude_option) { int i; for (i = 0; i < ARRAY_SIZE(commands); i++) { if (exclude_option && (commands[i].option & exclude_option)) continue; - printf("%s%c", commands[i].cmd, sep); + string_list_append(out, commands[i].cmd); } } -- cgit v0.10.2-6-g49f6 From 6bb2dc0b9472a84c7d17ee93bda28a7c1c97d415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:39:59 +0200 Subject: completion: implement and use --list-cmds=main,others MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is part of the effort to break down and provide commands by category in machine-readable form. This could be helpful later on when completion script switches to use --list-cmds for selecting completable commands. It would be much easier for the user to choose to complete _all_ commands instead of the default selection by passing different values to --list-cmds in git-completino.bash. While at there, replace "git help -a" in git-completion.bash with --list-cmds since it's better suited for this task. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/Documentation/git.txt b/Documentation/git.txt index 2800e3d..c01477a 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -167,7 +167,8 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config List commands by group. This is an internal/experimental option and may change or be removed in the future. Supported groups are: builtins, parseopt (builtin commands that use - parse-options). + parse-options), main (all commands in libexec directory), + others (all other commands in `$PATH` that have git- prefix). GIT COMMANDS ------------ diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 3556838..62ca864 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -839,7 +839,7 @@ __git_commands () { then printf "%s" "${GIT_TESTING_COMMAND_COMPLETION}" else - git help -a|egrep '^ [a-zA-Z0-9]' + git --list-cmds=main,others fi } diff --git a/git.c b/git.c index 376a59b..10907f7 100644 --- a/git.c +++ b/git.c @@ -56,6 +56,10 @@ static int list_cmds(const char *spec) if (match_token(spec, len, "builtins")) list_builtins(&list, 0); + else if (match_token(spec, len, "main")) + list_all_main_cmds(&list); + else if (match_token(spec, len, "others")) + list_all_other_cmds(&list); else die(_("unsupported command listing type '%s'"), spec); spec += len; diff --git a/help.c b/help.c index 2d6a315..d5ce9df 100644 --- a/help.c +++ b/help.c @@ -297,6 +297,38 @@ void list_common_cmds_help(void) print_cmd_by_category(common_categories); } +void list_all_main_cmds(struct string_list *list) +{ + struct cmdnames main_cmds, other_cmds; + int i; + + memset(&main_cmds, 0, sizeof(main_cmds)); + memset(&other_cmds, 0, sizeof(other_cmds)); + load_command_list("git-", &main_cmds, &other_cmds); + + for (i = 0; i < main_cmds.cnt; i++) + string_list_append(list, main_cmds.names[i]->name); + + clean_cmdnames(&main_cmds); + clean_cmdnames(&other_cmds); +} + +void list_all_other_cmds(struct string_list *list) +{ + struct cmdnames main_cmds, other_cmds; + int i; + + memset(&main_cmds, 0, sizeof(main_cmds)); + memset(&other_cmds, 0, sizeof(other_cmds)); + load_command_list("git-", &main_cmds, &other_cmds); + + for (i = 0; i < other_cmds.cnt; i++) + string_list_append(list, other_cmds.names[i]->name); + + clean_cmdnames(&main_cmds); + clean_cmdnames(&other_cmds); +} + int is_in_cmdlist(struct cmdnames *c, const char *s) { int i; diff --git a/help.h b/help.h index b21d7c9..97e6c09 100644 --- a/help.h +++ b/help.h @@ -1,6 +1,8 @@ #ifndef HELP_H #define HELP_H +struct string_list; + struct cmdnames { int alloc; int cnt; @@ -17,6 +19,8 @@ static inline void mput_char(char c, unsigned int num) } extern void list_common_cmds_help(void); +extern void list_all_main_cmds(struct string_list *list); +extern void list_all_other_cmds(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, -- cgit v0.10.2-6-g49f6 From 3c7777672bf9bc9ac2ddb422633b39af4faa1682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:40:00 +0200 Subject: git: support --list-cmds=list- MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to select any group of commands by a category defined in command-list.txt. This is an internal/hidden option so we don't have to be picky about the category name or worried about exposing too much. This will be used later by git-completion.bash to retrieve certain command groups. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/Documentation/git.txt b/Documentation/git.txt index c01477a..c423810 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -168,7 +168,8 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config option and may change or be removed in the future. Supported groups are: builtins, parseopt (builtin commands that use parse-options), main (all commands in libexec directory), - others (all other commands in `$PATH` that have git- prefix). + others (all other commands in `$PATH` that have git- prefix), + list- (see categories in command-list.txt) GIT COMMANDS ------------ diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index 3bcc1ee..8d6d8b4 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -45,6 +45,21 @@ define_categories () { test "$bit" -gt 32 && die "Urgh.. too many categories?" } +define_category_names () { + echo + echo "/* Category names */" + echo "static const char *category_names[] = {" + bit=0 + category_list "$1" | + while read cat + do + echo " \"$cat\", /* (1UL << $bit) */" + bit=$(($bit+1)) + done + echo " NULL" + echo "};" +} + print_command_list () { echo "static struct cmdname_help command_list[] = {" @@ -70,4 +85,6 @@ struct cmdname_help { " define_categories "$1" echo +define_category_names "$1" +echo print_command_list "$1" diff --git a/git.c b/git.c index 10907f7..4d5b8a9 100644 --- a/git.c +++ b/git.c @@ -60,6 +60,13 @@ static int list_cmds(const char *spec) list_all_main_cmds(&list); else if (match_token(spec, len, "others")) list_all_other_cmds(&list); + else if (len > 5 && !strncmp(spec, "list-", 5)) { + struct strbuf sb = STRBUF_INIT; + + strbuf_add(&sb, spec + 5, len - 5); + list_cmds_by_category(&list, sb.buf); + strbuf_release(&sb); + } else die(_("unsupported command listing type '%s'"), spec); spec += len; diff --git a/help.c b/help.c index d5ce9df..1117f7d 100644 --- a/help.c +++ b/help.c @@ -329,6 +329,29 @@ void list_all_other_cmds(struct string_list *list) clean_cmdnames(&other_cmds); } +void list_cmds_by_category(struct string_list *list, + const char *cat) +{ + int i, n = ARRAY_SIZE(command_list); + uint32_t cat_id = 0; + + for (i = 0; category_names[i]; i++) { + if (!strcmp(cat, category_names[i])) { + cat_id = 1UL << i; + break; + } + } + if (!cat_id) + die(_("unsupported command listing type '%s'"), cat); + + for (i = 0; i < n; i++) { + struct cmdname_help *cmd = command_list + i; + + if (cmd->category & cat_id) + string_list_append(list, drop_prefix(cmd->name)); + } +} + int is_in_cmdlist(struct cmdnames *c, const char *s) { int i; diff --git a/help.h b/help.h index 97e6c09..734bba3 100644 --- a/help.h +++ b/help.h @@ -21,6 +21,8 @@ static inline void mput_char(char c, unsigned int num) extern void list_common_cmds_help(void); 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 const char *help_unknown_cmd(const char *cmd); extern void load_command_list(const char *prefix, struct cmdnames *main_cmds, -- cgit v0.10.2-6-g49f6 From 63eae83f8f301a1052cdde254b84f5da00e7b9b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:40:01 +0200 Subject: help: add "-a --verbose" to list all commands with synopsis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This lists all recognized commands [1] by category. The group order follows closely git.txt. [1] We may actually show commands that are not built (e.g. if you set NO_PERL you don't have git-instaweb but it's still listed here). I ignore the problem because on Linux a git package could be split anyway. The "git-core" package may not contain git-instaweb even if it's built because it may end up in a separate package. We can't know anyway. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt index 40d328a..a40fc38 100644 --- a/Documentation/git-help.txt +++ b/Documentation/git-help.txt @@ -8,7 +8,7 @@ git-help - Display help information about Git SYNOPSIS -------- [verse] -'git help' [-a|--all] [-g|--guide] +'git help' [-a|--all [--verbose]] [-g|--guide] [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE] DESCRIPTION @@ -42,6 +42,8 @@ OPTIONS --all:: Prints all the available commands on the standard output. This option overrides any given command or guide name. + When used with `--verbose` print description for all recognized + commands. -g:: --guides:: diff --git a/builtin/help.c b/builtin/help.c index 598867c..0e0af84 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -36,6 +36,7 @@ static const char *html_path; static int show_all = 0; static int show_guides = 0; +static int verbose; static unsigned int colopts; static enum help_format help_format = HELP_FORMAT_NONE; static int exclude_guides; @@ -48,6 +49,7 @@ static struct option builtin_help_options[] = { HELP_FORMAT_WEB), OPT_SET_INT('i', "info", &help_format, N_("show info page"), HELP_FORMAT_INFO), + OPT__VERBOSE(&verbose, N_("print command description")), OPT_END(), }; @@ -463,6 +465,11 @@ int cmd_help(int argc, const char **argv, const char *prefix) if (show_all) { git_config(git_help_config, NULL); + if (verbose) { + setup_pager(); + list_all_cmds_help(); + return 0; + } printf(_("usage: %s%s"), _(git_usage_string), "\n\n"); load_command_list("git-", &main_cmds, &other_cmds); list_commands(colopts, &main_cmds, &other_cmds); diff --git a/help.c b/help.c index 1117f7d..c7df1d2 100644 --- a/help.c +++ b/help.c @@ -27,6 +27,17 @@ static struct category_description common_categories[] = { { CAT_remote, N_("collaborate (see also: git help workflows)") }, { 0, NULL } }; +static struct category_description main_categories[] = { + { CAT_mainporcelain, N_("Main Porcelain Commands") }, + { CAT_ancillarymanipulators, N_("Ancillary Commands / Manipulators") }, + { CAT_ancillaryinterrogators, N_("Ancillary Commands / Interrogators") }, + { CAT_foreignscminterface, N_("Interacting with Others") }, + { CAT_plumbingmanipulators, N_("Low-level Commands / Manipulators") }, + { CAT_plumbinginterrogators, N_("Low-level Commands / Interrogators") }, + { CAT_synchingrepositories, N_("Low-level Commands / Synching Repositories") }, + { CAT_purehelpers, N_("Low-level Commands / Internal Helpers") }, + { 0, NULL } +}; static const char *drop_prefix(const char *name) { @@ -352,6 +363,11 @@ void list_cmds_by_category(struct string_list *list, } } +void list_all_cmds_help(void) +{ + print_cmd_by_category(main_categories); +} + int is_in_cmdlist(struct cmdnames *c, const char *s) { int i; diff --git a/help.h b/help.h index 734bba3..40917fc 100644 --- a/help.h +++ b/help.h @@ -19,6 +19,8 @@ static inline void mput_char(char c, unsigned int num) } extern void list_common_cmds_help(void); +extern void list_all_cmds_help(void); + 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, diff --git a/t/t0012-help.sh b/t/t0012-help.sh index 3c91a90..060df24 100755 --- a/t/t0012-help.sh +++ b/t/t0012-help.sh @@ -25,6 +25,15 @@ test_expect_success "setup" ' EOF ' +# make sure to exercise these code paths, the output is a bit tricky +# to verify +test_expect_success 'basic help commands' ' + git help >/dev/null && + git help -a >/dev/null && + git help -g >/dev/null && + git help -av >/dev/null +' + test_expect_success "works for commands and guides by default" ' configure_help && git help status && -- cgit v0.10.2-6-g49f6 From 1b81d8cb19d8da6d865b7fca5a095dd5fec8d209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:40:02 +0200 Subject: help: use command-list.txt for the source of guides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The help command currently hard codes the list of guides and their summary in C. Let's move this list to command-list.txt. This lets us extract summary lines from Documentation/git*.txt. This also potentially lets us list guides in git.txt, but I'll leave that for now. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 1094fe2..083c2f3 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -3,7 +3,7 @@ gitattributes(5) NAME ---- -gitattributes - defining attributes per path +gitattributes - Defining attributes per path SYNOPSIS -------- diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt index db5d47e..4d63def 100644 --- a/Documentation/gitmodules.txt +++ b/Documentation/gitmodules.txt @@ -3,7 +3,7 @@ gitmodules(5) NAME ---- -gitmodules - defining submodule properties +gitmodules - Defining submodule properties SYNOPSIS -------- diff --git a/Documentation/gitrevisions.txt b/Documentation/gitrevisions.txt index 27dec5b..1f6ccea 100644 --- a/Documentation/gitrevisions.txt +++ b/Documentation/gitrevisions.txt @@ -3,7 +3,7 @@ gitrevisions(7) NAME ---- -gitrevisions - specifying revisions and ranges for Git +gitrevisions - Specifying revisions and ranges for Git SYNOPSIS -------- diff --git a/Makefile b/Makefile index a60a78e..1efb751 100644 --- a/Makefile +++ b/Makefile @@ -1937,7 +1937,7 @@ $(BUILT_INS): git$X command-list.h: generate-cmdlist.sh command-list.txt -command-list.h: $(wildcard Documentation/git-*.txt) +command-list.h: $(wildcard Documentation/git*.txt) $(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@ SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\ diff --git a/builtin/help.c b/builtin/help.c index 0e0af84..5727fb5 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -402,38 +402,6 @@ static void show_html_page(const char *git_cmd) open_html(page_path.buf); } -static struct { - const char *name; - const char *help; -} common_guides[] = { - { "attributes", N_("Defining attributes per path") }, - { "everyday", N_("Everyday Git With 20 Commands Or So") }, - { "glossary", N_("A Git glossary") }, - { "ignore", N_("Specifies intentionally untracked files to ignore") }, - { "modules", N_("Defining submodule properties") }, - { "revisions", N_("Specifying revisions and ranges for Git") }, - { "tutorial", N_("A tutorial introduction to Git (for version 1.5.1 or newer)") }, - { "workflows", N_("An overview of recommended workflows with Git") }, -}; - -static void list_common_guides_help(void) -{ - int i, longest = 0; - - for (i = 0; i < ARRAY_SIZE(common_guides); i++) { - if (longest < strlen(common_guides[i].name)) - longest = strlen(common_guides[i].name); - } - - puts(_("The common Git guides are:\n")); - for (i = 0; i < ARRAY_SIZE(common_guides); i++) { - printf(" %s ", common_guides[i].name); - mput_char(' ', longest - strlen(common_guides[i].name)); - puts(_(common_guides[i].help)); - } - putchar('\n'); -} - static const char *check_git_cmd(const char* cmd) { char *alias; diff --git a/command-list.txt b/command-list.txt index 3bd2320..99ddc23 100644 --- a/command-list.txt +++ b/command-list.txt @@ -139,3 +139,19 @@ gitweb ancillaryinterrogators git-whatchanged ancillaryinterrogators git-worktree mainporcelain git-write-tree plumbingmanipulators +gitattributes guide +gitcli guide +gitcore-tutorial guide +gitcvs-migration guide +gitdiffcore guide +giteveryday guide +gitglossary guide +githooks guide +gitignore guide +gitmodules guide +gitnamespaces guide +gitrepository-layout guide +gitrevisions guide +gittutorial-2 guide +gittutorial guide +gitworkflows guide diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 62ca864..4e724a5 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1575,6 +1575,13 @@ _git_grep () __git_complete_refs } +__git_all_guides= +__git_compute_all_guides () +{ + test -n "$__git_all_guides" || + __git_all_guides=$(git --list-cmds=list-guide) +} + _git_help () { case "$cur" in @@ -1584,11 +1591,9 @@ _git_help () ;; esac __git_compute_all_commands - __gitcomp "$__git_all_commands $(__git_aliases) - attributes cli core-tutorial cvs-migration - diffcore everyday gitk glossary hooks ignore modules - namespaces repository-layout revisions tutorial tutorial-2 - workflows + __git_compute_all_guides + __gitcomp "$__git_all_commands $(__git_aliases) $__git_all_guides + gitk " } diff --git a/help.c b/help.c index c7df1d2..23924dd 100644 --- a/help.c +++ b/help.c @@ -39,12 +39,14 @@ static struct category_description main_categories[] = { { 0, NULL } }; -static const char *drop_prefix(const char *name) +static const char *drop_prefix(const char *name, uint32_t category) { const char *new_name; if (skip_prefix(name, "git-", &new_name)) return new_name; + if (category == CAT_guide && skip_prefix(name, "git", &new_name)) + return new_name; return name; } @@ -66,7 +68,7 @@ static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask) continue; cmds[nr] = *cmd; - cmds[nr].name = drop_prefix(cmd->name); + cmds[nr].name = drop_prefix(cmd->name, cmd->category); nr++; } @@ -358,11 +360,22 @@ void list_cmds_by_category(struct string_list *list, for (i = 0; i < n; i++) { struct cmdname_help *cmd = command_list + i; - if (cmd->category & cat_id) - string_list_append(list, drop_prefix(cmd->name)); + if (!(cmd->category & cat_id)) + continue; + string_list_append(list, drop_prefix(cmd->name, cmd->category)); } } +void list_common_guides_help(void) +{ + struct category_description catdesc[] = { + { CAT_guide, N_("The common Git guides are:") }, + { 0, NULL } + }; + print_cmd_by_category(catdesc); + putchar('\n'); +} + void list_all_cmds_help(void) { print_cmd_by_category(main_categories); diff --git a/help.h b/help.h index 40917fc..b2293e9 100644 --- a/help.h +++ b/help.h @@ -20,6 +20,7 @@ static inline void mput_char(char c, unsigned int num) extern void list_common_cmds_help(void); extern void list_all_cmds_help(void); +extern void list_common_guides_help(void); extern void list_all_main_cmds(struct string_list *list); extern void list_all_other_cmds(struct string_list *list); diff --git a/t/t0012-help.sh b/t/t0012-help.sh index 060df24..bc27df7 100755 --- a/t/t0012-help.sh +++ b/t/t0012-help.sh @@ -66,6 +66,12 @@ test_expect_success 'git help' ' test_i18ngrep "^ commit " help.output && test_i18ngrep "^ fetch " help.output ' +test_expect_success 'git help -g' ' + git help -g >help.output && + test_i18ngrep "^ attributes " help.output && + test_i18ngrep "^ everyday " help.output && + test_i18ngrep "^ tutorial " help.output +' test_expect_success 'generate builtin list' ' git --list-cmds=builtins >builtins -- cgit v0.10.2-6-g49f6 From fe902f2cefee4d4607c43efe8b5750f346199c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:40:03 +0200 Subject: command-list.txt: documentation and guide line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is intended to help anybody who needs to update command-list.txt. It gives a brief introduction of all attributes a command can take. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/command-list.txt b/command-list.txt index 99ddc23..a2f360e 100644 --- a/command-list.txt +++ b/command-list.txt @@ -1,3 +1,48 @@ +# Command classification list +# --------------------------- +# All supported commands, builtin or external, must be described in +# here. This info is used to list commands in various places. Each +# command is on one line followed by one or more attributes. +# +# The first attribute group is mandatory and indicates the command +# type. This group includes: +# +# mainporcelain +# ancillarymanipulators +# ancillaryinterrogators +# foreignscminterface +# plumbingmanipulators +# plumbinginterrogators +# synchingrepositories +# synchelpers +# purehelpers +# +# The type names are self explanatory. But if you want to see what +# command belongs to what group to get a better picture, have a look +# at "git" man page, "GIT COMMANDS" section. +# +# Commands of type mainporcelain can also optionally have one of these +# attributes: +# +# init +# worktree +# info +# history +# remote +# +# These commands are considered "common" and will show up in "git +# help" output in groups. Uncommon porcelain commands must not +# specify any of these attributes. +# +# "complete" attribute is used to mark that the command should be +# completable by git-completion.bash. Note that by default, +# mainporcelain commands are completable so you don't need this +# attribute. +# +# As part of the Git man page list, the man(5/7) guides are also +# specified here, which can only have "guide" attribute and nothing +# else. +# ### command list (do not change this line, also do not change alignment) # command name category [category] [category] git-add mainporcelain worktree -- cgit v0.10.2-6-g49f6 From 84a971310656b7f553b48ca30bcd8936c95b00c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:40:04 +0200 Subject: completion: let git provide the completable command list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of maintaining a separate list of command classification, which often could go out of date, let's centralize the information back in git. While the function in git-completion.bash implies "list porcelain commands", that's not exactly what it does. It gets all commands (aka --list-cmds=main,others) then exclude certain non-porcelain ones. We could almost recreate this list two lists list-mainporcelain and others. The non-porcelain-but-included-anyway is added by the third category list-complete. Note that the current completion script incorrectly classifies filter-branch as porcelain and t9902 tests this behavior. We keep it this way in t9902 because this test does not really care which particular command is porcelain or plumbing, they're just names. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/command-list.txt b/command-list.txt index a2f360e..dcf1907 100644 --- a/command-list.txt +++ b/command-list.txt @@ -47,12 +47,12 @@ # command name category [category] [category] git-add mainporcelain worktree git-am mainporcelain -git-annotate ancillaryinterrogators -git-apply plumbingmanipulators +git-annotate ancillaryinterrogators complete +git-apply plumbingmanipulators complete git-archimport foreignscminterface git-archive mainporcelain git-bisect mainporcelain info -git-blame ancillaryinterrogators +git-blame ancillaryinterrogators complete git-branch mainporcelain history git-bundle mainporcelain git-cat-file plumbinginterrogators @@ -62,7 +62,7 @@ git-check-mailmap purehelpers git-checkout mainporcelain history git-checkout-index plumbingmanipulators git-check-ref-format purehelpers -git-cherry ancillaryinterrogators +git-cherry ancillaryinterrogators complete git-cherry-pick mainporcelain git-citool mainporcelain git-clean mainporcelain @@ -70,7 +70,7 @@ git-clone mainporcelain init git-column purehelpers git-commit mainporcelain history git-commit-tree plumbingmanipulators -git-config ancillarymanipulators +git-config ancillarymanipulators complete git-count-objects ancillaryinterrogators git-credential purehelpers git-credential-cache purehelpers @@ -84,30 +84,30 @@ git-diff mainporcelain history git-diff-files plumbinginterrogators git-diff-index plumbinginterrogators git-diff-tree plumbinginterrogators -git-difftool ancillaryinterrogators +git-difftool ancillaryinterrogators complete git-fast-export ancillarymanipulators git-fast-import ancillarymanipulators git-fetch mainporcelain remote git-fetch-pack synchingrepositories -git-filter-branch ancillarymanipulators +git-filter-branch ancillarymanipulators complete git-fmt-merge-msg purehelpers git-for-each-ref plumbinginterrogators git-format-patch mainporcelain -git-fsck ancillaryinterrogators +git-fsck ancillaryinterrogators complete git-gc mainporcelain -git-get-tar-commit-id ancillaryinterrogators +git-get-tar-commit-id ancillaryinterrogators complete git-grep mainporcelain info git-gui mainporcelain git-hash-object plumbingmanipulators -git-help ancillaryinterrogators +git-help ancillaryinterrogators complete git-http-backend synchingrepositories git-http-fetch synchelpers git-http-push synchelpers -git-imap-send foreignscminterface +git-imap-send foreignscminterface complete git-index-pack plumbingmanipulators git-init mainporcelain init -git-instaweb ancillaryinterrogators -git-interpret-trailers purehelpers +git-instaweb ancillaryinterrogators complete +git-interpret-trailers purehelpers complete gitk mainporcelain git-log mainporcelain info git-ls-files plumbinginterrogators @@ -120,14 +120,14 @@ git-merge-base plumbinginterrogators git-merge-file plumbingmanipulators git-merge-index plumbingmanipulators git-merge-one-file purehelpers -git-mergetool ancillarymanipulators +git-mergetool ancillarymanipulators complete git-merge-tree ancillaryinterrogators git-mktag plumbingmanipulators git-mktree plumbingmanipulators git-mv mainporcelain worktree -git-name-rev plumbinginterrogators +git-name-rev plumbinginterrogators complete git-notes mainporcelain -git-p4 foreignscminterface +git-p4 foreignscminterface complete git-pack-objects plumbingmanipulators git-pack-redundant plumbinginterrogators git-pack-refs ancillarymanipulators @@ -141,32 +141,33 @@ git-quiltimport foreignscminterface git-read-tree plumbingmanipulators git-rebase mainporcelain history git-receive-pack synchelpers -git-reflog ancillarymanipulators -git-remote ancillarymanipulators -git-repack ancillarymanipulators -git-replace ancillarymanipulators -git-request-pull foreignscminterface +git-reflog ancillarymanipulators complete +git-remote ancillarymanipulators complete +git-repack ancillarymanipulators complete +git-replace ancillarymanipulators complete +git-request-pull foreignscminterface complete git-rerere ancillaryinterrogators git-reset mainporcelain worktree git-revert mainporcelain git-rev-list plumbinginterrogators git-rev-parse ancillaryinterrogators git-rm mainporcelain worktree -git-send-email foreignscminterface +git-send-email foreignscminterface complete git-send-pack synchingrepositories git-shell synchelpers git-shortlog mainporcelain git-show mainporcelain info -git-show-branch ancillaryinterrogators +git-show-branch ancillaryinterrogators complete git-show-index plumbinginterrogators git-show-ref plumbinginterrogators git-sh-i18n purehelpers git-sh-setup purehelpers git-stash mainporcelain +git-stage complete git-status mainporcelain info git-stripspace purehelpers git-submodule mainporcelain -git-svn foreignscminterface +git-svn foreignscminterface complete git-symbolic-ref plumbingmanipulators git-tag mainporcelain history git-unpack-file plumbinginterrogators @@ -177,11 +178,11 @@ git-update-server-info synchingrepositories git-upload-archive synchelpers git-upload-pack synchelpers git-var plumbinginterrogators -git-verify-commit ancillaryinterrogators +git-verify-commit ancillaryinterrogators complete git-verify-pack plumbinginterrogators git-verify-tag ancillaryinterrogators gitweb ancillaryinterrogators -git-whatchanged ancillaryinterrogators +git-whatchanged ancillaryinterrogators complete git-worktree mainporcelain git-write-tree plumbingmanipulators gitattributes guide diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 4e724a5..cd1d8e5 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -834,19 +834,33 @@ __git_complete_strategy () return 1 } +# __git_commands requires 1 argument: +# 1: the command group, either "all" or "porcelain" __git_commands () { - if test -n "${GIT_TESTING_COMMAND_COMPLETION:-}" - then - printf "%s" "${GIT_TESTING_COMMAND_COMPLETION}" - else - git --list-cmds=main,others - fi + case "$1" in + porcelain) + if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST" + then + printf "%s" "$GIT_TESTING_PORCELAIN_COMMAND_LIST" + else + git --list-cmds=list-mainporcelain,others,list-complete + fi + ;; + all) + if test -n "$GIT_TESTING_ALL_COMMAND_LIST" + then + printf "%s" "$GIT_TESTING_ALL_COMMAND_LIST" + else + git --list-cmds=main,others + fi + ;; + esac } -__git_list_all_commands () +__git_list_commands () { local i IFS=" "$'\n' - for i in $(__git_commands) + for i in $(__git_commands $1) do case $i in *--*) : helper pattern;; @@ -855,6 +869,11 @@ __git_list_all_commands () done } +__git_list_all_commands () +{ + __git_list_commands all +} + __git_all_commands= __git_compute_all_commands () { @@ -864,89 +883,7 @@ __git_compute_all_commands () __git_list_porcelain_commands () { - local i IFS=" "$'\n' - __git_compute_all_commands - for i in $__git_all_commands - do - case $i in - *--*) : helper pattern;; - applymbox) : ask gittus;; - applypatch) : ask gittus;; - archimport) : import;; - cat-file) : plumbing;; - check-attr) : plumbing;; - check-ignore) : plumbing;; - check-mailmap) : plumbing;; - check-ref-format) : plumbing;; - checkout-index) : plumbing;; - column) : internal helper;; - commit-tree) : plumbing;; - count-objects) : infrequent;; - credential) : credentials;; - credential-*) : credentials helper;; - cvsexportcommit) : export;; - cvsimport) : import;; - cvsserver) : daemon;; - daemon) : daemon;; - diff-files) : plumbing;; - diff-index) : plumbing;; - diff-tree) : plumbing;; - fast-import) : import;; - fast-export) : export;; - fsck-objects) : plumbing;; - fetch-pack) : plumbing;; - fmt-merge-msg) : plumbing;; - for-each-ref) : plumbing;; - hash-object) : plumbing;; - http-*) : transport;; - index-pack) : plumbing;; - init-db) : deprecated;; - local-fetch) : plumbing;; - ls-files) : plumbing;; - ls-remote) : plumbing;; - ls-tree) : plumbing;; - mailinfo) : plumbing;; - mailsplit) : plumbing;; - merge-*) : plumbing;; - mktree) : plumbing;; - mktag) : plumbing;; - pack-objects) : plumbing;; - pack-redundant) : plumbing;; - pack-refs) : plumbing;; - parse-remote) : plumbing;; - patch-id) : plumbing;; - prune) : plumbing;; - prune-packed) : plumbing;; - quiltimport) : import;; - read-tree) : plumbing;; - receive-pack) : plumbing;; - remote-*) : transport;; - rerere) : plumbing;; - rev-list) : plumbing;; - rev-parse) : plumbing;; - runstatus) : plumbing;; - sh-setup) : internal;; - shell) : daemon;; - show-ref) : plumbing;; - send-pack) : plumbing;; - show-index) : plumbing;; - ssh-*) : transport;; - stripspace) : plumbing;; - symbolic-ref) : plumbing;; - unpack-file) : plumbing;; - unpack-objects) : plumbing;; - update-index) : plumbing;; - update-ref) : plumbing;; - update-server-info) : daemon;; - upload-archive) : plumbing;; - upload-pack) : plumbing;; - write-tree) : plumbing;; - var) : infrequent;; - verify-pack) : infrequent;; - verify-tag) : plumbing;; - *) echo $i;; - esac - done + __git_list_commands porcelain } __git_porcelain_commands= diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 1b34caa..2f16679 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -13,7 +13,7 @@ complete () return 0 } -# Be careful when updating this list: +# Be careful when updating these lists: # # (1) The build tree may have build artifact from different branch, or # the user's $PATH may have a random executable that may begin @@ -30,7 +30,8 @@ complete () # completion for "git ", and a plumbing is excluded. "add", # "filter-branch" and "ls-files" are listed for this. -GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files' +GIT_TESTING_ALL_COMMAND_LIST='add checkout check-attr filter-branch ls-files' +GIT_TESTING_PORCELAIN_COMMAND_LIST='add checkout filter-branch' . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" -- cgit v0.10.2-6-g49f6 From d9fcc7f8715c22b315146594afa19b75b9568dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:40:05 +0200 Subject: completion: reduce completable command list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following commands are removed from the complete list: - annotate obsolete, discouraged to use - filter-branch not often used - get-tar-commit-id not often used - imap-send not often used - interpreter-trailers not for interactive use - name-rev plumbing, just use git-describe - p4 too short and probably not often used (*) - svn same category as p4 (*) - verify-commit not often used (*) to be fair, send-email command which is in the same foreignscminterface group as svn and p4 does get completion, just because it's used by git and kernel development. So maybe we should include them. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/command-list.txt b/command-list.txt index dcf1907..e505a1e 100644 --- a/command-list.txt +++ b/command-list.txt @@ -47,7 +47,7 @@ # command name category [category] [category] git-add mainporcelain worktree git-am mainporcelain -git-annotate ancillaryinterrogators complete +git-annotate ancillaryinterrogators git-apply plumbingmanipulators complete git-archimport foreignscminterface git-archive mainporcelain @@ -89,13 +89,13 @@ git-fast-export ancillarymanipulators git-fast-import ancillarymanipulators git-fetch mainporcelain remote git-fetch-pack synchingrepositories -git-filter-branch ancillarymanipulators complete +git-filter-branch ancillarymanipulators git-fmt-merge-msg purehelpers git-for-each-ref plumbinginterrogators git-format-patch mainporcelain git-fsck ancillaryinterrogators complete git-gc mainporcelain -git-get-tar-commit-id ancillaryinterrogators complete +git-get-tar-commit-id ancillaryinterrogators git-grep mainporcelain info git-gui mainporcelain git-hash-object plumbingmanipulators @@ -103,11 +103,11 @@ git-help ancillaryinterrogators complete git-http-backend synchingrepositories git-http-fetch synchelpers git-http-push synchelpers -git-imap-send foreignscminterface complete +git-imap-send foreignscminterface git-index-pack plumbingmanipulators git-init mainporcelain init git-instaweb ancillaryinterrogators complete -git-interpret-trailers purehelpers complete +git-interpret-trailers purehelpers gitk mainporcelain git-log mainporcelain info git-ls-files plumbinginterrogators @@ -125,9 +125,9 @@ git-merge-tree ancillaryinterrogators git-mktag plumbingmanipulators git-mktree plumbingmanipulators git-mv mainporcelain worktree -git-name-rev plumbinginterrogators complete +git-name-rev plumbinginterrogators git-notes mainporcelain -git-p4 foreignscminterface complete +git-p4 foreignscminterface git-pack-objects plumbingmanipulators git-pack-redundant plumbinginterrogators git-pack-refs ancillarymanipulators @@ -167,7 +167,7 @@ git-stage complete git-status mainporcelain info git-stripspace purehelpers git-submodule mainporcelain -git-svn foreignscminterface complete +git-svn foreignscminterface git-symbolic-ref plumbingmanipulators git-tag mainporcelain history git-unpack-file plumbinginterrogators @@ -178,7 +178,7 @@ git-update-server-info synchingrepositories git-upload-archive synchelpers git-upload-pack synchelpers git-var plumbinginterrogators -git-verify-commit ancillaryinterrogators complete +git-verify-commit ancillaryinterrogators git-verify-pack plumbinginterrogators git-verify-tag ancillaryinterrogators gitweb ancillaryinterrogators -- cgit v0.10.2-6-g49f6 From 65b5f9483eafea0ccdea59884da4e00e0cfeee1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:40:06 +0200 Subject: Move declaration for alias.c to alias.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/alias.c b/alias.c index bf146e5..e9726ce 100644 --- a/alias.c +++ b/alias.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "alias.h" #include "config.h" struct config_alias_data { diff --git a/alias.h b/alias.h new file mode 100644 index 0000000..fbf1d22 --- /dev/null +++ b/alias.h @@ -0,0 +1,9 @@ +#ifndef __ALIAS_H__ +#define __ALIAS_H__ + +char *alias_lookup(const char *alias); +int split_cmdline(char *cmdline, const char ***argv); +/* Takes a negative value returned by split_cmdline */ +const char *split_cmdline_strerror(int cmdline_errno); + +#endif diff --git a/builtin/help.c b/builtin/help.c index 5727fb5..6b4b3df 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -9,6 +9,7 @@ #include "run-command.h" #include "column.h" #include "help.h" +#include "alias.h" #ifndef DEFAULT_HELP_FORMAT #define DEFAULT_HELP_FORMAT "man" diff --git a/builtin/merge.c b/builtin/merge.c index 9db5a2c..e3681cd 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -34,6 +34,7 @@ #include "string-list.h" #include "packfile.h" #include "tag.h" +#include "alias.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) diff --git a/cache.h b/cache.h index bbaf5c3..111116e 100644 --- a/cache.h +++ b/cache.h @@ -1835,11 +1835,6 @@ extern int ws_blank_line(const char *line, int len, unsigned ws_rule); void overlay_tree_on_index(struct index_state *istate, const char *tree_name, const char *prefix); -char *alias_lookup(const char *alias); -int split_cmdline(char *cmdline, const char ***argv); -/* Takes a negative value returned by split_cmdline */ -const char *split_cmdline_strerror(int cmdline_errno); - /* setup.c */ struct startup_info { int have_repository; diff --git a/connect.c b/connect.c index c3a014c..ff078d2 100644 --- a/connect.c +++ b/connect.c @@ -13,6 +13,7 @@ #include "transport.h" #include "strbuf.h" #include "protocol.h" +#include "alias.h" static char *server_capabilities; static const char *parse_feature_value(const char *, const char *, int *); diff --git a/git.c b/git.c index 4d5b8a9..19f73b3 100644 --- a/git.c +++ b/git.c @@ -3,6 +3,7 @@ #include "exec_cmd.h" #include "help.h" #include "run-command.h" +#include "alias.h" #define RUN_SETUP (1<<0) #define RUN_SETUP_GENTLY (1<<1) diff --git a/pager.c b/pager.c index 92b23e6..1f4688f 100644 --- a/pager.c +++ b/pager.c @@ -2,6 +2,7 @@ #include "config.h" #include "run-command.h" #include "sigchain.h" +#include "alias.h" #ifndef DEFAULT_PAGER #define DEFAULT_PAGER "less" diff --git a/sequencer.c b/sequencer.c index 667f35e..1288a36 100644 --- a/sequencer.c +++ b/sequencer.c @@ -23,6 +23,7 @@ #include "hashmap.h" #include "notes-utils.h" #include "sigchain.h" +#include "alias.h" #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" diff --git a/shell.c b/shell.c index 234b2d4..3ce77b8 100644 --- a/shell.c +++ b/shell.c @@ -3,6 +3,7 @@ #include "exec_cmd.h" #include "strbuf.h" #include "run-command.h" +#include "alias.h" #define COMMAND_DIR "git-shell-commands" #define HELP_COMMAND COMMAND_DIR "/help" -- cgit v0.10.2-6-g49f6 From e11dca10cfb3ef1e561c3e789b346a9719f0344a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:40:07 +0200 Subject: completion: add and use --list-cmds=nohelpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/Documentation/git.txt b/Documentation/git.txt index c423810..820ab77 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -169,7 +169,8 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config groups are: builtins, parseopt (builtin commands that use parse-options), main (all commands in libexec directory), others (all other commands in `$PATH` that have git- prefix), - list- (see categories in command-list.txt) + list- (see categories in command-list.txt), + nohelpers (exclude helper commands). GIT COMMANDS ------------ diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index cd1d8e5..217c8a3 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -843,7 +843,7 @@ __git_commands () { then printf "%s" "$GIT_TESTING_PORCELAIN_COMMAND_LIST" else - git --list-cmds=list-mainporcelain,others,list-complete + git --list-cmds=list-mainporcelain,others,nohelpers,list-complete fi ;; all) @@ -851,27 +851,15 @@ __git_commands () { then printf "%s" "$GIT_TESTING_ALL_COMMAND_LIST" else - git --list-cmds=main,others + git --list-cmds=main,others,nohelpers fi ;; esac } -__git_list_commands () -{ - local i IFS=" "$'\n' - for i in $(__git_commands $1) - do - case $i in - *--*) : helper pattern;; - *) echo $i;; - esac - done -} - __git_list_all_commands () { - __git_list_commands all + __git_commands all } __git_all_commands= @@ -883,7 +871,7 @@ __git_compute_all_commands () __git_list_porcelain_commands () { - __git_list_commands porcelain + __git_commands porcelain } __git_porcelain_commands= diff --git a/git.c b/git.c index 19f73b3..f6ae79f 100644 --- a/git.c +++ b/git.c @@ -39,6 +39,18 @@ static int use_pager = -1; static void list_builtins(struct string_list *list, unsigned int exclude_option); +static void exclude_helpers_from_list(struct string_list *list) +{ + int i = 0; + + while (i < list->nr) { + if (strstr(list->items[i].string, "--")) + unsorted_string_list_delete_item(list, i, 0); + else + i++; + } +} + static int match_token(const char *spec, int len, const char *token) { int token_len = strlen(token); @@ -61,6 +73,8 @@ static int list_cmds(const char *spec) list_all_main_cmds(&list); else if (match_token(spec, len, "others")) list_all_other_cmds(&list); + else if (match_token(spec, len, "nohelpers")) + exclude_helpers_from_list(&list); else if (len > 5 && !strncmp(spec, "list-", 5)) { struct strbuf sb = STRBUF_INIT; -- cgit v0.10.2-6-g49f6 From 3301d36b29467a05107340e4d9688ebf74335021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:40:08 +0200 Subject: completion: add and use --list-cmds=alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 " 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 Signed-off-by: Junio C Hamano diff --git a/Documentation/git.txt b/Documentation/git.txt index 820ab77..75f50d2 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -170,7 +170,7 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config parse-options), main (all commands in libexec directory), others (all other commands in `$PATH` that have git- prefix), list- (see categories in command-list.txt), - nohelpers (exclude helper commands). + nohelpers (exclude helper commands) and alias. GIT COMMANDS ------------ diff --git a/alias.c b/alias.c index e9726ce..a7e4e57 100644 --- a/alias.c +++ b/alias.c @@ -1,10 +1,12 @@ #include "cache.h" #include "alias.h" #include "config.h" +#include "string-list.h" struct config_alias_data { const char *alias; char *v; + struct string_list *list; }; 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) struct config_alias_data *data = d; const char *p; - if (skip_prefix(key, "alias.", &p) && !strcasecmp(p, data->alias)) - return git_config_string((const char **)&data->v, key, value); + if (!skip_prefix(key, "alias.", &p)) + return 0; + + if (data->alias) { + if (!strcasecmp(p, data->alias)) + return git_config_string((const char **)&data->v, + key, value); + } else if (data->list) { + string_list_append(data->list, p); + } return 0; } @@ -27,6 +37,13 @@ char *alias_lookup(const char *alias) return data.v; } +void list_aliases(struct string_list *list) +{ + struct config_alias_data data = { NULL, NULL, list }; + + read_early_config(config_alias_cb, &data); +} + #define SPLIT_CMDLINE_BAD_ENDING 1 #define SPLIT_CMDLINE_UNCLOSED_QUOTE 2 static const char *split_cmdline_errors[] = { diff --git a/alias.h b/alias.h index fbf1d22..79933f2 100644 --- a/alias.h +++ b/alias.h @@ -1,9 +1,12 @@ #ifndef __ALIAS_H__ #define __ALIAS_H__ +struct string_list; + char *alias_lookup(const char *alias); int split_cmdline(char *cmdline, const char ***argv); /* Takes a negative value returned by split_cmdline */ const char *split_cmdline_strerror(int cmdline_errno); +void list_aliases(struct string_list *list); #endif diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 217c8a3..98f278f 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -834,51 +834,11 @@ __git_complete_strategy () return 1 } -# __git_commands requires 1 argument: -# 1: the command group, either "all" or "porcelain" -__git_commands () { - case "$1" in - porcelain) - if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST" - then - printf "%s" "$GIT_TESTING_PORCELAIN_COMMAND_LIST" - else - git --list-cmds=list-mainporcelain,others,nohelpers,list-complete - fi - ;; - all) - if test -n "$GIT_TESTING_ALL_COMMAND_LIST" - then - printf "%s" "$GIT_TESTING_ALL_COMMAND_LIST" - else - git --list-cmds=main,others,nohelpers - fi - ;; - esac -} - -__git_list_all_commands () -{ - __git_commands all -} - __git_all_commands= __git_compute_all_commands () { test -n "$__git_all_commands" || - __git_all_commands=$(__git_list_all_commands) -} - -__git_list_porcelain_commands () -{ - __git_commands porcelain -} - -__git_porcelain_commands= -__git_compute_porcelain_commands () -{ - test -n "$__git_porcelain_commands" || - __git_porcelain_commands=$(__git_list_porcelain_commands) + __git_all_commands=$(git --list-cmds=main,others,alias,nohelpers) } # Lists all set config variables starting with the given section prefix, @@ -896,11 +856,6 @@ __git_pretty_aliases () __git_get_config_variables "pretty" } -__git_aliases () -{ - __git_get_config_variables "alias" -} - # __git_aliased_command requires 1 argument __git_aliased_command () { @@ -1500,13 +1455,6 @@ _git_grep () __git_complete_refs } -__git_all_guides= -__git_compute_all_guides () -{ - test -n "$__git_all_guides" || - __git_all_guides=$(git --list-cmds=list-guide) -} - _git_help () { case "$cur" in @@ -1515,11 +1463,12 @@ _git_help () return ;; esac - __git_compute_all_commands - __git_compute_all_guides - __gitcomp "$__git_all_commands $(__git_aliases) $__git_all_guides - gitk - " + if test -n "$GIT_TESTING_ALL_COMMAND_LIST" + then + __gitcomp "$GIT_TESTING_ALL_COMMAND_LIST $(git --list-cmds=alias,list-guide) gitk" + else + __gitcomp "$(git --list-cmds=main,nohelpers,alias,list-guide) gitk" + fi } _git_init () @@ -3058,8 +3007,14 @@ __git_main () --help " ;; - *) __git_compute_porcelain_commands - __gitcomp "$__git_porcelain_commands $(__git_aliases)" ;; + *) + if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST" + then + __gitcomp "$GIT_TESTING_PORCELAIN_COMMAND_LIST" + else + __gitcomp "$(git --list-cmds=list-mainporcelain,others,nohelpers,alias,list-complete)" + fi + ;; esac return fi diff --git a/git.c b/git.c index f6ae79f..63acd9e 100644 --- a/git.c +++ b/git.c @@ -75,6 +75,8 @@ static int list_cmds(const char *spec) list_all_other_cmds(&list); else if (match_token(spec, len, "nohelpers")) exclude_helpers_from_list(&list); + else if (match_token(spec, len, "alias")) + list_aliases(&list); else if (len > 5 && !strncmp(spec, "list-", 5)) { struct strbuf sb = STRBUF_INIT; diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 2f16679..5863b1a 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -1192,17 +1192,6 @@ test_expect_success '__git_pretty_aliases' ' test_cmp expect actual ' -test_expect_success '__git_aliases' ' - cat >expect <<-EOF && - ci - co - EOF - test_config alias.ci commit && - test_config alias.co checkout && - __git_aliases >actual && - test_cmp expect actual -' - test_expect_success 'basic' ' run_completion "git " && # built-in @@ -1511,13 +1500,6 @@ test_expect_success 'sourcing the completion script clears cached commands' ' verbose test -z "$__git_all_commands" ' -test_expect_success 'sourcing the completion script clears cached porcelain commands' ' - __git_compute_porcelain_commands && - verbose test -n "$__git_porcelain_commands" && - . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" && - verbose test -z "$__git_porcelain_commands" -' - test_expect_success !GETTEXT_POISON 'sourcing the completion script clears cached merge strategies' ' __git_compute_merge_strategies && verbose test -n "$__git_merge_strategies" && -- cgit v0.10.2-6-g49f6 From 6532f3740b1c228c0a2a03a4126f4f7e4f2d73e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 20 May 2018 20:40:09 +0200 Subject: completion: allow to customize the completable command list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 a new config variable. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano diff --git a/Documentation/config.txt b/Documentation/config.txt index 2659153..9e81dcf 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1343,6 +1343,14 @@ credential..*:: credentialCache.ignoreSIGHUP:: Tell git-credential-cache--daemon to ignore SIGHUP, instead of quitting. +completion.commands:: + This is only used by git-completion.bash to add or remove + commands from the list of completed commands. Normally only + porcelain commands and a few select others are completed. You + can add more commands, separated by space, in this + variable. Prefixing the command with '-' will remove it from + the existing list. + include::diff-config.txt[] difftool..path:: diff --git a/Documentation/git.txt b/Documentation/git.txt index 75f50d2..6f7eddf 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -170,7 +170,8 @@ foo.bar= ...`) sets `foo.bar` to the empty string which `git config parse-options), main (all commands in libexec directory), others (all other commands in `$PATH` that have git- prefix), list- (see categories in command-list.txt), - nohelpers (exclude helper commands) and alias. + nohelpers (exclude helper commands), alias and config + (retrieve command list from config variable completion.commands) GIT COMMANDS ------------ diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 98f278f..e5b2ccb 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -3012,7 +3012,7 @@ __git_main () then __gitcomp "$GIT_TESTING_PORCELAIN_COMMAND_LIST" else - __gitcomp "$(git --list-cmds=list-mainporcelain,others,nohelpers,alias,list-complete)" + __gitcomp "$(git --list-cmds=list-mainporcelain,others,nohelpers,alias,list-complete,config)" fi ;; esac diff --git a/git.c b/git.c index 63acd9e..447dac0 100644 --- a/git.c +++ b/git.c @@ -77,6 +77,8 @@ static int list_cmds(const char *spec) exclude_helpers_from_list(&list); else if (match_token(spec, len, "alias")) list_aliases(&list); + else if (match_token(spec, len, "config")) + 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 23924dd..abf8720 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 b2293e9..3b38292 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, -- cgit v0.10.2-6-g49f6