]> git.ipfire.org Git - thirdparty/git.git/commitdiff
help / completion: make "git help" do the hard work
authorÆvar Arnfjörð Bjarmason <avarab@gmail.com>
Tue, 21 Sep 2021 22:40:38 +0000 (00:40 +0200)
committerJunio C Hamano <gitster@pobox.com>
Thu, 23 Sep 2021 17:30:43 +0000 (10:30 -0700)
The "help" builtin has been able to emit configuration variables since
e17ca926371 (completion: drop the hard coded list of config vars,
2018-05-26), but it hasn't produced exactly the format the completion
script wanted. Let's do that.

We got partway there in 2675ea1cc0f (completion: use 'sort -u' to
deduplicate config variable names, 2019-08-13) and
d9438873c4d (completion: deduplicate configuration sections,
2019-08-13), but after both we still needed some sorting,
de-duplicating and awk post-processing of the list.

We can instead simply do the relevant parsing ourselves (we were doing
most of it already), and call string_list_remove_duplicates() after
already sorting the list, so the caller doesn't need to invoke "sort
-u". The "--config-for-completion" output is the same as before after
being passed through "sort -u".

Then add a new "--config-sections-for-completion" option. Under that
output we'll emit config sections like "alias" (instead of "alias." in
the --config-for-completion output).

We need to be careful to leave the "--config-for-completion" option
compatible with users git, but are still running a shell with an older
git-completion.bash. If we e.g. changed the option name they'd see
messages about git-completion.bash being unable to find the
"--config-for-completion" option.

Such backwards compatibility isn't something we should bend over
backwards for, it's only helping users who:

 * Upgrade git
 * Are in an old shell
 * The git-completion.bash in that shell hasn't cached the old
   "--config-for-completion" output already.

But since it's easy in this case to retain compatibility, let's do it,
the older versions of git-completion.bash won't care that the input
they get doesn't change after a "sort -u".

While we're at it let's make "--config-for-completion" die if there's
anything left over in "argc", and do the same in the new
"--config-sections-for-completion" option.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/help.c
contrib/completion/git-completion.bash
t/t0012-help.sh

index 6a022d9803ef179d171adcfc7d575c3ae8e93ea5..9a255a9aee6712ad3ca104fd8ca4a237fb177925 100644 (file)
@@ -34,11 +34,18 @@ enum help_format {
        HELP_FORMAT_WEB
 };
 
+enum show_config_type {
+       SHOW_CONFIG_HUMAN,
+       SHOW_CONFIG_VARS,
+       SHOW_CONFIG_SECTIONS,
+};
+
 static enum help_action {
        HELP_ACTION_ALL = 1,
        HELP_ACTION_GUIDES,
        HELP_ACTION_CONFIG,
        HELP_ACTION_CONFIG_FOR_COMPLETION,
+       HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION,
 } cmd_mode;
 
 static const char *html_path;
@@ -63,6 +70,8 @@ static struct option builtin_help_options[] = {
                    HELP_ACTION_CONFIG),
        OPT_CMDMODE_F(0, "config-for-completion", &cmd_mode, "",
                    HELP_ACTION_CONFIG_FOR_COMPLETION, PARSE_OPT_HIDDEN),
+       OPT_CMDMODE_F(0, "config-sections-for-completion", &cmd_mode, "",
+                   HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION, PARSE_OPT_HIDDEN),
 
        OPT_END(),
 };
@@ -82,7 +91,7 @@ struct slot_expansion {
        int found;
 };
 
-static void list_config_help(int for_human)
+static void list_config_help(enum show_config_type type)
 {
        struct slot_expansion slot_expansions[] = {
                { "advice", "*", list_config_advices },
@@ -100,6 +109,8 @@ static void list_config_help(int for_human)
        const char **p;
        struct slot_expansion *e;
        struct string_list keys = STRING_LIST_INIT_DUP;
+       struct string_list keys_uniq = STRING_LIST_INIT_DUP;
+       struct string_list_item *item;
        int i;
 
        for (p = config_name_list; *p; p++) {
@@ -130,34 +141,46 @@ static void list_config_help(int for_human)
        for (i = 0; i < keys.nr; i++) {
                const char *var = keys.items[i].string;
                const char *wildcard, *tag, *cut;
+               const char *dot = NULL;
+               struct strbuf sb = STRBUF_INIT;
 
-               if (for_human) {
+               switch (type) {
+               case SHOW_CONFIG_HUMAN:
                        puts(var);
                        continue;
+               case SHOW_CONFIG_SECTIONS:
+                       dot = strchr(var, '.');
+                       break;
+               case SHOW_CONFIG_VARS:
+                       break;
                }
-
                wildcard = strchr(var, '*');
                tag = strchr(var, '<');
 
-               if (!wildcard && !tag) {
-                       puts(var);
+               if (!dot && !wildcard && !tag) {
+                       string_list_append(&keys_uniq, var);
                        continue;
                }
 
-               if (wildcard && !tag)
+               if (dot)
+                       cut = dot;
+               else if (wildcard && !tag)
                        cut = wildcard;
                else if (!wildcard && tag)
                        cut = tag;
                else
                        cut = wildcard < tag ? wildcard : tag;
 
-               /*
-                * We may produce duplicates, but that's up to
-                * git-completion.bash to handle
-                */
-               printf("%.*s\n", (int)(cut - var), var);
+               strbuf_add(&sb, var, cut - var);
+               string_list_append(&keys_uniq, sb.buf);
+               strbuf_release(&sb);
+
        }
        string_list_clear(&keys, 0);
+       string_list_remove_duplicates(&keys_uniq, 0);
+       for_each_string_list_item(item, &keys_uniq)
+               puts(item->string);
+       string_list_clear(&keys_uniq, 0);
 }
 
 static enum help_format parse_help_format(const char *format)
@@ -589,12 +612,17 @@ int cmd_help(int argc, const char **argv, const char *prefix)
                printf("%s\n", _(git_more_info_string));
                return 0;
        case HELP_ACTION_CONFIG_FOR_COMPLETION:
-               list_config_help(0);
+               no_extra_argc(argc);
+               list_config_help(SHOW_CONFIG_VARS);
+               return 0;
+       case HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION:
+               no_extra_argc(argc);
+               list_config_help(SHOW_CONFIG_SECTIONS);
                return 0;
        case HELP_ACTION_CONFIG:
                no_extra_argc(argc);
                setup_pager();
-               list_config_help(1);
+               list_config_help(SHOW_CONFIG_HUMAN);
                printf("\n%s\n", _("'git help config' for more information"));
                return 0;
        }
index 8108eda1e8614728063c67f5658bccdc0e1d8ec0..b9f637019303d22d328acc5f86a4e6bf11688c02 100644 (file)
@@ -2503,7 +2503,14 @@ __git_config_vars=
 __git_compute_config_vars ()
 {
        test -n "$__git_config_vars" ||
-       __git_config_vars="$(git help --config-for-completion | sort -u)"
+       __git_config_vars="$(git help --config-for-completion)"
+}
+
+__git_config_sections=
+__git_compute_config_sections ()
+{
+       test -n "$__git_config_sections" ||
+       __git_config_sections="$(git help --config-sections-for-completion)"
 }
 
 # Completes possible values of various configuration variables.
@@ -2717,16 +2724,8 @@ __git_complete_config_variable_name ()
                __gitcomp "$__git_config_vars" "" "$cur_" "$sfx"
                ;;
        *)
-               __git_compute_config_vars
-               __gitcomp "$(echo "$__git_config_vars" |
-                               awk -F . '{
-                                       sections[$1] = 1
-                               }
-                               END {
-                                       for (s in sections)
-                                               print s "."
-                               }
-                               ')" "" "$cur_"
+               __git_compute_config_sections
+               __gitcomp "$__git_config_sections" "" "$cur_" "."
                ;;
        esac
 }
index 25bbaf0d586bbcb7f06650872fb5c1d6c0b9250f..60d713021f91c9b2bd1784cf440d2bee8c9aeb68 100755 (executable)
@@ -42,7 +42,8 @@ test_expect_success 'invalid usage' '
        test_expect_code 129 git help -a -g &&
 
        test_expect_code 129 git help -g -c &&
-       test_expect_code 0 git help --config-for-completion add
+       test_expect_code 129 git help --config-for-completion add &&
+       test_expect_code 129 git help --config-sections-for-completion add
 '
 
 test_expect_success "works for commands and guides by default" '
@@ -106,11 +107,21 @@ test_expect_success 'git help --config-for-completion' '
             sort -u >human.munged &&
 
        git help --config-for-completion >vars &&
-       sort -u <vars >vars.new &&
-       mv vars.new vars &&
        test_cmp human.munged vars
 '
 
+test_expect_success 'git help --config-sections-for-completion' '
+       git help -c >human &&
+       grep -E \
+            -e "^[^.]+\.[^.]+$" \
+            -e "^[^.]+\.[^.]+\.[^.]+$" human |
+            sed -e "s/\..*//" |
+            sort -u >human.munged &&
+
+       git help --config-sections-for-completion >sections &&
+       test_cmp human.munged sections
+'
+
 test_expect_success 'generate builtin list' '
        git --list-cmds=builtins >builtins
 '