help: use command-list.h for common command list
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 <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
May 10, 2018 at 10:46 UTC
cfb22a02ab52a5e8b74139efad8e0a10bd95f149
5 files changed
+122
-50
Makefile
+2
-2
@@ -1914,9 +1914,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
1914
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
1915
$(filter %.o,$^) $(LIBS)
1916
1917
-help.sp help.s help.o: common-cmds.h
1917
+help.sp help.s help.o: common-cmds.h command-list.h
1918
1919
-builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX
1919
+builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX
1920
builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
1921
'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
1922
'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
command-list.txt
-10
@@ -1,13 +1,3 @@
1
-# common commands are grouped by themes
2
-# these groups are output by 'git help' in the order declared here.
3
-# map each common command in the command list to one of these groups.
4
-### common groups (do not change this line)
5
-init start a working area (see also: git help tutorial)
6
-worktree work on the current change (see also: git help everyday)
7
-info examine the history and state (see also: git help revisions)
8
-history grow, mark and tweak your common history
9
-remote collaborate (see also: git help workflows)
10
-
1
### command list (do not change this line, also do not change alignment)
2
# command name category [category] [category]
3
git-add mainporcelain worktree
generate-cmdlist.sh
+2
-2
@@ -6,7 +6,7 @@ die () {
6
}
7
8
command_list () {
9
- sed '1,/^### command list/d;/^#/d' "$1"
9
+ grep -v '^#' "$1"
10
}
11
12
get_categories () {
@@ -65,7 +65,7 @@ echo "/* Automatically generated by generate-cmdlist.sh */
65
struct cmdname_help {
66
const char *name;
67
const char *help;
68
- uint32_t group;
68
+ uint32_t category;
69
};
70
"
71
if test -z "$2"
help.c
+109
-36
@@ -5,13 +5,114 @@
5
#include "run-command.h"
6
#include "levenshtein.h"
7
#include "help.h"
8
-#include "common-cmds.h"
8
+#include "command-list.h"
9
#include "string-list.h"
10
#include "column.h"
11
#include "version.h"
12
#include "refs.h"
13
#include "parse-options.h"
14
15
+struct category_description {
16
+ uint32_t category;
17
+ const char *desc;
18
+};
19
+static uint32_t common_mask =
20
+ CAT_init | CAT_worktree | CAT_info |
21
+ CAT_history | CAT_remote;
22
+static struct category_description common_categories[] = {
23
+ { CAT_init, N_("start a working area (see also: git help tutorial)") },
24
+ { CAT_worktree, N_("work on the current change (see also: git help everyday)") },
25
+ { CAT_info, N_("examine the history and state (see also: git help revisions)") },
26
+ { CAT_history, N_("grow, mark and tweak your common history") },
27
+ { CAT_remote, N_("collaborate (see also: git help workflows)") },
28
+ { 0, NULL }
29
+};
30
+
31
+static const char *drop_prefix(const char *name)
32
+{
33
+ const char *new_name;
34
+
35
+ if (skip_prefix(name, "git-", &new_name))
36
+ return new_name;
37
+ return name;
38
+
39
+}
40
+
41
+static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)
42
+{
43
+ int i, nr = 0;
44
+ struct cmdname_help *cmds;
45
+
46
+ if (ARRAY_SIZE(command_list) == 0)
47
+ BUG("empty command_list[] is a sign of broken generate-cmdlist.sh");
48
+
49
+ ALLOC_ARRAY(cmds, ARRAY_SIZE(command_list) + 1);
50
+
51
+ for (i = 0; i < ARRAY_SIZE(command_list); i++) {
52
+ const struct cmdname_help *cmd = command_list + i;
53
+
54
+ if (!(cmd->category & mask))
55
+ continue;
56
+
57
+ cmds[nr] = *cmd;
58
+ cmds[nr].name = drop_prefix(cmd->name);
59
+
60
+ nr++;
61
+ }
62
+ cmds[nr].name = NULL;
63
+ *p_cmds = cmds;
64
+}
65
+
66
+static void print_command_list(const struct cmdname_help *cmds,
67
+ uint32_t mask, int longest)
68
+{
69
+ int i;
70
+
71
+ for (i = 0; cmds[i].name; i++) {
72
+ if (cmds[i].category & mask) {
73
+ printf(" %s ", cmds[i].name);
74
+ mput_char(' ', longest - strlen(cmds[i].name));
75
+ puts(_(cmds[i].help));
76
+ }
77
+ }
78
+}
79
+
80
+static int cmd_name_cmp(const void *elem1, const void *elem2)
81
+{
82
+ const struct cmdname_help *e1 = elem1;
83
+ const struct cmdname_help *e2 = elem2;
84
+
85
+ return strcmp(e1->name, e2->name);
86
+}
87
+
88
+static void print_cmd_by_category(const struct category_description *catdesc)
89
+{
90
+ struct cmdname_help *cmds;
91
+ int longest = 0;
92
+ int i, nr = 0;
93
+ uint32_t mask = 0;
94
+
95
+ for (i = 0; catdesc[i].desc; i++)
96
+ mask |= catdesc[i].category;
97
+
98
+ extract_cmds(&cmds, mask);
99
+
100
+ for (i = 0; cmds[i].name; i++, nr++) {
101
+ if (longest < strlen(cmds[i].name))
102
+ longest = strlen(cmds[i].name);
103
+ }
104
+ QSORT(cmds, nr, cmd_name_cmp);
105
+
106
+ for (i = 0; catdesc[i].desc; i++) {
107
+ uint32_t mask = catdesc[i].category;
108
+ const char *desc = catdesc[i].desc;
109
+
110
+ printf("\n%s\n", _(desc));
111
+ print_command_list(cmds, mask, longest);
112
+ }
113
+ free(cmds);
114
+}
115
+
116
void add_cmdname(struct cmdnames *cmds, const char *name, int len)
117
{
118
struct cmdname *ent;
@@ -190,42 +291,10 @@ void list_commands(unsigned int colopts,
291
}
292
}
293
193
-static int cmd_group_cmp(const void *elem1, const void *elem2)
194
-{
195
- const struct cmdname_help *e1 = elem1;
196
- const struct cmdname_help *e2 = elem2;
197
-
198
- if (e1->group < e2->group)
199
- return -1;
200
- if (e1->group > e2->group)
201
- return 1;
202
- return strcmp(e1->name, e2->name);
203
-}
204
-
294
void list_common_cmds_help(void)
295
{
207
- int i, longest = 0;
208
- int current_grp = -1;
209
-
210
- for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
211
- if (longest < strlen(common_cmds[i].name))
212
- longest = strlen(common_cmds[i].name);
213
- }
214
-
215
- QSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp);
216
-
296
puts(_("These are common Git commands used in various situations:"));
218
-
219
- for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
220
- if (common_cmds[i].group != current_grp) {
221
- printf("\n%s\n", _(common_cmd_groups[common_cmds[i].group]));
222
- current_grp = common_cmds[i].group;
223
- }
224
-
225
- printf(" %s ", common_cmds[i].name);
226
- mput_char(' ', longest - strlen(common_cmds[i].name));
227
- puts(_(common_cmds[i].help));
228
- }
297
+ print_cmd_by_category(common_categories);
298
}
299
300
int is_in_cmdlist(struct cmdnames *c, const char *s)
@@ -285,6 +354,7 @@ const char *help_unknown_cmd(const char *cmd)
354
{
355
int i, n, best_similarity = 0;
356
struct cmdnames main_cmds, other_cmds;
357
+ struct cmdname_help *common_cmds;
358
359
memset(&main_cmds, 0, sizeof(main_cmds));
360
memset(&other_cmds, 0, sizeof(other_cmds));
@@ -299,6 +369,8 @@ const char *help_unknown_cmd(const char *cmd)
369
QSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);
370
uniq(&main_cmds);
371
372
+ extract_cmds(&common_cmds, common_mask);
373
+
374
/* This abuses cmdname->len for levenshtein distance */
375
for (i = 0, n = 0; i < main_cmds.cnt; i++) {
376
int cmp = 0; /* avoid compiler stupidity */
@@ -313,10 +385,10 @@ const char *help_unknown_cmd(const char *cmd)
385
die(_(bad_interpreter_advice), cmd, cmd);
386
387
/* Does the candidate appear in common_cmds list? */
316
- while (n < ARRAY_SIZE(common_cmds) &&
388
+ while (common_cmds[n].name &&
389
(cmp = strcmp(common_cmds[n].name, candidate)) < 0)
390
n++;
319
- if ((n < ARRAY_SIZE(common_cmds)) && !cmp) {
391
+ if (common_cmds[n].name && !cmp) {
392
/* Yes, this is one of the common commands */
393
n++; /* use the entry from common_cmds[] */
394
if (starts_with(candidate, cmd)) {
@@ -329,6 +401,7 @@ const char *help_unknown_cmd(const char *cmd)
401
main_cmds.names[i]->len =
402
levenshtein(cmd, candidate, 0, 2, 1, 3) + 1;
403
}
404
+ FREE_AND_NULL(common_cmds);
405
406
QSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare);
407
t/t0012-help.sh
+9
@@ -49,6 +49,15 @@ test_expect_success "--help does not work for guides" "
49
test_i18ncmp expect actual
50
"
51
52
+test_expect_success 'git help' '
53
+ git help >help.output &&
54
+ test_i18ngrep "^ clone " help.output &&
55
+ test_i18ngrep "^ add " help.output &&
56
+ test_i18ngrep "^ log " help.output &&
57
+ test_i18ngrep "^ commit " help.output &&
58
+ test_i18ngrep "^ fetch " help.output
59
+'
60
+
61
test_expect_success 'generate builtin list' '
62
git --list-builtins >builtins
63
'