Merge branch 'ef/help-cmd-prefix'

* ef/help-cmd-prefix:
  help: always suggest common-cmds if prefix of cmd
This commit is contained in:
Junio C Hamano 2010-12-12 21:49:52 -08:00
commit 4a29c6a0db
2 changed files with 41 additions and 8 deletions

View File

@ -1675,6 +1675,8 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
help.o: common-cmds.h
builtin/help.o: common-cmds.h builtin/help.o: common-cmds.h
builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \ builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
'-DGIT_HTML_PATH="$(htmldir_SQ)"' \ '-DGIT_HTML_PATH="$(htmldir_SQ)"' \

47
help.c
View File

@ -3,6 +3,7 @@
#include "exec_cmd.h" #include "exec_cmd.h"
#include "levenshtein.h" #include "levenshtein.h"
#include "help.h" #include "help.h"
#include "common-cmds.h"
/* most GUI terminals set COLUMNS (although some don't export it) */ /* most GUI terminals set COLUMNS (although some don't export it) */
static int term_columns(void) static int term_columns(void)
@ -298,7 +299,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
} }
/* An empirically derived magic number */ /* An empirically derived magic number */
#define SIMILAR_ENOUGH(x) ((x) < 6) #define SIMILARITY_FLOOR 7
#define SIMILAR_ENOUGH(x) ((x) < SIMILARITY_FLOOR)
const char *help_unknown_cmd(const char *cmd) const char *help_unknown_cmd(const char *cmd)
{ {
@ -319,10 +321,28 @@ const char *help_unknown_cmd(const char *cmd)
sizeof(main_cmds.names), cmdname_compare); sizeof(main_cmds.names), cmdname_compare);
uniq(&main_cmds); uniq(&main_cmds);
/* This reuses cmdname->len for similarity index */ /* This abuses cmdname->len for levenshtein distance */
for (i = 0; i < main_cmds.cnt; ++i) for (i = 0, n = 0; i < main_cmds.cnt; i++) {
int cmp = 0; /* avoid compiler stupidity */
const char *candidate = main_cmds.names[i]->name;
/* Does the candidate appear in common_cmds list? */
while (n < ARRAY_SIZE(common_cmds) &&
(cmp = strcmp(common_cmds[n].name, candidate)) < 0)
n++;
if ((n < ARRAY_SIZE(common_cmds)) && !cmp) {
/* Yes, this is one of the common commands */
n++; /* use the entry from common_cmds[] */
if (!prefixcmp(candidate, cmd)) {
/* Give prefix match a very good score */
main_cmds.names[i]->len = 0;
continue;
}
}
main_cmds.names[i]->len = main_cmds.names[i]->len =
levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4); levenshtein(cmd, candidate, 0, 2, 1, 4) + 1;
}
qsort(main_cmds.names, main_cmds.cnt, qsort(main_cmds.names, main_cmds.cnt,
sizeof(*main_cmds.names), levenshtein_compare); sizeof(*main_cmds.names), levenshtein_compare);
@ -330,10 +350,21 @@ const char *help_unknown_cmd(const char *cmd)
if (!main_cmds.cnt) if (!main_cmds.cnt)
die ("Uh oh. Your system reports no Git commands at all."); die ("Uh oh. Your system reports no Git commands at all.");
best_similarity = main_cmds.names[0]->len; /* skip and count prefix matches */
n = 1; for (n = 0; n < main_cmds.cnt && !main_cmds.names[n]->len; n++)
while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len) ; /* still counting */
++n;
if (main_cmds.cnt <= n) {
/* prefix matches with everything? that is too ambiguous */
best_similarity = SIMILARITY_FLOOR + 1;
} else {
/* count all the most similar ones */
for (best_similarity = main_cmds.names[n++]->len;
(n < main_cmds.cnt &&
best_similarity == main_cmds.names[n]->len);
n++)
; /* still counting */
}
if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) { if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {
const char *assumed = main_cmds.names[0]->name; const char *assumed = main_cmds.names[0]->name;
main_cmds.names[0] = NULL; main_cmds.names[0] = NULL;