diff options
author | Junio C Hamano <gitster@pobox.com> | 2021-10-13 15:15:58 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2021-10-13 15:15:58 -0700 |
commit | 62f035aee3ff53aa9c5296d5acb4c4b683ba314d (patch) | |
tree | 8b2ff32deb4922a1468a672b68ecf2284fc09899 | |
parent | af303ee39214a04ad3c01e5924f2e8c09b5c18cb (diff) | |
parent | 06fa4db3f7e450deb0bb849b338d7a5453f0d183 (diff) | |
download | git-62f035aee3ff53aa9c5296d5acb4c4b683ba314d.tar.gz |
Merge branch 'ab/help-config-vars'
Teach "git help -c" into helping the command line completion of
configuration variables.
* ab/help-config-vars:
help: move column config discovery to help.c library
help / completion: make "git help" do the hard work
help tests: test --config-for-completion option & output
help: simplify by moving to OPT_CMDMODE()
help: correct logic error in combining --all and --guides
help: correct logic error in combining --all and --config
help tests: add test for --config output
help: correct usage & behavior of "git help --guides"
help: correct the usage string in -h and documentation
-rw-r--r-- | Documentation/git-help.txt | 9 | ||||
-rw-r--r-- | builtin/help.c | 131 | ||||
-rw-r--r-- | contrib/completion/git-completion.bash | 21 | ||||
-rw-r--r-- | help.c | 16 | ||||
-rw-r--r-- | help.h | 2 | ||||
-rw-r--r-- | parse-options.h | 6 | ||||
-rwxr-xr-x | t/t0012-help.sh | 49 |
7 files changed, 166 insertions, 68 deletions
diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt index 44fe8860b3..96d5f598b4 100644 --- a/Documentation/git-help.txt +++ b/Documentation/git-help.txt @@ -8,8 +8,10 @@ git-help - Display help information about Git SYNOPSIS -------- [verse] -'git help' [-a|--all [--[no-]verbose]] [-g|--guides] - [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE] +'git help' [-a|--all [--[no-]verbose]] + [[-i|--info] [-m|--man] [-w|--web]] [COMMAND|GUIDE] +'git help' [-g|--guides] +'git help' [-c|--config] DESCRIPTION ----------- @@ -58,8 +60,7 @@ OPTIONS -g:: --guides:: - Prints a list of the Git concept guides on the standard output. This - option overrides any given command or guide name. + Prints a list of the Git concept guides on the standard output. -i:: --info:: diff --git a/builtin/help.c b/builtin/help.c index 7731659765..75cd2fb407 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -7,7 +7,6 @@ #include "exec-cmd.h" #include "parse-options.h" #include "run-command.h" -#include "column.h" #include "config-list.h" #include "help.h" #include "alias.h" @@ -34,32 +33,52 @@ enum help_format { HELP_FORMAT_WEB }; -static const char *html_path; +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 int show_all = 0; -static int show_guides = 0; -static int show_config; +static const char *html_path; static int verbose = 1; -static unsigned int colopts; static enum help_format help_format = HELP_FORMAT_NONE; static int exclude_guides; static struct option builtin_help_options[] = { - OPT_BOOL('a', "all", &show_all, N_("print all available commands")), + OPT_CMDMODE('a', "all", &cmd_mode, N_("print all available commands"), + HELP_ACTION_ALL), OPT_HIDDEN_BOOL(0, "exclude-guides", &exclude_guides, N_("exclude guides")), - OPT_BOOL('g', "guides", &show_guides, N_("print list of useful guides")), - OPT_BOOL('c', "config", &show_config, N_("print all configuration variable names")), - OPT_SET_INT_F(0, "config-for-completion", &show_config, "", 2, PARSE_OPT_HIDDEN), OPT_SET_INT('m', "man", &help_format, N_("show man page"), HELP_FORMAT_MAN), OPT_SET_INT('w', "web", &help_format, N_("show manual in web browser"), 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_CMDMODE('g', "guides", &cmd_mode, N_("print list of useful guides"), + HELP_ACTION_GUIDES), + OPT_CMDMODE('c', "config", &cmd_mode, N_("print all configuration variable names"), + 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(), }; static const char * const builtin_help_usage[] = { - N_("git help [--all] [--guides] [--man | --web | --info] [<command>]"), + N_("git help [-a|--all] [--[no-]verbose]]\n" + " [[-i|--info] [-m|--man] [-w|--web]] [<command>]"), + N_("git help [-g|--guides]"), + N_("git help [-c|--config]"), NULL }; @@ -70,7 +89,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 }, @@ -88,6 +107,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++) { @@ -118,34 +139,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) @@ -349,8 +382,6 @@ static int add_man_viewer_info(const char *var, const char *value) static int git_help_config(const char *var, const char *value, void *cb) { - if (starts_with(var, "column.")) - return git_column_config(var, value, "help", &colopts); if (!strcmp(var, "help.format")) { if (!value) return config_error_nonbool(var); @@ -544,6 +575,13 @@ static const char *check_git_cmd(const char* cmd) return cmd; } +static void no_extra_argc(int argc) +{ + if (argc) + usage_msg_opt(_("this option doesn't take any other arguments"), + builtin_help_usage, builtin_help_options); +} + int cmd_help(int argc, const char **argv, const char *prefix) { int nongit; @@ -554,8 +592,8 @@ int cmd_help(int argc, const char **argv, const char *prefix) builtin_help_usage, 0); parsed_help_format = help_format; - if (show_all) { - git_config(git_help_config, NULL); + switch (cmd_mode) { + case HELP_ACTION_ALL: if (verbose) { setup_pager(); list_all_cmds_help(); @@ -563,30 +601,27 @@ int cmd_help(int argc, const char **argv, const char *prefix) } printf(_("usage: %s%s"), _(git_usage_string), "\n\n"); load_command_list("git-", &main_cmds, &other_cmds); - list_commands(colopts, &main_cmds, &other_cmds); - } - - if (show_config) { - int for_human = show_config == 1; - - if (!for_human) { - list_config_help(for_human); - return 0; - } - setup_pager(); - list_config_help(for_human); - printf("\n%s\n", _("'git help config' for more information")); - return 0; - } - - if (show_guides) + list_commands(&main_cmds, &other_cmds); + printf("%s\n", _(git_more_info_string)); + break; + case HELP_ACTION_GUIDES: + no_extra_argc(argc); list_guides_help(); - - if (show_all || show_guides) { printf("%s\n", _(git_more_info_string)); - /* - * We're done. Ignore any remaining args - */ + return 0; + case HELP_ACTION_CONFIG_FOR_COMPLETION: + 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(SHOW_CONFIG_HUMAN); + printf("\n%s\n", _("'git help config' for more information")); return 0; } diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 8108eda1e8..b9f6370193 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -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 } @@ -293,9 +293,21 @@ void load_command_list(const char *prefix, exclude_cmds(other_cmds, main_cmds); } -void list_commands(unsigned int colopts, - struct cmdnames *main_cmds, struct cmdnames *other_cmds) +static int get_colopts(const char *var, const char *value, void *data) { + unsigned int *colopts = data; + + if (starts_with(var, "column.")) + return git_column_config(var, value, "help", colopts); + + return 0; +} + +void list_commands(struct cmdnames *main_cmds, struct cmdnames *other_cmds) +{ + unsigned int colopts = 0; + git_config(get_colopts, &colopts); + if (main_cmds->cnt) { const char *exec_path = git_exec_path(); printf_ln(_("available git commands in '%s'"), exec_path); @@ -37,7 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len); /* Here we require that excludes is a sorted list. */ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes); int is_in_cmdlist(struct cmdnames *cmds, const char *name); -void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds); +void list_commands(struct cmdnames *main_cmds, struct cmdnames *other_cmds); void get_version_info(struct strbuf *buf, int show_build_options); /* diff --git a/parse-options.h b/parse-options.h index 39d9088254..13405472ee 100644 --- a/parse-options.h +++ b/parse-options.h @@ -166,8 +166,10 @@ struct option { #define OPT_BOOL(s, l, v, h) OPT_BOOL_F(s, l, v, h, 0) #define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \ (h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1} -#define OPT_CMDMODE(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, \ - (h), PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) } +#define OPT_CMDMODE_F(s, l, v, h, i, f) { OPTION_SET_INT, (s), (l), (v), NULL, \ + (h), PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG | (f), NULL, (i) } +#define OPT_CMDMODE(s, l, v, h, i) OPT_CMDMODE_F(s, l, v, h, i, 0) + #define OPT_INTEGER(s, l, v, h) OPT_INTEGER_F(s, l, v, h, 0) #define OPT_MAGNITUDE(s, l, v, h) { OPTION_MAGNITUDE, (s), (l), (v), \ N_("n"), (h), PARSE_OPT_NONEG } diff --git a/t/t0012-help.sh b/t/t0012-help.sh index 913f34c8e9..91b68c74a1 100755 --- a/t/t0012-help.sh +++ b/t/t0012-help.sh @@ -34,6 +34,18 @@ test_expect_success 'basic help commands' ' git help -a >/dev/null ' +test_expect_success 'invalid usage' ' + test_expect_code 129 git help -g add && + test_expect_code 129 git help -a -c && + + test_expect_code 129 git help -g add && + test_expect_code 129 git help -a -g && + + test_expect_code 129 git help -g -c && + 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" ' configure_help && git help status && @@ -89,6 +101,43 @@ test_expect_success 'git help succeeds without git.html' ' test_cmp expect test-browser.log ' +test_expect_success 'git help -c' ' + git help -c >help.output && + cat >expect <<-\EOF && + + '\''git help config'\'' for more information + EOF + grep -v -E \ + -e "^[^.]+\.[^.]+$" \ + -e "^[^.]+\.[^.]+\.[^.]+$" \ + help.output >actual && + test_cmp expect actual +' + +test_expect_success 'git help --config-for-completion' ' + git help -c >human && + grep -E \ + -e "^[^.]+\.[^.]+$" \ + -e "^[^.]+\.[^.]+\.[^.]+$" human | + sed -e "s/\*.*//" -e "s/<.*//" | + sort -u >human.munged && + + git help --config-for-completion >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 ' |