Skip to content

Commit 62f035a

Browse files
committed
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
2 parents af303ee + 06fa4db commit 62f035a

File tree

7 files changed

+166
-68
lines changed

7 files changed

+166
-68
lines changed

Documentation/git-help.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ git-help - Display help information about Git
88
SYNOPSIS
99
--------
1010
[verse]
11-
'git help' [-a|--all [--[no-]verbose]] [-g|--guides]
12-
[-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]
11+
'git help' [-a|--all [--[no-]verbose]]
12+
[[-i|--info] [-m|--man] [-w|--web]] [COMMAND|GUIDE]
13+
'git help' [-g|--guides]
14+
'git help' [-c|--config]
1315

1416
DESCRIPTION
1517
-----------
@@ -58,8 +60,7 @@ OPTIONS
5860

5961
-g::
6062
--guides::
61-
Prints a list of the Git concept guides on the standard output. This
62-
option overrides any given command or guide name.
63+
Prints a list of the Git concept guides on the standard output.
6364

6465
-i::
6566
--info::

builtin/help.c

Lines changed: 83 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include "exec-cmd.h"
88
#include "parse-options.h"
99
#include "run-command.h"
10-
#include "column.h"
1110
#include "config-list.h"
1211
#include "help.h"
1312
#include "alias.h"
@@ -34,32 +33,52 @@ enum help_format {
3433
HELP_FORMAT_WEB
3534
};
3635

37-
static const char *html_path;
36+
enum show_config_type {
37+
SHOW_CONFIG_HUMAN,
38+
SHOW_CONFIG_VARS,
39+
SHOW_CONFIG_SECTIONS,
40+
};
41+
42+
static enum help_action {
43+
HELP_ACTION_ALL = 1,
44+
HELP_ACTION_GUIDES,
45+
HELP_ACTION_CONFIG,
46+
HELP_ACTION_CONFIG_FOR_COMPLETION,
47+
HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION,
48+
} cmd_mode;
3849

39-
static int show_all = 0;
40-
static int show_guides = 0;
41-
static int show_config;
50+
static const char *html_path;
4251
static int verbose = 1;
43-
static unsigned int colopts;
4452
static enum help_format help_format = HELP_FORMAT_NONE;
4553
static int exclude_guides;
4654
static struct option builtin_help_options[] = {
47-
OPT_BOOL('a', "all", &show_all, N_("print all available commands")),
55+
OPT_CMDMODE('a', "all", &cmd_mode, N_("print all available commands"),
56+
HELP_ACTION_ALL),
4857
OPT_HIDDEN_BOOL(0, "exclude-guides", &exclude_guides, N_("exclude guides")),
49-
OPT_BOOL('g', "guides", &show_guides, N_("print list of useful guides")),
50-
OPT_BOOL('c', "config", &show_config, N_("print all configuration variable names")),
51-
OPT_SET_INT_F(0, "config-for-completion", &show_config, "", 2, PARSE_OPT_HIDDEN),
5258
OPT_SET_INT('m', "man", &help_format, N_("show man page"), HELP_FORMAT_MAN),
5359
OPT_SET_INT('w', "web", &help_format, N_("show manual in web browser"),
5460
HELP_FORMAT_WEB),
5561
OPT_SET_INT('i', "info", &help_format, N_("show info page"),
5662
HELP_FORMAT_INFO),
5763
OPT__VERBOSE(&verbose, N_("print command description")),
64+
65+
OPT_CMDMODE('g', "guides", &cmd_mode, N_("print list of useful guides"),
66+
HELP_ACTION_GUIDES),
67+
OPT_CMDMODE('c', "config", &cmd_mode, N_("print all configuration variable names"),
68+
HELP_ACTION_CONFIG),
69+
OPT_CMDMODE_F(0, "config-for-completion", &cmd_mode, "",
70+
HELP_ACTION_CONFIG_FOR_COMPLETION, PARSE_OPT_HIDDEN),
71+
OPT_CMDMODE_F(0, "config-sections-for-completion", &cmd_mode, "",
72+
HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION, PARSE_OPT_HIDDEN),
73+
5874
OPT_END(),
5975
};
6076

6177
static const char * const builtin_help_usage[] = {
62-
N_("git help [--all] [--guides] [--man | --web | --info] [<command>]"),
78+
N_("git help [-a|--all] [--[no-]verbose]]\n"
79+
" [[-i|--info] [-m|--man] [-w|--web]] [<command>]"),
80+
N_("git help [-g|--guides]"),
81+
N_("git help [-c|--config]"),
6382
NULL
6483
};
6584

@@ -70,7 +89,7 @@ struct slot_expansion {
7089
int found;
7190
};
7291

73-
static void list_config_help(int for_human)
92+
static void list_config_help(enum show_config_type type)
7493
{
7594
struct slot_expansion slot_expansions[] = {
7695
{ "advice", "*", list_config_advices },
@@ -88,6 +107,8 @@ static void list_config_help(int for_human)
88107
const char **p;
89108
struct slot_expansion *e;
90109
struct string_list keys = STRING_LIST_INIT_DUP;
110+
struct string_list keys_uniq = STRING_LIST_INIT_DUP;
111+
struct string_list_item *item;
91112
int i;
92113

93114
for (p = config_name_list; *p; p++) {
@@ -118,34 +139,46 @@ static void list_config_help(int for_human)
118139
for (i = 0; i < keys.nr; i++) {
119140
const char *var = keys.items[i].string;
120141
const char *wildcard, *tag, *cut;
142+
const char *dot = NULL;
143+
struct strbuf sb = STRBUF_INIT;
121144

122-
if (for_human) {
145+
switch (type) {
146+
case SHOW_CONFIG_HUMAN:
123147
puts(var);
124148
continue;
149+
case SHOW_CONFIG_SECTIONS:
150+
dot = strchr(var, '.');
151+
break;
152+
case SHOW_CONFIG_VARS:
153+
break;
125154
}
126-
127155
wildcard = strchr(var, '*');
128156
tag = strchr(var, '<');
129157

130-
if (!wildcard && !tag) {
131-
puts(var);
158+
if (!dot && !wildcard && !tag) {
159+
string_list_append(&keys_uniq, var);
132160
continue;
133161
}
134162

135-
if (wildcard && !tag)
163+
if (dot)
164+
cut = dot;
165+
else if (wildcard && !tag)
136166
cut = wildcard;
137167
else if (!wildcard && tag)
138168
cut = tag;
139169
else
140170
cut = wildcard < tag ? wildcard : tag;
141171

142-
/*
143-
* We may produce duplicates, but that's up to
144-
* git-completion.bash to handle
145-
*/
146-
printf("%.*s\n", (int)(cut - var), var);
172+
strbuf_add(&sb, var, cut - var);
173+
string_list_append(&keys_uniq, sb.buf);
174+
strbuf_release(&sb);
175+
147176
}
148177
string_list_clear(&keys, 0);
178+
string_list_remove_duplicates(&keys_uniq, 0);
179+
for_each_string_list_item(item, &keys_uniq)
180+
puts(item->string);
181+
string_list_clear(&keys_uniq, 0);
149182
}
150183

151184
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)
349382

350383
static int git_help_config(const char *var, const char *value, void *cb)
351384
{
352-
if (starts_with(var, "column."))
353-
return git_column_config(var, value, "help", &colopts);
354385
if (!strcmp(var, "help.format")) {
355386
if (!value)
356387
return config_error_nonbool(var);
@@ -544,6 +575,13 @@ static const char *check_git_cmd(const char* cmd)
544575
return cmd;
545576
}
546577

578+
static void no_extra_argc(int argc)
579+
{
580+
if (argc)
581+
usage_msg_opt(_("this option doesn't take any other arguments"),
582+
builtin_help_usage, builtin_help_options);
583+
}
584+
547585
int cmd_help(int argc, const char **argv, const char *prefix)
548586
{
549587
int nongit;
@@ -554,39 +592,36 @@ int cmd_help(int argc, const char **argv, const char *prefix)
554592
builtin_help_usage, 0);
555593
parsed_help_format = help_format;
556594

557-
if (show_all) {
558-
git_config(git_help_config, NULL);
595+
switch (cmd_mode) {
596+
case HELP_ACTION_ALL:
559597
if (verbose) {
560598
setup_pager();
561599
list_all_cmds_help();
562600
return 0;
563601
}
564602
printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
565603
load_command_list("git-", &main_cmds, &other_cmds);
566-
list_commands(colopts, &main_cmds, &other_cmds);
567-
}
568-
569-
if (show_config) {
570-
int for_human = show_config == 1;
571-
572-
if (!for_human) {
573-
list_config_help(for_human);
574-
return 0;
575-
}
576-
setup_pager();
577-
list_config_help(for_human);
578-
printf("\n%s\n", _("'git help config' for more information"));
579-
return 0;
580-
}
581-
582-
if (show_guides)
604+
list_commands(&main_cmds, &other_cmds);
605+
printf("%s\n", _(git_more_info_string));
606+
break;
607+
case HELP_ACTION_GUIDES:
608+
no_extra_argc(argc);
583609
list_guides_help();
584-
585-
if (show_all || show_guides) {
586610
printf("%s\n", _(git_more_info_string));
587-
/*
588-
* We're done. Ignore any remaining args
589-
*/
611+
return 0;
612+
case HELP_ACTION_CONFIG_FOR_COMPLETION:
613+
no_extra_argc(argc);
614+
list_config_help(SHOW_CONFIG_VARS);
615+
return 0;
616+
case HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION:
617+
no_extra_argc(argc);
618+
list_config_help(SHOW_CONFIG_SECTIONS);
619+
return 0;
620+
case HELP_ACTION_CONFIG:
621+
no_extra_argc(argc);
622+
setup_pager();
623+
list_config_help(SHOW_CONFIG_HUMAN);
624+
printf("\n%s\n", _("'git help config' for more information"));
590625
return 0;
591626
}
592627

contrib/completion/git-completion.bash

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2503,7 +2503,14 @@ __git_config_vars=
25032503
__git_compute_config_vars ()
25042504
{
25052505
test -n "$__git_config_vars" ||
2506-
__git_config_vars="$(git help --config-for-completion | sort -u)"
2506+
__git_config_vars="$(git help --config-for-completion)"
2507+
}
2508+
2509+
__git_config_sections=
2510+
__git_compute_config_sections ()
2511+
{
2512+
test -n "$__git_config_sections" ||
2513+
__git_config_sections="$(git help --config-sections-for-completion)"
25072514
}
25082515

25092516
# Completes possible values of various configuration variables.
@@ -2717,16 +2724,8 @@ __git_complete_config_variable_name ()
27172724
__gitcomp "$__git_config_vars" "" "$cur_" "$sfx"
27182725
;;
27192726
*)
2720-
__git_compute_config_vars
2721-
__gitcomp "$(echo "$__git_config_vars" |
2722-
awk -F . '{
2723-
sections[$1] = 1
2724-
}
2725-
END {
2726-
for (s in sections)
2727-
print s "."
2728-
}
2729-
')" "" "$cur_"
2727+
__git_compute_config_sections
2728+
__gitcomp "$__git_config_sections" "" "$cur_" "."
27302729
;;
27312730
esac
27322731
}

help.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,21 @@ void load_command_list(const char *prefix,
293293
exclude_cmds(other_cmds, main_cmds);
294294
}
295295

296-
void list_commands(unsigned int colopts,
297-
struct cmdnames *main_cmds, struct cmdnames *other_cmds)
296+
static int get_colopts(const char *var, const char *value, void *data)
298297
{
298+
unsigned int *colopts = data;
299+
300+
if (starts_with(var, "column."))
301+
return git_column_config(var, value, "help", colopts);
302+
303+
return 0;
304+
}
305+
306+
void list_commands(struct cmdnames *main_cmds, struct cmdnames *other_cmds)
307+
{
308+
unsigned int colopts = 0;
309+
git_config(get_colopts, &colopts);
310+
299311
if (main_cmds->cnt) {
300312
const char *exec_path = git_exec_path();
301313
printf_ln(_("available git commands in '%s'"), exec_path);

help.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);
3737
/* Here we require that excludes is a sorted list. */
3838
void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
3939
int is_in_cmdlist(struct cmdnames *cmds, const char *name);
40-
void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);
40+
void list_commands(struct cmdnames *main_cmds, struct cmdnames *other_cmds);
4141
void get_version_info(struct strbuf *buf, int show_build_options);
4242

4343
/*

parse-options.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,10 @@ struct option {
166166
#define OPT_BOOL(s, l, v, h) OPT_BOOL_F(s, l, v, h, 0)
167167
#define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \
168168
(h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1}
169-
#define OPT_CMDMODE(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, \
170-
(h), PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) }
169+
#define OPT_CMDMODE_F(s, l, v, h, i, f) { OPTION_SET_INT, (s), (l), (v), NULL, \
170+
(h), PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG | (f), NULL, (i) }
171+
#define OPT_CMDMODE(s, l, v, h, i) OPT_CMDMODE_F(s, l, v, h, i, 0)
172+
171173
#define OPT_INTEGER(s, l, v, h) OPT_INTEGER_F(s, l, v, h, 0)
172174
#define OPT_MAGNITUDE(s, l, v, h) { OPTION_MAGNITUDE, (s), (l), (v), \
173175
N_("n"), (h), PARSE_OPT_NONEG }

t/t0012-help.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ test_expect_success 'basic help commands' '
3434
git help -a >/dev/null
3535
'
3636

37+
test_expect_success 'invalid usage' '
38+
test_expect_code 129 git help -g add &&
39+
test_expect_code 129 git help -a -c &&
40+
41+
test_expect_code 129 git help -g add &&
42+
test_expect_code 129 git help -a -g &&
43+
44+
test_expect_code 129 git help -g -c &&
45+
test_expect_code 129 git help --config-for-completion add &&
46+
test_expect_code 129 git help --config-sections-for-completion add
47+
'
48+
3749
test_expect_success "works for commands and guides by default" '
3850
configure_help &&
3951
git help status &&
@@ -89,6 +101,43 @@ test_expect_success 'git help succeeds without git.html' '
89101
test_cmp expect test-browser.log
90102
'
91103

104+
test_expect_success 'git help -c' '
105+
git help -c >help.output &&
106+
cat >expect <<-\EOF &&
107+
108+
'\''git help config'\'' for more information
109+
EOF
110+
grep -v -E \
111+
-e "^[^.]+\.[^.]+$" \
112+
-e "^[^.]+\.[^.]+\.[^.]+$" \
113+
help.output >actual &&
114+
test_cmp expect actual
115+
'
116+
117+
test_expect_success 'git help --config-for-completion' '
118+
git help -c >human &&
119+
grep -E \
120+
-e "^[^.]+\.[^.]+$" \
121+
-e "^[^.]+\.[^.]+\.[^.]+$" human |
122+
sed -e "s/\*.*//" -e "s/<.*//" |
123+
sort -u >human.munged &&
124+
125+
git help --config-for-completion >vars &&
126+
test_cmp human.munged vars
127+
'
128+
129+
test_expect_success 'git help --config-sections-for-completion' '
130+
git help -c >human &&
131+
grep -E \
132+
-e "^[^.]+\.[^.]+$" \
133+
-e "^[^.]+\.[^.]+\.[^.]+$" human |
134+
sed -e "s/\..*//" |
135+
sort -u >human.munged &&
136+
137+
git help --config-sections-for-completion >sections &&
138+
test_cmp human.munged sections
139+
'
140+
92141
test_expect_success 'generate builtin list' '
93142
git --list-cmds=builtins >builtins
94143
'

0 commit comments

Comments
 (0)