diff options
author | Erik Faye-Lund <kusmabite@gmail.com> | 2010-11-26 17:00:39 +0100 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2010-12-05 12:15:12 -0800 |
commit | 6612b9e471a3e25079dac5257ead8cf6abe68575 (patch) | |
tree | 16dd87d66b5f169af3f33f0d0fedb003ae2d5789 /help.c | |
parent | 7d43de925b2771d295d8fc4341b7bd544e2a74fa (diff) | |
download | git-6612b9e471a3e25079dac5257ead8cf6abe68575.tar.gz |
help: always suggest common-cmds if prefix of cmd
If someone runs "git st", the command "git status" is not suggested
because it's not one of the closest levenshtein-neighbour.
Reserve the distance of 0 for common commands where the entered command
is a prefixe, as these are often more likely to be what the user meant.
This way, "git status" is the first suggestion, while a list of possible
typos are still suggested as well.
Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'help.c')
-rw-r--r-- | help.c | 47 |
1 files changed, 39 insertions, 8 deletions
@@ -3,6 +3,7 @@ #include "exec_cmd.h" #include "levenshtein.h" #include "help.h" +#include "common-cmds.h" /* most GUI terminals set COLUMNS (although some don't export it) */ 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 */ -#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) { @@ -319,10 +321,28 @@ const char *help_unknown_cmd(const char *cmd) sizeof(main_cmds.names), cmdname_compare); uniq(&main_cmds); - /* This reuses cmdname->len for similarity index */ - for (i = 0; i < main_cmds.cnt; ++i) + /* This abuses cmdname->len for levenshtein distance */ + 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 = - 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, sizeof(*main_cmds.names), levenshtein_compare); @@ -330,10 +350,21 @@ const char *help_unknown_cmd(const char *cmd) if (!main_cmds.cnt) die ("Uh oh. Your system reports no Git commands at all."); - best_similarity = main_cmds.names[0]->len; - n = 1; - while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len) - ++n; + /* skip and count prefix matches */ + for (n = 0; n < main_cmds.cnt && !main_cmds.names[n]->len; n++) + ; /* still counting */ + + 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)) { const char *assumed = main_cmds.names[0]->name; main_cmds.names[0] = NULL; |