{"thread":{"id":"15253","subject":"[PATCH] Remove calculation of the longest command name from where it is not used","startedAt":"2008-08-28T17:15:33Z","lastAt":"2008-09-08T06:50:45Z","messageCount":19,"participants":["Alex Riesen","Andreas Ericsson","Mikael Magnusson","Junio C Hamano","Felipe Carvalho Oliveira","Matthieu Moy"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"88926","messageId":"20080828171533.GA6024@blimp.local","threadId":"15253","inReplyTo":null,"subject":"[PATCH] Remove calculation of the longest command name from where it is not used","fromName":"Alex Riesen","fromEmail":"fork0@users.sourceforge.net","sentAt":"2008-08-28T17:15:33Z","receivedAt":"2008-08-28T17:15:33Z","isPatch":true,"sender":{"key":"fork0@users.sourceforge.net","avatar":null},"body":"Just calculate it where it is needed - it is cheap and trivial,\nas all the lengths are already there (stored when creating the\ncommand lists).\n\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\n---\n\nAnd it less code than before (it is even more deletions than\ninsertions).\n\nBTW, the Johannesses typo-guesser conflicts heavily in recent master.\nPity. I'm going to rebase it and send out the rebased version.\n\n builtin-help.c  |    4 ++--\n builtin-merge.c |    8 ++++----\n help.c          |   34 +++++++++++++++-------------------\n help.h          |    6 +++---\n 4 files changed, 24 insertions(+), 28 deletions(-)\n\ndiff --git a/builtin-help.c b/builtin-help.c\nindex 391f749..9225102 100644\n--- a/builtin-help.c\n+++ b/builtin-help.c\n@@ -418,7 +418,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n {\n \tint nongit;\n \tconst char *alias;\n-\tunsigned int longest = load_command_list(\"git-\", &main_cmds, &other_cmds);\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \n \tsetup_git_directory_gently(&nongit);\n \tgit_config(git_help_config, NULL);\n@@ -428,7 +428,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tlist_commands(\"git commands\", longest, &main_cmds, &other_cmds);\n+\t\tlist_commands(\"git commands\", &main_cmds, &other_cmds);\n \t\tprintf(\"%s\\n\", git_more_info_string);\n \t\treturn 0;\n \t}\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex d6bcbec..dcd08f7 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -80,7 +80,7 @@ static struct strategy *get_strategy(const char *name)\n \tint i;\n \tstruct strategy *ret;\n \tstatic struct cmdnames main_cmds, other_cmds;\n-\tstatic int longest;\n+\tstatic int loaded;\n \n \tif (!name)\n \t\treturn NULL;\n@@ -89,14 +89,14 @@ static struct strategy *get_strategy(const char *name)\n \t\tif (!strcmp(name, all_strategy[i].name))\n \t\t\treturn &all_strategy[i];\n \n-\tif (!longest) {\n+\tif (!loaded) {\n \t\tstruct cmdnames not_strategies;\n+\t\tloaded = 1;\n \n \t\tmemset(&main_cmds, 0, sizeof(struct cmdnames));\n \t\tmemset(&other_cmds, 0, sizeof(struct cmdnames));\n \t\tmemset(&not_strategies, 0, sizeof(struct cmdnames));\n-\t\tlongest = load_command_list(\"git-merge-\", &main_cmds,\n-\t\t\t\t&other_cmds);\n+\t\tload_command_list(\"git-merge-\", &main_cmds, &other_cmds);\n \t\tfor (i = 0; i < main_cmds.cnt; i++) {\n \t\t\tint j, found = 0;\n \t\t\tstruct cmdname *ent = main_cmds.names[i];\ndiff --git a/help.c b/help.c\nindex 1afbac0..a17a746 100644\n--- a/help.c\n+++ b/help.c\n@@ -133,11 +133,10 @@ static int is_executable(const char *name)\n \treturn st.st_mode & S_IXUSR;\n }\n \n-static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n+static void list_commands_in_dir(struct cmdnames *cmds,\n \t\t\t\t\t const char *path,\n \t\t\t\t\t const char *prefix)\n {\n-\tunsigned int longest = 0;\n \tint prefix_len;\n \tDIR *dir = opendir(path);\n \tstruct dirent *de;\n@@ -145,7 +144,7 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \tint len;\n \n \tif (!dir)\n-\t\treturn 0;\n+\t\treturn;\n \tif (!prefix)\n \t\tprefix = \"git-\";\n \tprefix_len = strlen(prefix);\n@@ -168,29 +167,22 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \t\tif (has_extension(de->d_name, \".exe\"))\n \t\t\tentlen -= 4;\n \n-\t\tif (longest < entlen)\n-\t\t\tlongest = entlen;\n-\n \t\tadd_cmdname(cmds, de->d_name + prefix_len, entlen);\n \t}\n \tclosedir(dir);\n \tstrbuf_release(&buf);\n-\n-\treturn longest;\n }\n \n-unsigned int load_command_list(const char *prefix,\n+void load_command_list(const char *prefix,\n \t\tstruct cmdnames *main_cmds,\n \t\tstruct cmdnames *other_cmds)\n {\n-\tunsigned int longest = 0;\n-\tunsigned int len;\n \tconst char *env_path = getenv(\"PATH\");\n \tchar *paths, *path, *colon;\n \tconst char *exec_path = git_exec_path();\n \n \tif (exec_path)\n-\t\tlongest = list_commands_in_dir(main_cmds, exec_path, prefix);\n+\t\tlist_commands_in_dir(main_cmds, exec_path, prefix);\n \n \tif (!env_path) {\n \t\tfprintf(stderr, \"PATH not set\\n\");\n@@ -202,9 +194,7 @@ unsigned int load_command_list(const char *prefix,\n \t\tif ((colon = strchr(path, PATH_SEP)))\n \t\t\t*colon = 0;\n \n-\t\tlen = list_commands_in_dir(other_cmds, path, prefix);\n-\t\tif (len > longest)\n-\t\t\tlongest = len;\n+\t\tlist_commands_in_dir(other_cmds, path, prefix);\n \n \t\tif (!colon)\n \t\t\tbreak;\n@@ -220,14 +210,20 @@ unsigned int load_command_list(const char *prefix,\n \t      sizeof(*other_cmds->names), cmdname_compare);\n \tuniq(other_cmds);\n \texclude_cmds(other_cmds, main_cmds);\n-\n-\treturn longest;\n }\n \n-void list_commands(const char *title, unsigned int longest,\n-\t\tstruct cmdnames *main_cmds, struct cmdnames *other_cmds)\n+void list_commands(const char *title, struct cmdnames *main_cmds,\n+\t\t   struct cmdnames *other_cmds)\n {\n \tconst char *exec_path = git_exec_path();\n+\tint i, longest = 0;\n+\n+\tfor (i = 0; i < main_cmds->cnt; i++)\n+\t\tif (longest < main_cmds->names[i]->len)\n+\t\t\tlongest = main_cmds->names[i]->len;\n+\tfor (i = 0; i < other_cmds->cnt; i++)\n+\t\tif (longest < other_cmds->names[i]->len)\n+\t\t\tlongest = other_cmds->names[i]->len;\n \n \tif (main_cmds->cnt) {\n \t\tprintf(\"available %s in '%s'\\n\", title, exec_path);\ndiff --git a/help.h b/help.h\nindex 3f1ae89..2733433 100644\n--- a/help.h\n+++ b/help.h\n@@ -16,14 +16,14 @@ static inline void mput_char(char c, unsigned int num)\n \t\tputchar(c);\n }\n \n-unsigned int load_command_list(const char *prefix,\n+void load_command_list(const char *prefix,\n \t\tstruct cmdnames *main_cmds,\n \t\tstruct cmdnames *other_cmds);\n void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n /* Here we require that excludes is a sorted list. */\n void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n int is_in_cmdlist(struct cmdnames *c, const char *s);\n-void list_commands(const char *title, unsigned int longest,\n-\t\tstruct cmdnames *main_cmds, struct cmdnames *other_cmds);\n+void list_commands(const char *title, struct cmdnames *main_cmds,\n+\t\t   struct cmdnames *other_cmds);\n \n #endif /* HELP_H */\n-- \n1.6.0.1.150.g5966\n"},{"id":"89011","messageId":"20080828212722.GF6439@steel.home","threadId":"15253","inReplyTo":"20080828171533.GA6024@blimp.local","subject":"[PATCH updated] git wrapper: DWIM mistyped commands","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-08-28T21:27:22Z","receivedAt":"2008-08-28T21:27:22Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"From: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n\nThis patch introduces a modified Damerau-Levenshtein algorithm into\nGit's code base, and uses it with the following penalties to show some\nsimilar commands when an unknown command was encountered:\n\n\tswap = 0, insertion = 1, substitution = 2, deletion = 4\n\nA typical output would now look like this:\n\n\t$ git sm\n\tgit: 'sm' is not a git-command. See 'git --help'.\n\n\tDid you mean one of these?\n\t\tam\n\t\trm\n\nThe cut-off is at similarity rating 6, which was empirically determined\nto give sensible results.\n\nAs a convenience, if there is only one candidate, Git continues under\nthe assumption that the user mistyped it.  Example:\n\n\t$ git reabse\n\tWARNING: You called a Git program named 'reabse', which does\n\tnot exist.\n\tContinuing under the assumption that you meant 'rebase'\n\t[...]\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\n---\n\nAlex Riesen, Thu, Aug 28, 2008 19:15:33 +0200:\n> \n> BTW, the Johannesses typo-guesser conflicts heavily in recent master.\n> Pity. I'm going to rebase it and send out the rebased version.\n> \n\nAs promised. Johannes, I remember you talking about some problem with\nthat code (it should be the latest we talked about on the list), but I\nam not sure I have updated the algorithm accordingly. Could you please\ncheck?\n\n Makefile      |    2 +\n builtin.h     |    2 +-\n git.c         |    4 ++-\n help.c        |   64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n levenshtein.c |   47 +++++++++++++++++++++++++++++++++++++++++\n levenshtein.h |    8 +++++++\n 6 files changed, 124 insertions(+), 3 deletions(-)\n create mode 100644 levenshtein.c\n create mode 100644 levenshtein.h\n\ndiff --git a/Makefile b/Makefile\nindex bf400e6..3daa6dc 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -358,6 +358,7 @@ LIB_H += graph.h\n LIB_H += grep.h\n LIB_H += hash.h\n LIB_H += help.h\n+LIB_H += levenshtein.h\n LIB_H += list-objects.h\n LIB_H += ll-merge.h\n LIB_H += log-tree.h\n@@ -433,6 +434,7 @@ LIB_OBJS += hash.o\n LIB_OBJS += help.o\n LIB_OBJS += ident.o\n LIB_OBJS += interpolate.o\n+LIB_OBJS += levenshtein.o\n LIB_OBJS += list-objects.o\n LIB_OBJS += ll-merge.o\n LIB_OBJS += lockfile.o\ndiff --git a/builtin.h b/builtin.h\nindex f3502d3..e67cb20 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -11,7 +11,7 @@ extern const char git_usage_string[];\n extern const char git_more_info_string[];\n \n extern void list_common_cmds_help(void);\n-extern void help_unknown_cmd(const char *cmd);\n+extern const char *help_unknown_cmd(const char *cmd);\n extern void prune_packed_objects(int);\n extern int read_line_with_nul(char *buf, int size, FILE *file);\n extern int fmt_merge_msg(int merge_summary, struct strbuf *in,\ndiff --git a/git.c b/git.c\nindex 37b1d76..54c5bfa 100644\n--- a/git.c\n+++ b/git.c\n@@ -499,7 +499,9 @@ int main(int argc, const char **argv)\n \t\t\t\tcmd, argv[0]);\n \t\t\texit(1);\n \t\t}\n-\t\thelp_unknown_cmd(cmd);\n+\t\targv[0] = help_unknown_cmd(cmd);\n+\t\thandle_internal_command(argc, argv);\n+\t\texecv_dashed_external(argv);\n \t}\n \n \tfprintf(stderr, \"Failed to run command '%s': %s\\n\",\ndiff --git a/help.c b/help.c\nindex 1afbac0..981fb02 100644\n--- a/help.c\n+++ b/help.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n+#include \"levenshtein.h\"\n #include \"help.h\"\n \n /* most GUI terminals set COLUMNS (although some don't export it) */\n@@ -257,9 +258,70 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)\n \treturn 0;\n }\n \n-void help_unknown_cmd(const char *cmd)\n+static const char *levenshtein_cmd;\n+static int similarity(const char *cmd) {\n+\treturn levenshtein(levenshtein_cmd, cmd, 0, 2, 1, 4);\n+}\n+\n+static int levenshtein_compare(const void *p1, const void *p2)\n {\n+\tconst struct cmdname *const *c1 = p1, *const *c2 = p2;\n+\tconst char *s1 = (*c1)->name, *s2 = (*c2)->name;\n+\tint l1 = similarity(s1);\n+\tint l2 = similarity(s2);\n+\treturn l1 != l2 ? l1 - l2 : strcmp(s1, s2);\n+}\n+\n+const char *help_unknown_cmd(const char *cmd)\n+{\n+\tint i, best_similarity = 0;\n+\tchar cwd[PATH_MAX];\n+\tstatic struct cmdnames main_cmds, other_cmds;\n+\n+\tif (!getcwd(cwd, sizeof(cwd))) {\n+\t\terror(\"Could not get current working directory\");\n+\t\tcwd[0] = '\\0';\n+\t}\n+\n+\tif (!main_cmds.cnt && !other_cmds.cnt)\n+\t\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tALLOC_GROW(main_cmds.names, main_cmds.cnt + other_cmds.cnt,\n+\t\t\tmain_cmds.alloc);\n+\tmemcpy(main_cmds.names + main_cmds.cnt, other_cmds.names,\n+\t\tother_cmds.cnt * sizeof(other_cmds.names[0]));\n+\tmain_cmds.cnt += other_cmds.cnt;\n+\n+\tlevenshtein_cmd = cmd;\n+\tqsort(main_cmds.names, main_cmds.cnt,\n+\t      sizeof(*main_cmds.names), levenshtein_compare);\n+\n+\tif (!main_cmds.cnt)\n+\t\tdie (\"Uh oh.  Your system reports no Git commands at all.\");\n+\tbest_similarity = similarity(main_cmds.names[0]->name);\n+\tif (main_cmds.cnt < 2 ||\n+\t    best_similarity < similarity(main_cmds.names[1]->name)) {\n+\t\tif (!*cwd)\n+\t\t\texit(1);\n+\t\tif (chdir(cwd))\n+\t\t\tdie (\"Could not change directory back to '%s'\", cwd);\n+\t\tfprintf(stderr, \"WARNING: You called a Git program named '%s', \"\n+\t\t\t\"which does not exist.\\n\"\n+\t\t\t\"Continuing under the assumption that you meant '%s'\\n\",\n+\t\t\tcmd, main_cmds.names[0]->name);\n+\t\treturn main_cmds.names[0]->name;\n+\t}\n+\n \tfprintf(stderr, \"git: '%s' is not a git-command. See 'git --help'.\\n\", cmd);\n+\n+\tif (best_similarity < 6) {\n+\t\tfprintf(stderr, \"\\nDid you mean one of these?\\n\");\n+\n+\t\tfor (i = 0; i < main_cmds.cnt && best_similarity ==\n+\t\t\t\tsimilarity(main_cmds.names[i]->name); i++)\n+\t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n+\t}\n+\n \texit(1);\n }\n \ndiff --git a/levenshtein.c b/levenshtein.c\nnew file mode 100644\nindex 0000000..db52f2c\n--- /dev/null\n+++ b/levenshtein.c\n@@ -0,0 +1,47 @@\n+#include \"cache.h\"\n+#include \"levenshtein.h\"\n+\n+int levenshtein(const char *string1, const char *string2,\n+\t\tint w, int s, int a, int d)\n+{\n+\tint len1 = strlen(string1), len2 = strlen(string2);\n+\tint *row0 = xmalloc(sizeof(int) * (len2 + 1));\n+\tint *row1 = xmalloc(sizeof(int) * (len2 + 1));\n+\tint *row2 = xmalloc(sizeof(int) * (len2 + 1));\n+\tint i, j;\n+\n+\tfor (j = 0; j <= len2; j++)\n+\t\trow1[j] = j * a;\n+\tfor (i = 0; i < len1; i++) {\n+\t\tint *dummy;\n+\n+\t\trow2[0] = (i + 1) * d;\n+\t\tfor (j = 0; j < len2; j++) {\n+\t\t\t/* substitution */\n+\t\t\trow2[j + 1] = row1[j] + s * (string1[i] != string2[j]);\n+\t\t\t/* swap */\n+\t\t\tif (i > 0 && j > 0 && string1[i - 1] == string2[j] &&\n+\t\t\t\t\tstring1[i] == string2[j - 1] &&\n+\t\t\t\t\trow2[j + 1] > row0[j - 1] + w)\n+\t\t\t\trow2[j + 1] = row0[j - 1] + w;\n+\t\t\t/* deletion */\n+\t\t\tif (j + 1 < len2 && row2[j + 1] > row1[j + 1] + d)\n+\t\t\t\trow2[j + 1] = row1[j + 1] + d;\n+\t\t\t/* insertion */\n+\t\t\tif (row2[j + 1] > row2[j] + a)\n+\t\t\t\trow2[j + 1] = row2[j] + a;\n+\t\t}\n+\n+\t\tdummy = row0;\n+\t\trow0 = row1;\n+\t\trow1 = row2;\n+\t\trow2 = dummy;\n+\t}\n+\n+\ti = row1[len2];\n+\tfree(row0);\n+\tfree(row1);\n+\tfree(row2);\n+\n+\treturn i;\n+}\ndiff --git a/levenshtein.h b/levenshtein.h\nnew file mode 100644\nindex 0000000..0173abe\n--- /dev/null\n+++ b/levenshtein.h\n@@ -0,0 +1,8 @@\n+#ifndef LEVENSHTEIN_H\n+#define LEVENSHTEIN_H\n+\n+int levenshtein(const char *string1, const char *string2,\n+\tint swap_penalty, int substition_penalty,\n+\tint insertion_penalty, int deletion_penalty);\n+\n+#endif\n-- \n1.6.0.106.g97c8\n"},{"id":"89012","messageId":"20080828212815.GG6439@steel.home","threadId":"15253","inReplyTo":"20080828212722.GF6439@steel.home","subject":"[PATCH] Add help.autocorrect to enable/disable autocorrecting","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-08-28T21:28:15Z","receivedAt":"2008-08-28T21:28:15Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"It is off(0) by default, to avoid scaring people unless they asked to.\nIf set to a non-0 value, wait for that amount of deciseconds before\nrunning the corrected command.\n\nSuggested by Junio, so he has a chance to hit Ctrl-C.\n\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\n---\n Documentation/config.txt |    9 ++++++++\n help.c                   |   50 ++++++++++++++++++++++++++++++++++++++-------\n 2 files changed, 51 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex af57d94..8c644ab 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -790,6 +790,15 @@ help.format::\n \tValues 'man', 'info', 'web' and 'html' are supported. 'man' is\n \tthe default. 'web' and 'html' are the same.\n \n+help.autocorrect::\n+\tAutomatically correct and execute mistyped commands after\n+\twaiting for the given number of deciseconds (0.1 sec). If more\n+\tthan one command can be deduced from the entered text, nothing\n+\twill be executed.  If the value of this option is negative,\n+\tthe corrected command will be executed immediately. If the\n+\tvalue is 0 - the command will be just shown but not executed.\n+\tThis is the default.\n+\n http.proxy::\n \tOverride the HTTP proxy, normally configured using the 'http_proxy'\n \tenvironment variable (see linkgit:curl[1]).  This can be overridden\ndiff --git a/help.c b/help.c\nindex 981fb02..7bfbbcd 100644\n--- a/help.c\n+++ b/help.c\n@@ -38,6 +38,16 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n \tcmds->names[cmds->cnt++] = ent;\n }\n \n+static void clean_cmdnames(struct cmdnames *cmds)\n+{\n+\tint i;\n+\tfor (i = 0; i < cmds->cnt; ++i)\n+\t\tfree(cmds->names[i]);\n+\tfree(cmds->names);\n+\tcmds->cnt = 0;\n+\tcmds->alloc = 0;\n+}\n+\n static int cmdname_compare(const void *a_, const void *b_)\n {\n \tstruct cmdname *a = *(struct cmdname **)a_;\n@@ -258,6 +268,16 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)\n \treturn 0;\n }\n \n+static int autocorrect;\n+\n+static int git_unknown_cmd_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"help.autocorrect\"))\n+\t\tautocorrect = git_config_int(var,value);\n+\n+\treturn git_default_config(var, value, cb);\n+}\n+\n static const char *levenshtein_cmd;\n static int similarity(const char *cmd) {\n \treturn levenshtein(levenshtein_cmd, cmd, 0, 2, 1, 4);\n@@ -274,7 +294,7 @@ static int levenshtein_compare(const void *p1, const void *p2)\n \n const char *help_unknown_cmd(const char *cmd)\n {\n-\tint i, best_similarity = 0;\n+\tint i, best_similarity = 0, n;\n \tchar cwd[PATH_MAX];\n \tstatic struct cmdnames main_cmds, other_cmds;\n \n@@ -283,6 +303,7 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tcwd[0] = '\\0';\n \t}\n \n+\tgit_config(git_unknown_cmd_config, NULL);\n \tif (!main_cmds.cnt && !other_cmds.cnt)\n \t\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \n@@ -299,26 +320,39 @@ const char *help_unknown_cmd(const char *cmd)\n \tif (!main_cmds.cnt)\n \t\tdie (\"Uh oh.  Your system reports no Git commands at all.\");\n \tbest_similarity = similarity(main_cmds.names[0]->name);\n-\tif (main_cmds.cnt < 2 ||\n-\t    best_similarity < similarity(main_cmds.names[1]->name)) {\n+\tn = 1;\n+\twhile (n < main_cmds.cnt &&\n+\t\tbest_similarity == similarity(main_cmds.names[n]->name))\n+\t\t++n;\n+\tif (autocorrect && n == 1) {\n+\t\tconst char *assumed;\n \t\tif (!*cwd)\n \t\t\texit(1);\n \t\tif (chdir(cwd))\n \t\t\tdie (\"Could not change directory back to '%s'\", cwd);\n+\t\tassumed = main_cmds.names[0]->name;\n+\t\tmain_cmds.names[0] = NULL;\n+\t\tclean_cmdnames(&other_cmds);\n+\t\tclean_cmdnames(&main_cmds);\n \t\tfprintf(stderr, \"WARNING: You called a Git program named '%s', \"\n \t\t\t\"which does not exist.\\n\"\n \t\t\t\"Continuing under the assumption that you meant '%s'\\n\",\n-\t\t\tcmd, main_cmds.names[0]->name);\n-\t\treturn main_cmds.names[0]->name;\n+\t\t\tcmd, assumed);\n+\t\tif (autocorrect > 0) {\n+\t\t\tfprintf(stderr, \"in %0.1f seconds automatically...\\n\",\n+\t\t\t\t(float)autocorrect/10.0);\n+\t\t\tpoll(NULL, 0, autocorrect * 100);\n+\t\t}\n+\t\treturn assumed;\n \t}\n \n \tfprintf(stderr, \"git: '%s' is not a git-command. See 'git --help'.\\n\", cmd);\n \n \tif (best_similarity < 6) {\n-\t\tfprintf(stderr, \"\\nDid you mean one of these?\\n\");\n+\t\tfprintf(stderr, \"\\nDid you mean %s?\\n\",\n+\t\t\tn < 2 ? \"this\": \"one of these\");\n \n-\t\tfor (i = 0; i < main_cmds.cnt && best_similarity ==\n-\t\t\t\tsimilarity(main_cmds.names[i]->name); i++)\n+\t\tfor (i = 0; i < n; i++)\n \t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n \t}\n \n-- \n1.6.0.106.g97c8\n"},{"id":"89114","messageId":"48B7CB43.3020808@op5.se","threadId":"15253","inReplyTo":"20080828212815.GG6439@steel.home","subject":"Re: [PATCH] Add help.autocorrect to enable/disable autocorrecting","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2008-08-29T10:11:15Z","receivedAt":"2008-08-29T10:11:15Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Alex Riesen wrote:\n> It is off(0) by default, to avoid scaring people unless they asked to.\n> If set to a non-0 value, wait for that amount of deciseconds before\n> running the corrected command.\n> \n> Suggested by Junio, so he has a chance to hit Ctrl-C.\n> \n\nI'm just plain loving this :)\n\nLiked-by: Andreas Ericsson <ae@op5.se>\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"89134","messageId":"237967ef0808290758p2bd1de55idcb9ad9150389b2b@mail.gmail.com","threadId":"15253","inReplyTo":"20080828212722.GF6439@steel.home","subject":"Re: [PATCH updated] git wrapper: DWIM mistyped commands","fromName":"Mikael Magnusson","fromEmail":"mikachu@gmail.com","sentAt":"2008-08-29T14:58:14Z","receivedAt":"2008-08-29T14:58:14Z","isPatch":true,"sender":{"key":"mikachu@gmail.com","avatar":null},"body":"2008/8/28 Alex Riesen <raa.lkml@gmail.com>:\n> From: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n>\n> This patch introduces a modified Damerau-Levenshtein algorithm into\n> Git's code base, and uses it with the following penalties to show some\n> similar commands when an unknown command was encountered:\n>\n>        swap = 0, insertion = 1, substitution = 2, deletion = 4\n>\n> A typical output would now look like this:\n>\n>        $ git sm\n>        git: 'sm' is not a git-command. See 'git --help'.\n>\n>        Did you mean one of these?\n>                am\n>                rm\n>\n> The cut-off is at similarity rating 6, which was empirically determined\n> to give sensible results.\n\nI merged the branch in pu into next, which I think should work, but I get\nthese segfaults for some commands... I tried running in gdb but even with\n-g3 I only get nonsense backtraces, not sure why.\n\n% git puhs\nWARNING: You called a Git program named 'puhs', which does not exist.\nContinuing under the assumption that you meant 'push'\nin 2.0 seconds automatically...\nzsh: segmentation fault  git puhs\n\n% git ma\nWARNING: You called a Git program named 'ma', which does not exist.\nContinuing under the assumption that you meant 'am'\nin 2.0 seconds automatically...\nNothing to do.\n\nAt this point I thought builtins crashed and scripts were fine, but...\n% git ada\nWARNING: You called a Git program named 'ada', which does not exist.\nContinuing under the assumption that you meant 'add'\nin 2.0 seconds automatically...\nNothing specified, nothing added.\nMaybe you wanted to say 'git add .'?\n\nHowever,\n% git ada git.c\nWARNING: You called a Git program named 'ada', which does not exist.\nContinuing under the assumption that you meant 'add'\nin 2.0 seconds automatically...\nzsh: segmentation fault  git ada git.c\n\n-- \nMikael Magnusson\n"},{"id":"89204","messageId":"81b0412b0808300312h53605ac8p2d60784ca2178a0@mail.gmail.com","threadId":"15253","inReplyTo":"237967ef0808290758p2bd1de55idcb9ad9150389b2b@mail.gmail.com","subject":"Re: [PATCH updated] git wrapper: DWIM mistyped commands","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-08-30T10:12:47Z","receivedAt":"2008-08-30T10:12:47Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"2008/8/29 Mikael Magnusson <mikachu@gmail.com>:\n> I merged the branch in pu into next, which I think should work, but I get\n> these segfaults for some commands... I tried running in gdb but even with\n\nCan't reproduce in master, will try with next later, am busy right now, sorry.\n\n> -g3 I only get nonsense backtraces, not sure why.\n\nRemove -O2 from CFLAGS:\n\n  $ make CFLAGS=\"-O0 -ggdb\"\n"},{"id":"89205","messageId":"237967ef0808300333t2cd4e354xd461f7bfead40f4c@mail.gmail.com","threadId":"15253","inReplyTo":"81b0412b0808300312h53605ac8p2d60784ca2178a0@mail.gmail.com","subject":"Re: [PATCH updated] git wrapper: DWIM mistyped commands","fromName":"Mikael Magnusson","fromEmail":"mikachu@gmail.com","sentAt":"2008-08-30T10:33:26Z","receivedAt":"2008-08-30T10:33:26Z","isPatch":true,"sender":{"key":"mikachu@gmail.com","avatar":null},"body":"2008/8/30 Alex Riesen <raa.lkml@gmail.com>:\n> 2008/8/29 Mikael Magnusson <mikachu@gmail.com>:\n>> I merged the branch in pu into next, which I think should work, but I get\n>> these segfaults for some commands... I tried running in gdb but even with\n>\n> Can't reproduce in master, will try with next later, am busy right now, sorry.\n>\n>> -g3 I only get nonsense backtraces, not sure why.\n>\n> Remove -O2 from CFLAGS:\n>\n>  $ make CFLAGS=\"-O0 -ggdb\"\n\nHm, I only had CFLAGS set in the env, maybe that's not enough, or maybe it\nwas that I had it set to -gdwarf-2 -g3 instead of -ggdb3. At any rate, I got\nthis now:\n\n% git fotch\nProgram received signal SIGSEGV, Segmentation fault.\n[Switching to Thread 0xa7ce56c0 (LWP 13043)]\n0x41b61490 in ?? () from /lib/libc.so.6\n(gdb) bt\n#0  0x41b61490 in ?? () from /lib/libc.so.6\n#1  0x41b634b0 in realloc () from /lib/libc.so.6\n#2  0x41b62fdb in malloc () from /lib/libc.so.6\n#3  0x080f63e6 in xmalloc (size=24) at wrapper.c:20\n#4  0x080f6471 in xmemdupz (data=0x816a44f, len=23) at wrapper.c:45\n#5  0x080f64e9 in xstrndup (str=0x816a44f \"refs/remotes/origin/man\",\nlen=23) at wrapper.c:54\n#6  0x080dc05c in parse_refspec_internal (nr_refspec=6,\nrefspec=0x816a010, fetch=1, verify=0)\n    at remote.c:505\n#7  0x080dc3ca in parse_fetch_refspec (nr_refspec=6,\nrefspec=0x816a010) at remote.c:613\n#8  0x080dc512 in remote_get (name=0x8169458 \"origin\") at remote.c:649\n#9  0x0806cd4d in cmd_fetch (argc=0, argv=0xafc2d578, prefix=0x0) at\nbuiltin-fetch.c:620\n#10 0x0804bb3c in run_command (p=0x8123498, argc=1, argv=0xafc2d578)\nat git.c:238\n#11 0x0804bccc in handle_internal_command (argc=1, argv=0xafc2d578) at git.c:380\n#12 0x0804bfea in main (argc=1, argv=0xafc2d578) at git.c:500\n(gdb) bt full\n#0  0x41b61490 in ?? () from /lib/libc.so.6\nNo symbol table info available.\n#1  0x41b634b0 in realloc () from /lib/libc.so.6\nNo symbol table info available.\n#2  0x41b62fdb in malloc () from /lib/libc.so.6\nNo symbol table info available.\n#3  0x080f63e6 in xmalloc (size=24) at wrapper.c:20\n\tret = (void *) 0x0\n#4  0x080f6471 in xmemdupz (data=0x816a44f, len=23) at wrapper.c:45\n\tp = 0x0\n#5  0x080f64e9 in xstrndup (str=0x816a44f \"refs/remotes/origin/man\",\nlen=23) at wrapper.c:54\n\tp = 0x0\n#6  0x080dc05c in parse_refspec_internal (nr_refspec=6,\nrefspec=0x816a010, fetch=1, verify=0)\n    at remote.c:505\n\trlen = 23\n\tllen = 0\n\tis_glob = 0\n\tlhs = 0x816a440 \"refs/heads/man:refs/remotes/origin/man\"\n\trhs = 0x816a44f \"refs/remotes/origin/man\"\n\ti = 4\n\tst = 0\n\trs = (struct refspec *) 0x8169d88\n#7  0x080dc3ca in parse_fetch_refspec (nr_refspec=6,\nrefspec=0x816a010) at remote.c:613\nNo locals.\n#8  0x080dc512 in remote_get (name=0x8169458 \"origin\") at remote.c:649\n\tret = (struct remote *) 0x8169ef0\n#9  0x0806cd4d in cmd_fetch (argc=0, argv=0xafc2d578, prefix=0x0) at\nbuiltin-fetch.c:620\n\tremote = (struct remote *) 0x804b2d4\n\ti = 1\n---Type <return> to continue, or q <return> to quit---\n\tref_nr = 0\n\texit_code = 0\n\trefs = (const char **) 0x0\n#10 0x0804bb3c in run_command (p=0x8123498, argc=1, argv=0xafc2d578)\nat git.c:238\n\tstatus = -1346186104\n\tst = {st_dev = 582794214293012544, __pad1 = 0, __st_ino = 1103151906,\nst_mode = 5,\n  st_nlink = 0, st_uid = 0, st_gid = 135692352, st_rdev =\n582794423264539853, __pad2 = 54328,\n  st_size = 579290465871466043, st_blksize = 0, st_blocks =\n577791495034295448, st_atim = {\n    tv_sec = -1346180215, tv_nsec = 1103274272}, st_mtim = {tv_sec = 135692296,\n    tv_nsec = 1103269876}, st_ctim = {tv_sec = 1090632864, tv_nsec = 0},\n  st_ino = 580626572881613928}\n\tprefix = 0x0\n#11 0x0804bccc in handle_internal_command (argc=1, argv=0xafc2d578) at git.c:380\n\tp = (struct cmd_struct *) 0x8123498\n\tcmd = 0x8169a3c \"fetch\"\n\ti = 26\n\tcommands = {{cmd = 0x8104ebd \"add\", fn = 0x804c905 <cmd_add>, option = 5}, {\n    cmd = 0x8104ec1 \"annotate\", fn = 0x804cc70 <cmd_annotate>, option = 1}, {\n    cmd = 0x8104eca \"apply\", fn = 0x805362c <cmd_apply>, option = 0}, {\n    cmd = 0x8104ed0 \"archive\", fn = 0x80542e5 <cmd_archive>, option = 0}, {\n    cmd = 0x8104ed8 \"blame\", fn = 0x805889e <cmd_blame>, option = 1},\n{cmd = 0x8104ede \"branch\",\n    fn = 0x805a62f <cmd_branch>, option = 1}, {cmd = 0x8104ee5 \"bundle\",\n    fn = 0x805adb8 <cmd_bundle>, option = 0}, {cmd = 0x8104eec \"cat-file\",\n    fn = 0x805b6b1 <cmd_cat_file>, option = 1}, {cmd = 0x8104ef5 \"checkout\",\n    fn = 0x805d865 <cmd_checkout>, option = 5}, {cmd = 0x8104efe\n\"checkout-index\",\n    fn = 0x805c123 <cmd_checkout_index>, option = 5}, {cmd = 0x8104f0d\n\"check-ref-format\",\n    fn = 0x805bb84 <cmd_check_ref_format>, option = 0}, {cmd =\n0x8104f1e \"check-attr\",\n    fn = 0x805b94c <cmd_check_attr>, option = 1}, {cmd = 0x8104f29 \"cherry\",\n    fn = 0x8078c23 <cmd_cherry>, option = 1}, {cmd = 0x8104f30 \"cherry-pick\",\n---Type <return> to continue, or q <return> to quit---\n    fn = 0x8094c96 <cmd_cherry_pick>, option = 5}, {cmd = 0x8104f3c \"clone\",\n    fn = 0x805ef85 <cmd_clone>, option = 0}, {cmd = 0x8104f42 \"clean\",\n    fn = 0x805ddb3 <cmd_clean>, option = 5}, {cmd = 0x8104f48 \"commit\",\n    fn = 0x8062115 <cmd_commit>, option = 5}, {cmd = 0x8104f4f \"commit-tree\",\n    fn = 0x805fcbd <cmd_commit_tree>, option = 1}, {cmd = 0x8104f5b \"config\",\n    fn = 0x80632c5 <cmd_config>, option = 0}, {cmd = 0x8104f62 \"count-objects\",\n    fn = 0x8063f14 <cmd_count_objects>, option = 1}, {cmd = 0x8104f70\n\"describe\",\n    fn = 0x8064ce4 <cmd_describe>, option = 1}, {cmd = 0x8104f79 \"diff\",\n    fn = 0x80663da <cmd_diff>, option = 0}, {cmd = 0x8104f7e \"diff-files\",\n    fn = 0x80650d8 <cmd_diff_files>, option = 1}, {cmd = 0x8104f89\n\"diff-index\",\n    fn = 0x806530c <cmd_diff_index>, option = 1}, {cmd = 0x8104f94 \"diff-tree\",\n    fn = 0x80657f0 <cmd_diff_tree>, option = 1}, {cmd = 0x8104f9e\n\"fast-export\",\n    fn = 0x8067c10 <cmd_fast_export>, option = 1}, {cmd = 0x8104faa \"fetch\",\n    fn = 0x806ccb5 <cmd_fetch>, option = 1}, {cmd = 0x8104fb0 \"fetch-pack\",\n    fn = 0x806adeb <cmd_fetch_pack>, option = 1}, {cmd = 0x8104fbb\n\"fetch--tool\",\n    fn = 0x80692be <cmd_fetch__tool>, option = 1}, {cmd = 0x8104fc7\n\"fmt-merge-msg\",\n    fn = 0x806defb <cmd_fmt_merge_msg>, option = 1}, {cmd = 0x8104fd5\n\"for-each-ref\",\n    fn = 0x806fc5b <cmd_for_each_ref>, option = 1}, {cmd = 0x8104fe2\n\"format-patch\",\n    fn = 0x8077b7e <cmd_format_patch>, option = 1}, {cmd = 0x8104fef \"fsck\",\n    fn = 0x8071106 <cmd_fsck>, option = 1}, {cmd = 0x8104ff4 \"fsck-objects\",\n    fn = 0x8071106 <cmd_fsck>, option = 1}, {cmd = 0x8105001 \"gc\", fn\n= 0x80719b9 <cmd_gc>,\n    option = 1}, {cmd = 0x8105004 \"get-tar-commit-id\", fn = 0x809be66\n<cmd_get_tar_commit_id>,\n    option = 0}, {cmd = 0x8105016 \"grep\", fn = 0x807308e <cmd_grep>,\noption = 3}, {\n    cmd = 0x810501b \"help\", fn = 0x8074bd2 <cmd_help>, option = 0}, {\n    cmd = 0x8105020 \"http-fetch\", fn = 0x80a057c <cmd_http_fetch>,\noption = 1}, {\n    cmd = 0x810502b \"init\", fn = 0x8075a8d <cmd_init_db>, option = 0}, {\n    cmd = 0x8105030 \"init-db\", fn = 0x8075a8d <cmd_init_db>, option = 0}, {\n    cmd = 0x8105038 \"log\", fn = 0x8076c36 <cmd_log>, option = 3}, {cmd\n= 0x810503c \"ls-files\",\n    fn = 0x8079e63 <cmd_ls_files>, option = 1}, {cmd = 0x8105045 \"ls-tree\",\n---Type <return> to continue, or q <return> to quit---\n    fn = 0x807ae13 <cmd_ls_tree>, option = 1}, {cmd = 0x810504d \"ls-remote\",\n    fn = 0x807a797 <cmd_ls_remote>, option = 0}, {cmd = 0x8105057 \"mailinfo\",\n    fn = 0x807d1ef <cmd_mailinfo>, option = 0}, {cmd = 0x8105060 \"mailsplit\",\n    fn = 0x807db6e <cmd_mailsplit>, option = 0}, {cmd = 0x810506a \"merge\",\n    fn = 0x808016f <cmd_merge>, option = 5}, {cmd = 0x8105070 \"merge-base\",\n    fn = 0x8080fe6 <cmd_merge_base>, option = 1}, {cmd = 0x810507b\n\"merge-file\",\n    fn = 0x80810f0 <cmd_merge_file>, option = 0}, {cmd = 0x8105086\n\"merge-ours\",\n    fn = 0x8081438 <cmd_merge_ours>, option = 1}, {cmd = 0x8105091\n\"merge-recursive\",\n    fn = 0x8084c44 <cmd_merge_recursive>, option = 5}, {cmd =\n0x81050a1 \"merge-subtree\",\n    fn = 0x8084c44 <cmd_merge_recursive>, option = 5}, {cmd = 0x81050af \"mv\",\n    fn = 0x808509d <cmd_mv>, option = 5}, {cmd = 0x81050b2 \"name-rev\",\n    fn = 0x8086090 <cmd_name_rev>, option = 1}, {cmd = 0x81050bb\n\"pack-objects\",\n    fn = 0x808aa1a <cmd_pack_objects>, option = 1}, {cmd = 0x81050c8\n\"peek-remote\",\n    fn = 0x807a797 <cmd_ls_remote>, option = 0}, {cmd = 0x81050d4 \"pickaxe\",\n    fn = 0x805889e <cmd_blame>, option = 1}, {cmd = 0x81050dc \"prune\",\n    fn = 0x808badd <cmd_prune>, option = 1}, {cmd = 0x81050e2 \"prune-packed\",\n    fn = 0x808b60a <cmd_prune_packed>, option = 1}, {cmd = 0x81050ef \"push\",\n    fn = 0x808bf9f <cmd_push>, option = 1}, {cmd = 0x81050f4 \"read-tree\",\n    fn = 0x808c418 <cmd_read_tree>, option = 1}, {cmd = 0x81050fe \"reflog\",\n    fn = 0x808e264 <cmd_reflog>, option = 1}, {cmd = 0x8105105 \"remote\",\n    fn = 0x8090076 <cmd_remote>, option = 1}, {cmd = 0x810510c \"repo-config\",\n    fn = 0x80632c5 <cmd_config>, option = 0}, {cmd = 0x8105118 \"rerere\",\n    fn = 0x8090669 <cmd_rerere>, option = 1}, {cmd = 0x810511f \"reset\",\n    fn = 0x8090e44 <cmd_reset>, option = 1}, {cmd = 0x8105125 \"rev-list\",\n    fn = 0x8092096 <cmd_rev_list>, option = 1}, {cmd = 0x810512e \"rev-parse\",\n    fn = 0x80932a0 <cmd_rev_parse>, option = 0}, {cmd = 0x8105138 \"revert\",\n    fn = 0x8094c4e <cmd_revert>, option = 5}, {cmd = 0x810513f \"rm\",\nfn = 0x80950b5 <cmd_rm>,\n    option = 1}, {cmd = 0x8105142 \"send-pack\", fn = 0x8096982\n<cmd_send_pack>, option = 1}, {\n    cmd = 0x810514c \"shortlog\", fn = 0x809769a <cmd_shortlog>, option = 2}, {\n---Type <return> to continue, or q <return> to quit---\n    cmd = 0x8105155 \"show-branch\", fn = 0x8098c0c <cmd_show_branch>,\noption = 1}, {\n    cmd = 0x8105161 \"show\", fn = 0x80767e8 <cmd_show>, option = 3},\n{cmd = 0x8105166 \"status\",\n    fn = 0x8061d60 <cmd_status>, option = 5}, {cmd = 0x810516d \"stripspace\",\n    fn = 0x809a78d <cmd_stripspace>, option = 0}, {cmd = 0x8105178\n\"symbolic-ref\",\n    fn = 0x809a8db <cmd_symbolic_ref>, option = 1}, {cmd = 0x8105185 \"tag\",\n    fn = 0x809b51a <cmd_tag>, option = 1}, {cmd = 0x8105189 \"tar-tree\",\n    fn = 0x809bca4 <cmd_tar_tree>, option = 0}, {cmd = 0x8105192\n\"unpack-objects\",\n    fn = 0x809d17c <cmd_unpack_objects>, option = 1}, {cmd = 0x81051a1\n\"update-index\",\n    fn = 0x809e85c <cmd_update_index>, option = 1}, {cmd = 0x81051ae\n\"update-ref\",\n    fn = 0x809f1d8 <cmd_update_ref>, option = 1}, {cmd = 0x81051b9\n\"upload-archive\",\n    fn = 0x809f7a8 <cmd_upload_archive>, option = 0}, {cmd = 0x81051c8\n\"verify-tag\",\n    fn = 0x80a0353 <cmd_verify_tag>, option = 1}, {cmd = 0x81051d3 \"version\",\n    fn = 0x80c5376 <cmd_version>, option = 0}, {cmd = 0x81051db \"whatchanged\",\n    fn = 0x80764c0 <cmd_whatchanged>, option = 3}, {cmd = 0x81051e7\n\"write-tree\",\n    fn = 0x80a0434 <cmd_write_tree>, option = 1}, {cmd = 0x81051f2\n\"verify-pack\",\n    fn = 0x809ff24 <cmd_verify_pack>, option = 0}, {cmd = 0x81051fe \"show-ref\",\n    fn = 0x809a0cc <cmd_show_ref>, option = 1}, {cmd = 0x8105207 \"pack-refs\",\n    fn = 0x808b2e8 <cmd_pack_refs>, option = 1}}\n\text = \"\"\n#12 0x0804bfea in main (argc=1, argv=0xafc2d578) at git.c:500\n\tcmd = 0xafc2eb89 \"fotch\"\n\tslash = 0xafc2eb85 \"git\"\n\tdone_alias = 0\n\n-- \nMikael Magnusson\n"},{"id":"89212","messageId":"7vsksm1pmd.fsf@gitster.siamese.dyndns.org","threadId":"15253","inReplyTo":"20080828212722.GF6439@steel.home","subject":"Re: [PATCH updated] git wrapper: DWIM mistyped commands","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-30T15:36:42Z","receivedAt":"2008-08-30T15:36:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alex Riesen <raa.lkml@gmail.com> writes:\n\n> @@ -257,9 +258,70 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)\n> ...\n> +static const char *levenshtein_cmd;\n> +static int similarity(const char *cmd) {\n> +\treturn levenshtein(levenshtein_cmd, cmd, 0, 2, 1, 4);\n> +}\n> +\n> +static int levenshtein_compare(const void *p1, const void *p2)\n>  {\n> +\tconst struct cmdname *const *c1 = p1, *const *c2 = p2;\n> +\tconst char *s1 = (*c1)->name, *s2 = (*c2)->name;\n> +\tint l1 = similarity(s1);\n> +\tint l2 = similarity(s2);\n> +\treturn l1 != l2 ? l1 - l2 : strcmp(s1, s2);\n> +}\n> ...\n> +\tlevenshtein_cmd = cmd;\n> +\tqsort(main_cmds.names, main_cmds.cnt,\n> +\t      sizeof(*main_cmds.names), levenshtein_compare);\n\nIsn't this awfully inefficient?\n\nYou have one mistyped command name to compute distance against, and want\nto sort the available 100+ command names by that distance.  In qsort(),\nlevenshtein_compare() will be called O(N log N) times (depending on your\nqsort implementation)?\n\nI wonder if it makes sense to give an otherwise unused \"score\" member to\nthe \"struct cmdname\", compute the distance only once per each command, and\nuse that as the sort key (alternatively you can have a separate int[N]\narray to store similarity values for each item in the cmdnames list, only\nused inside this codepath).\n"},{"id":"89218","messageId":"81b0412b0808300944p29199600ie95c65404b6cb380@mail.gmail.com","threadId":"15253","inReplyTo":"7vsksm1pmd.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH updated] git wrapper: DWIM mistyped commands","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-08-30T16:44:15Z","receivedAt":"2008-08-30T16:44:15Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"2008/8/30 Junio C Hamano <gitster@pobox.com>:\n>> +static int levenshtein_compare(const void *p1, const void *p2)\n>>  {\n>> +     const struct cmdname *const *c1 = p1, *const *c2 = p2;\n>> +     const char *s1 = (*c1)->name, *s2 = (*c2)->name;\n>> +     int l1 = similarity(s1);\n>> +     int l2 = similarity(s2);\n>> +     return l1 != l2 ? l1 - l2 : strcmp(s1, s2);\n>> +}\n>> ...\n>> +     levenshtein_cmd = cmd;\n>> +     qsort(main_cmds.names, main_cmds.cnt,\n>> +           sizeof(*main_cmds.names), levenshtein_compare);\n>\n> Isn't this awfully inefficient?\n>\n> You have one mistyped command name to compute distance against, and want\n> to sort the available 100+ command names by that distance.  In qsort(),\n> levenshtein_compare() will be called O(N log N) times (depending on your\n> qsort implementation)?\n\nnot only similarity, but strcmp as well.\n\n> I wonder if it makes sense to give an otherwise unused \"score\" member to\n\nHmm, it is a _non-existing_ member of cmdname, isn't it?\n\n> the \"struct cmdname\", compute the distance only once per each command, and\n> use that as the sort key (alternatively you can have a separate int[N]\n> array to store similarity values for each item in the cmdnames list, only\n> used inside this codepath).\n\nI think I'll take the struct cmdname->len over.\n"},{"id":"89222","messageId":"20080830171331.GA26932@steel.home","threadId":"15253","inReplyTo":"81b0412b0808300944p29199600ie95c65404b6cb380@mail.gmail.com","subject":"[PATCH] Reuse cmdname->len to store pre-calculated similarity indexes","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-08-30T17:13:31Z","receivedAt":"2008-08-30T17:13:31Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"To avoid doing that while sorting\n\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\n---\n\nAlex Riesen, Sat, Aug 30, 2008 18:44:15 +0200:\n> 2008/8/30 Junio C Hamano <gitster@pobox.com>:\n> > I wonder if it makes sense to give an otherwise unused \"score\" member to\n> \n> Hmm, it is a _non-existing_ member of cmdname, isn't it?\n> \n> > the \"struct cmdname\", compute the distance only once per each command, and\n> > use that as the sort key (alternatively you can have a separate int[N]\n> > array to store similarity values for each item in the cmdnames list, only\n> > used inside this codepath).\n> \n> I think I'll take the struct cmdname->len over.\n\n help.c |   12 +++++++-----\n 1 files changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 7bfbbcd..70d57a3 100644\n--- a/help.c\n+++ b/help.c\n@@ -287,8 +287,8 @@ static int levenshtein_compare(const void *p1, const void *p2)\n {\n \tconst struct cmdname *const *c1 = p1, *const *c2 = p2;\n \tconst char *s1 = (*c1)->name, *s2 = (*c2)->name;\n-\tint l1 = similarity(s1);\n-\tint l2 = similarity(s2);\n+\tint l1 = (*c1)->len;\n+\tint l2 = (*c2)->len;\n \treturn l1 != l2 ? l1 - l2 : strcmp(s1, s2);\n }\n \n@@ -312,6 +312,9 @@ const char *help_unknown_cmd(const char *cmd)\n \tmemcpy(main_cmds.names + main_cmds.cnt, other_cmds.names,\n \t\tother_cmds.cnt * sizeof(other_cmds.names[0]));\n \tmain_cmds.cnt += other_cmds.cnt;\n+\t/* This reuses cmdname->len for similarity index */\n+\tfor (i = 0; i < main_cmds.cnt; ++i)\n+\t\tmain_cmds.names[i]->len = similarity(main_cmds.names[i]->name);\n \n \tlevenshtein_cmd = cmd;\n \tqsort(main_cmds.names, main_cmds.cnt,\n@@ -319,10 +322,9 @@ const char *help_unknown_cmd(const char *cmd)\n \n \tif (!main_cmds.cnt)\n \t\tdie (\"Uh oh.  Your system reports no Git commands at all.\");\n-\tbest_similarity = similarity(main_cmds.names[0]->name);\n+\tbest_similarity = main_cmds.names[0]->len;\n \tn = 1;\n-\twhile (n < main_cmds.cnt &&\n-\t\tbest_similarity == similarity(main_cmds.names[n]->name))\n+\twhile (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)\n \t\t++n;\n \tif (autocorrect && n == 1) {\n \t\tconst char *assumed;\n-- \n1.6.0.1.149.g9ecb0\n"},{"id":"89224","messageId":"7vprnqifd2.fsf@gitster.siamese.dyndns.org","threadId":"15253","inReplyTo":"20080830171331.GA26932@steel.home","subject":"Re: [PATCH] Reuse cmdname->len to store pre-calculated similarity indexes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-30T17:26:17Z","receivedAt":"2008-08-30T17:26:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alex Riesen <raa.lkml@gmail.com> writes:\n\n> To avoid doing that while sorting\n>\n> Signed-off-by: Alex Riesen <raa.lkml@gmail.com>\n> ---\n>\n> Alex Riesen, Sat, Aug 30, 2008 18:44:15 +0200:\n>> 2008/8/30 Junio C Hamano <gitster@pobox.com>:\n>> > I wonder if it makes sense to give an otherwise unused \"score\" member to\n>> \n>> Hmm, it is a _non-existing_ member of cmdname, isn't it?\n>> \n>> > the \"struct cmdname\", compute the distance only once per each command, and\n>> > use that as the sort key (alternatively you can have a separate int[N]\n>> > array to store similarity values for each item in the cmdnames list, only\n>> > used inside this codepath).\n>> \n>> I think I'll take the struct cmdname->len over.\n\nI think you do not need the file-scope static levenshtein_cmd anymore with\nthis change, if you make similarity() take two command names.  No?\n\nPlease reroll the whole f66dd34 (git wrapper: DWIM mistyped commands,\n2008-08-28), as it is not part of any solid integration branch yet.\n\nYou might also want to update the commit log message to talk about the\n\"len\" reuse hack, but you already have in-code comment which might be\nsufficient.\n"},{"id":"89272","messageId":"a2075f4c0808301517m1df72e85j5a0de23c04c7f6ae@mail.gmail.com","threadId":"15253","inReplyTo":"a2075f4c0808301510g1af01b14kd58da12dc2e80f93@mail.gmail.com","subject":"Re: [PATCH updated] git wrapper: DWIM mistyped commands","fromName":"Felipe Carvalho Oliveira","fromEmail":"felipekde@gmail.com","sentAt":"2008-08-30T22:17:11Z","receivedAt":"2008-08-30T22:17:11Z","isPatch":true,"sender":{"key":"felipekde@gmail.com","avatar":"https://gravatar.com/avatar/d3b0d3f3e680016d92159d539a9fcae3057490722dac4e206176bd4cf7e20e1b?d=mp&s=160"},"body":"> From: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n>\n> This patch introduces a modified Damerau-Levenshtein algorithm into\n> Git's code base, and uses it with the following penalties to show some\n> similar commands when an unknown command was encountered:\n\n Thanks so much by implement this. Few weeks ago I had thought about this.\n\n  Felipe(from Brazil)\n"},{"id":"89312","messageId":"20080831135023.GA6616@blimp.local","threadId":"15253","inReplyTo":"7vprnqifd2.fsf@gitster.siamese.dyndns.org","subject":"[PATCH] git wrapper: DWIM mistyped commands","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-08-31T13:50:23Z","receivedAt":"2008-08-31T13:50:23Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"From: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n\nThis patch introduces a modified Damerau-Levenshtein algorithm into\nGit's code base, and uses it with the following penalties to show some\nsimilar commands when an unknown command was encountered:\n\n\tswap = 0, insertion = 1, substitution = 2, deletion = 4\n\nA typical output would now look like this:\n\n\t$ git sm\n\tgit: 'sm' is not a git-command. See 'git --help'.\n\n\tDid you mean one of these?\n\t\tam\n\t\trm\n\nThe cut-off is at similarity rating 6, which was empirically determined\nto give sensible results.\n\nAs a convenience, if there is only one candidate, Git continues under\nthe assumption that the user mistyped it.  Example:\n\n\t$ git reabse\n\tWARNING: You called a Git program named 'reabse', which does\n\tnot exist.\n\tContinuing under the assumption that you meant 'rebase'\n\t[...]\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\n---\n\nJunio C Hamano, Sat, Aug 30, 2008 19:26:17 +0200:\n> I think you do not need the file-scope static levenshtein_cmd anymore with\n> this change, if you make similarity() take two command names.  No?\n\nYes :)\n\n> Please reroll the whole f66dd34 (git wrapper: DWIM mistyped commands,\n> 2008-08-28), as it is not part of any solid integration branch yet.\n\nI think I better reroll (now) both\n\n> You might also want to update the commit log message to talk about the\n> \"len\" reuse hack, but you already have in-code comment which might be\n> sufficient.\n\nI believe it is (and I added one against the member in the\ndeclaration)\n\nMikael, this also might fix the crash you're seeing: the heap was\ncorrupted by clean_cmdnames(&other_cmds) names members of which were\nmoved to main_cmds.\n\n Makefile      |    2 +\n builtin.h     |    2 +-\n git.c         |    4 ++-\n help.c        |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n help.h        |    2 +-\n levenshtein.c |   47 +++++++++++++++++++++++++++++++++++++\n levenshtein.h |    8 ++++++\n 7 files changed, 133 insertions(+), 4 deletions(-)\n create mode 100644 levenshtein.c\n create mode 100644 levenshtein.h\n\ndiff --git a/Makefile b/Makefile\nindex bf400e6..3daa6dc 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -358,6 +358,7 @@ LIB_H += graph.h\n LIB_H += grep.h\n LIB_H += hash.h\n LIB_H += help.h\n+LIB_H += levenshtein.h\n LIB_H += list-objects.h\n LIB_H += ll-merge.h\n LIB_H += log-tree.h\n@@ -433,6 +434,7 @@ LIB_OBJS += hash.o\n LIB_OBJS += help.o\n LIB_OBJS += ident.o\n LIB_OBJS += interpolate.o\n+LIB_OBJS += levenshtein.o\n LIB_OBJS += list-objects.o\n LIB_OBJS += ll-merge.o\n LIB_OBJS += lockfile.o\ndiff --git a/builtin.h b/builtin.h\nindex f3502d3..e67cb20 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -11,7 +11,7 @@ extern const char git_usage_string[];\n extern const char git_more_info_string[];\n \n extern void list_common_cmds_help(void);\n-extern void help_unknown_cmd(const char *cmd);\n+extern const char *help_unknown_cmd(const char *cmd);\n extern void prune_packed_objects(int);\n extern int read_line_with_nul(char *buf, int size, FILE *file);\n extern int fmt_merge_msg(int merge_summary, struct strbuf *in,\ndiff --git a/git.c b/git.c\nindex 37b1d76..54c5bfa 100644\n--- a/git.c\n+++ b/git.c\n@@ -499,7 +499,9 @@ int main(int argc, const char **argv)\n \t\t\t\tcmd, argv[0]);\n \t\t\texit(1);\n \t\t}\n-\t\thelp_unknown_cmd(cmd);\n+\t\targv[0] = help_unknown_cmd(cmd);\n+\t\thandle_internal_command(argc, argv);\n+\t\texecv_dashed_external(argv);\n \t}\n \n \tfprintf(stderr, \"Failed to run command '%s': %s\\n\",\ndiff --git a/help.c b/help.c\nindex b278257..aaba809 100644\n--- a/help.c\n+++ b/help.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n+#include \"levenshtein.h\"\n #include \"help.h\"\n \n /* most GUI terminals set COLUMNS (although some don't export it) */\n@@ -37,6 +38,16 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n \tcmds->names[cmds->cnt++] = ent;\n }\n \n+static void clean_cmdnames(struct cmdnames *cmds)\n+{\n+\tint i;\n+\tfor (i = 0; i < cmds->cnt; ++i)\n+\t\tfree(cmds->names[i]);\n+\tfree(cmds->names);\n+\tcmds->cnt = 0;\n+\tcmds->alloc = 0;\n+}\n+\n static int cmdname_compare(const void *a_, const void *b_)\n {\n \tstruct cmdname *a = *(struct cmdname **)a_;\n@@ -250,9 +261,68 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)\n \treturn 0;\n }\n \n-void help_unknown_cmd(const char *cmd)\n+static int levenshtein_compare(const void *p1, const void *p2)\n+{\n+\tconst struct cmdname *const *c1 = p1, *const *c2 = p2;\n+\tconst char *s1 = (*c1)->name, *s2 = (*c2)->name;\n+\tint l1 = (*c1)->len;\n+\tint l2 = (*c2)->len;\n+\treturn l1 != l2 ? l1 - l2 : strcmp(s1, s2);\n+}\n+\n+const char *help_unknown_cmd(const char *cmd)\n {\n+\tint i, n, best_similarity = 0;\n+\tstruct cmdnames main_cmds, other_cmds;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(main_cmds));\n+\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tALLOC_GROW(main_cmds.names, main_cmds.cnt + other_cmds.cnt,\n+\t\t   main_cmds.alloc);\n+\tmemcpy(main_cmds.names + main_cmds.cnt, other_cmds.names,\n+\t       other_cmds.cnt * sizeof(other_cmds.names[0]));\n+\tmain_cmds.cnt += other_cmds.cnt;\n+\tfree(other_cmds.names);\n+\n+\t/* This reuses cmdname->len for similarity index */\n+\tfor (i = 0; i < main_cmds.cnt; ++i)\n+\t\tmain_cmds.names[i]->len =\n+\t\t\tlevenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);\n+\n+\tqsort(main_cmds.names, main_cmds.cnt,\n+\t      sizeof(*main_cmds.names), levenshtein_compare);\n+\n+\tif (!main_cmds.cnt)\n+\t\tdie (\"Uh oh. Your system reports no Git commands at all.\");\n+\n+\tbest_similarity = main_cmds.names[0]->len;\n+\tn = 1;\n+\twhile (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)\n+\t\t++n;\n+\tif (n == 1) {\n+\t\tconst char *assumed = main_cmds.names[0]->name;\n+\t\tmain_cmds.names[0] = NULL;\n+\t\tclean_cmdnames(&main_cmds);\n+\t\tfprintf(stderr, \"WARNING: You called a Git program named '%s', \"\n+\t\t\t\"which does not exist.\\n\"\n+\t\t\t\"Continuing under the assumption that you meant '%s'\\n\",\n+\t\t\tcmd, assumed);\n+\t\treturn assumed;\n+\t}\n+\n \tfprintf(stderr, \"git: '%s' is not a git-command. See 'git --help'.\\n\", cmd);\n+\n+\tif (best_similarity < 6) {\n+\t\tfprintf(stderr, \"\\nDid you mean %s?\\n\",\n+\t\t\tn < 2 ? \"this\": \"one of these\");\n+\n+\t\tfor (i = 0; i < n; i++)\n+\t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n+\t}\n+\n \texit(1);\n }\n \ndiff --git a/help.h b/help.h\nindex 2733433..56bc154 100644\n--- a/help.h\n+++ b/help.h\n@@ -5,7 +5,7 @@ struct cmdnames {\n \tint alloc;\n \tint cnt;\n \tstruct cmdname {\n-\t\tsize_t len;\n+\t\tsize_t len; /* also used for similarity index in help.c */\n \t\tchar name[FLEX_ARRAY];\n \t} **names;\n };\ndiff --git a/levenshtein.c b/levenshtein.c\nnew file mode 100644\nindex 0000000..db52f2c\n--- /dev/null\n+++ b/levenshtein.c\n@@ -0,0 +1,47 @@\n+#include \"cache.h\"\n+#include \"levenshtein.h\"\n+\n+int levenshtein(const char *string1, const char *string2,\n+\t\tint w, int s, int a, int d)\n+{\n+\tint len1 = strlen(string1), len2 = strlen(string2);\n+\tint *row0 = xmalloc(sizeof(int) * (len2 + 1));\n+\tint *row1 = xmalloc(sizeof(int) * (len2 + 1));\n+\tint *row2 = xmalloc(sizeof(int) * (len2 + 1));\n+\tint i, j;\n+\n+\tfor (j = 0; j <= len2; j++)\n+\t\trow1[j] = j * a;\n+\tfor (i = 0; i < len1; i++) {\n+\t\tint *dummy;\n+\n+\t\trow2[0] = (i + 1) * d;\n+\t\tfor (j = 0; j < len2; j++) {\n+\t\t\t/* substitution */\n+\t\t\trow2[j + 1] = row1[j] + s * (string1[i] != string2[j]);\n+\t\t\t/* swap */\n+\t\t\tif (i > 0 && j > 0 && string1[i - 1] == string2[j] &&\n+\t\t\t\t\tstring1[i] == string2[j - 1] &&\n+\t\t\t\t\trow2[j + 1] > row0[j - 1] + w)\n+\t\t\t\trow2[j + 1] = row0[j - 1] + w;\n+\t\t\t/* deletion */\n+\t\t\tif (j + 1 < len2 && row2[j + 1] > row1[j + 1] + d)\n+\t\t\t\trow2[j + 1] = row1[j + 1] + d;\n+\t\t\t/* insertion */\n+\t\t\tif (row2[j + 1] > row2[j] + a)\n+\t\t\t\trow2[j + 1] = row2[j] + a;\n+\t\t}\n+\n+\t\tdummy = row0;\n+\t\trow0 = row1;\n+\t\trow1 = row2;\n+\t\trow2 = dummy;\n+\t}\n+\n+\ti = row1[len2];\n+\tfree(row0);\n+\tfree(row1);\n+\tfree(row2);\n+\n+\treturn i;\n+}\ndiff --git a/levenshtein.h b/levenshtein.h\nnew file mode 100644\nindex 0000000..0173abe\n--- /dev/null\n+++ b/levenshtein.h\n@@ -0,0 +1,8 @@\n+#ifndef LEVENSHTEIN_H\n+#define LEVENSHTEIN_H\n+\n+int levenshtein(const char *string1, const char *string2,\n+\tint swap_penalty, int substition_penalty,\n+\tint insertion_penalty, int deletion_penalty);\n+\n+#endif\n-- \n1.6.0.1.168.gdf6f0\n"},{"id":"89314","messageId":"20080831135458.GB6616@blimp.local","threadId":"15253","inReplyTo":"20080831135023.GA6616@blimp.local","subject":"[PATCH] Add help.autocorrect to enable/disable autocorrecting","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-08-31T13:54:58Z","receivedAt":"2008-08-31T13:54:58Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"It is off(0) by default, to avoid scaring people unless they asked to.\nIf set to a non-0 value, wait for that amount of deciseconds before\nrunning the corrected command.\n\nSuggested by Junio, so he has a chance to hit Ctrl-C.\n\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\n---\nAlex Riesen, Sun, Aug 31, 2008 15:50:23 +0200:\n> Junio C Hamano, Sat, Aug 30, 2008 19:26:17 +0200:\n> > Please reroll the whole f66dd34 (git wrapper: DWIM mistyped commands,\n> > 2008-08-28), as it is not part of any solid integration branch yet.\n> \n> I think I better reroll (now) both\n> \n\n Documentation/config.txt |    9 +++++++++\n help.c                   |   19 ++++++++++++++++++-\n 2 files changed, 27 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex af57d94..8c644ab 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -790,6 +790,15 @@ help.format::\n \tValues 'man', 'info', 'web' and 'html' are supported. 'man' is\n \tthe default. 'web' and 'html' are the same.\n \n+help.autocorrect::\n+\tAutomatically correct and execute mistyped commands after\n+\twaiting for the given number of deciseconds (0.1 sec). If more\n+\tthan one command can be deduced from the entered text, nothing\n+\twill be executed.  If the value of this option is negative,\n+\tthe corrected command will be executed immediately. If the\n+\tvalue is 0 - the command will be just shown but not executed.\n+\tThis is the default.\n+\n http.proxy::\n \tOverride the HTTP proxy, normally configured using the 'http_proxy'\n \tenvironment variable (see linkgit:curl[1]).  This can be overridden\ndiff --git a/help.c b/help.c\nindex aaba809..300cd38 100644\n--- a/help.c\n+++ b/help.c\n@@ -261,6 +261,16 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)\n \treturn 0;\n }\n \n+static int autocorrect;\n+\n+static int git_unknown_cmd_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"help.autocorrect\"))\n+\t\tautocorrect = git_config_int(var,value);\n+\n+\treturn git_default_config(var, value, cb);\n+}\n+\n static int levenshtein_compare(const void *p1, const void *p2)\n {\n \tconst struct cmdname *const *c1 = p1, *const *c2 = p2;\n@@ -278,6 +288,8 @@ const char *help_unknown_cmd(const char *cmd)\n \tmemset(&main_cmds, 0, sizeof(main_cmds));\n \tmemset(&other_cmds, 0, sizeof(main_cmds));\n \n+\tgit_config(git_unknown_cmd_config, NULL);\n+\n \tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \n \tALLOC_GROW(main_cmds.names, main_cmds.cnt + other_cmds.cnt,\n@@ -302,7 +314,7 @@ const char *help_unknown_cmd(const char *cmd)\n \tn = 1;\n \twhile (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)\n \t\t++n;\n-\tif (n == 1) {\n+\tif (autocorrect && n == 1) {\n \t\tconst char *assumed = main_cmds.names[0]->name;\n \t\tmain_cmds.names[0] = NULL;\n \t\tclean_cmdnames(&main_cmds);\n@@ -310,6 +322,11 @@ const char *help_unknown_cmd(const char *cmd)\n \t\t\t\"which does not exist.\\n\"\n \t\t\t\"Continuing under the assumption that you meant '%s'\\n\",\n \t\t\tcmd, assumed);\n+\t\tif (autocorrect > 0) {\n+\t\t\tfprintf(stderr, \"in %0.1f seconds automatically...\\n\",\n+\t\t\t\t(float)autocorrect/10.0);\n+\t\t\tpoll(NULL, 0, autocorrect * 100);\n+\t\t}\n \t\treturn assumed;\n \t}\n \n-- \n1.6.0.1.168.gdf6f0\n"},{"id":"89315","messageId":"20080831135717.GA25984@blimp.local","threadId":"15253","inReplyTo":"237967ef0808300333t2cd4e354xd461f7bfead40f4c@mail.gmail.com","subject":"Re: [PATCH updated] git wrapper: DWIM mistyped commands","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-08-31T13:57:17Z","receivedAt":"2008-08-31T13:57:17Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"Mikael Magnusson, Sat, Aug 30, 2008 12:33:26 +0200:\n> 2008/8/30 Alex Riesen <raa.lkml@gmail.com>:\n> > 2008/8/29 Mikael Magnusson <mikachu@gmail.com>:\n> >> I merged the branch in pu into next, which I think should work, but I get\n> >> these segfaults for some commands... I tried running in gdb but even with\n> >\n> > Can't reproduce in master, will try with next later, am busy right now, sorry.\n> >\n> >> -g3 I only get nonsense backtraces, not sure why.\n> >\n> > Remove -O2 from CFLAGS:\n> >\n> >  $ make CFLAGS=\"-O0 -ggdb\"\n> \n> Hm, I only had CFLAGS set in the env, maybe that's not enough, or maybe it\n\nThe make variables set in Makefile take precedence over the variables\nwith same names in environment (see make(1), \"-e\" option).\n\n> was that I had it set to -gdwarf-2 -g3 instead of -ggdb3. At any rate, I got\n> this now:\n> \n> % git fotch\n> Program received signal SIGSEGV, Segmentation fault.\n> [Switching to Thread 0xa7ce56c0 (LWP 13043)]\n> 0x41b61490 in ?? () from /lib/libc.so.6\n> (gdb) bt\n> #0  0x41b61490 in ?? () from /lib/libc.so.6\n> #1  0x41b634b0 in realloc () from /lib/libc.so.6\n> #2  0x41b62fdb in malloc () from /lib/libc.so.6\n> #3  0x080f63e6 in xmalloc (size=24) at wrapper.c:20\n> #4  0x080f6471 in xmemdupz (data=0x816a44f, len=23) at wrapper.c:45\n> #5  0x080f64e9 in xstrndup (str=0x816a44f \"refs/remotes/origin/man\",\n> len=23) at wrapper.c:54\n> #6  0x080dc05c in parse_refspec_internal (nr_refspec=6,\n> refspec=0x816a010, fetch=1, verify=0)\n>     at remote.c:505\n\nLooks like heap corruption. See that patch I sent today.\n"},{"id":"89318","messageId":"vpqk5dxqlya.fsf@bauges.imag.fr","threadId":"15253","inReplyTo":"20080831135458.GB6616@blimp.local","subject":"Re: [PATCH] Add help.autocorrect to enable/disable autocorrecting","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2008-08-31T14:49:01Z","receivedAt":"2008-08-31T14:49:01Z","isPatch":true,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"Alex Riesen <raa.lkml@gmail.com> writes:\n\n> It is off(0) by default, to avoid scaring people unless they asked to.\n> If set to a non-0 value, wait for that amount of deciseconds before\n> running the corrected command.\n\nPerhaps off should be -1 (or, say, anything negative), so that the\nvalue 0 can be used to mean \"execute the corrected command without\nwaiting\".\n\n(not that I really care personnally, I'd probably keep it off anyway).\n\n-- \nMatthieu\n"},{"id":"89324","messageId":"7v1w05401m.fsf@gitster.siamese.dyndns.org","threadId":"15253","inReplyTo":"vpqk5dxqlya.fsf@bauges.imag.fr","subject":"Re: [PATCH] Add help.autocorrect to enable/disable autocorrecting","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-31T16:33:09Z","receivedAt":"2008-08-31T16:33:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthieu Moy <Matthieu.Moy@imag.fr> writes:\n\n> Alex Riesen <raa.lkml@gmail.com> writes:\n>\n>> It is off(0) by default, to avoid scaring people unless they asked to.\n>> If set to a non-0 value, wait for that amount of deciseconds before\n>> running the corrected command.\n>\n> Perhaps off should be -1 (or, say, anything negative), so that the\n> value 0 can be used to mean \"execute the corrected command without\n> waiting\".\n>\n> (not that I really care personnally, I'd probably keep it off anyway).\n\nI do not want to suggest this because I do not think of a good way to\nimplement it myself, but it would be very nice if this feature can be\nenabled by default for interactive session and disabled for scripts.\n\nWell, actually I think I do ;-)\n\nPerhaps have a bash alias that does:\n\n\talias git=\"git --dwim\"\n\nonly in interactive session (ensuring \"only in interactive\" is the\nresponsibility of the end user), with the global option similar to\nthe \"--paginate\" that \"git\" wrapper itself takes?\n"},{"id":"89420","messageId":"237967ef0809010742w43de9e3dj28880de484e8c48d@mail.gmail.com","threadId":"15253","inReplyTo":"20080831135023.GA6616@blimp.local","subject":"Re: [PATCH] git wrapper: DWIM mistyped commands","fromName":"Mikael Magnusson","fromEmail":"mikachu@gmail.com","sentAt":"2008-09-01T14:42:44Z","receivedAt":"2008-09-01T14:42:44Z","isPatch":true,"sender":{"key":"mikachu@gmail.com","avatar":null},"body":"2008/8/31 Alex Riesen <raa.lkml@gmail.com>:\n> From: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n>\n> This patch introduces a modified Damerau-Levenshtein algorithm into\n> Git's code base, and uses it with the following penalties to show some\n> similar commands when an unknown command was encountered:\n>\n>        swap = 0, insertion = 1, substitution = 2, deletion = 4\n>\n> A typical output would now look like this:\n>\n>        $ git sm\n>        git: 'sm' is not a git-command. See 'git --help'.\n>\n>        Did you mean one of these?\n>                am\n>                rm\n>\n> The cut-off is at similarity rating 6, which was empirically determined\n> to give sensible results.\n>\n> As a convenience, if there is only one candidate, Git continues under\n> the assumption that the user mistyped it.  Example:\n>\n>        $ git reabse\n>        WARNING: You called a Git program named 'reabse', which does\n>        not exist.\n>        Continuing under the assumption that you meant 'rebase'\n>        [...]\n\n> Mikael, this also might fix the crash you're seeing: the heap was\n> corrupted by clean_cmdnames(&other_cmds) names members of which were\n> moved to main_cmds.\n\nIt doesn't crash now, but the cut-off appears ineffective:\n% git aaaaaaaaaaaaaaa\nWARNING: You called a Git program named 'aaaaaaaaaaaaaaa', which does not exist.\nContinuing under the assumption that you meant 'add--interactive'\nin 2.0 seconds automatically...\n\nBy my estimate, that should have a score above 6 :).\n\n-- \nMikael Magnusson\n"},{"id":"90050","messageId":"7vbpyzgmgq.fsf@gitster.siamese.dyndns.org","threadId":"15253","inReplyTo":"20080828212815.GG6439@steel.home","subject":"Re: [PATCH] Add help.autocorrect to enable/disable autocorrecting","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-08T06:50:45Z","receivedAt":"2008-09-08T06:50:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alex Riesen <raa.lkml@gmail.com> writes:\n\n> It is off(0) by default, to avoid scaring people unless they asked to.\n\nI do not think this is off by default, by the way.  \"off by default\" means\nthat you would not waste extra cycles to compute the list of suggestions.\n\nI am not suggesting that it should be \"off\" by default in that sense,\nthough.  I am just pointing out that it is not described correctly.\n\nI also noticed that this does not seem to pay attention to mistyped\naliases.  Is it by design, oversight, or lazyness?\n"}]}