{"thread":{"id":"25818","subject":"bug: unexpected output for \"git st\" + suggestion","startedAt":"2010-11-23T12:23:17Z","lastAt":"2018-11-20T03:24:07Z","messageCount":27,"participants":["Tarek Ziadé","Nguyen Thai Ngoc Duy","Sylvain Rabot","Erik Faye-Lund","Andreas Schwab","Junio C Hamano","Jonathan Nieder","Ævar Arnfjörð Bjarmason"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"156369","messageId":"AANLkTimdKoGHapMTrA-bf_mEyMAEiiM0ALvLbZX8QJpv@mail.gmail.com","threadId":"25818","inReplyTo":null,"subject":"bug: unexpected output for \"git st\" + suggestion","fromName":"Tarek Ziadé","fromEmail":"ziade.tarek@gmail.com","sentAt":"2010-11-23T12:23:17Z","receivedAt":"2010-11-23T12:23:17Z","isPatch":false,"sender":{"key":"ziade.tarek@gmail.com","avatar":null},"body":"Hello,\n\nI am new to Git and I tried to run \"git st\"\n\nI have found one small bug: \"status\" is not listed in the help screen\nGit displays in that case.\n\n$ git st\ngit: 'st' is not a git command. See 'git --help'.\n\nDid you mean one of these?\n\treset\n\tstage\n\tstash\n\n\nI also have a suggestion: I was looking for the way to report that bug\nby visiting http://git-scm.com/ and looking for the bug tracker.\nSomeone eventually explained to me on the IRC channel that I had to\npost a mail here. I would suggest making it clear on how to report\nbugs on the project's website. Maybe under  \"Got a question\" /\n\"Email\".\n\nCheers\nTarek\n\n-- \nTarek Ziadé | http://ziade.org\n"},{"id":"156372","messageId":"AANLkTinFMn4V3c3yV6j72eqj5=v4jW7Uh3fmNDOyYjnT@mail.gmail.com","threadId":"25818","inReplyTo":"AANLkTimdKoGHapMTrA-bf_mEyMAEiiM0ALvLbZX8QJpv@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-11-23T12:40:57Z","receivedAt":"2010-11-23T12:40:57Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Nov 23, 2010 at 7:23 PM, Tarek Ziadé <ziade.tarek@gmail.com> wrote:\n> Hello,\n>\n> I am new to Git and I tried to run \"git st\"\n>\n> I have found one small bug: \"status\" is not listed in the help screen\n> Git displays in that case.\n>\n> $ git st\n> git: 'st' is not a git command. See 'git --help'.\n>\n> Did you mean one of these?\n>        reset\n>        stage\n>        stash\n\nIt's heuristics, based on the assumption that you mistype a command by\na letter or two. It gives helpful suggestions most of the time, but\nyou can't expect it to be always right, especially when \"st\" is not a\nmistyping. \"git --help\" does show \"status\" though so I guess it's ok.\n-- \nDuy\n"},{"id":"156373","messageId":"1290516191.21750.17.camel@isis.agematis.loc","threadId":"25818","inReplyTo":"AANLkTimdKoGHapMTrA-bf_mEyMAEiiM0ALvLbZX8QJpv@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Sylvain Rabot","fromEmail":"sylvain@abstraction.fr","sentAt":"2010-11-23T12:43:11Z","receivedAt":"2010-11-23T12:43:11Z","isPatch":false,"sender":{"key":"sylvain@abstraction.fr","avatar":"https://avatars.githubusercontent.com/u/153052?v=4"},"body":"Hi,\n\n\"st\" does not exist in git. You have to create an alias yourself by\ndoing this :\n\n$ git config --global --add alias.st status\n\nRegards\n\nOn Tue, 2010-11-23 at 13:23 +0100, Tarek Ziadé wrote:\n> Hello,\n> \n> I am new to Git and I tried to run \"git st\"\n> \n> I have found one small bug: \"status\" is not listed in the help screen\n> Git displays in that case.\n> \n> $ git st\n> git: 'st' is not a git command. See 'git --help'.\n> \n> Did you mean one of these?\n> \treset\n> \tstage\n> \tstash\n> \n> \n> I also have a suggestion: I was looking for the way to report that bug\n> by visiting http://git-scm.com/ and looking for the bug tracker.\n> Someone eventually explained to me on the IRC channel that I had to\n> post a mail here. I would suggest making it clear on how to report\n> bugs on the project's website. Maybe under  \"Got a question\" /\n> \"Email\".\n> \n> Cheers\n> Tarek\n> \n"},{"id":"156375","messageId":"AANLkTinj3ryChGKV8c6fHSD=aickmz0TMos4k0RYGKvo@mail.gmail.com","threadId":"25818","inReplyTo":"AANLkTinFMn4V3c3yV6j72eqj5=v4jW7Uh3fmNDOyYjnT@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Tarek Ziadé","fromEmail":"ziade.tarek@gmail.com","sentAt":"2010-11-23T12:49:24Z","receivedAt":"2010-11-23T12:49:24Z","isPatch":false,"sender":{"key":"ziade.tarek@gmail.com","avatar":null},"body":"On Tue, Nov 23, 2010 at 1:40 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:\n> On Tue, Nov 23, 2010 at 7:23 PM, Tarek Ziadé <ziade.tarek@gmail.com> wrote:\n>> Hello,\n>>\n>> I am new to Git and I tried to run \"git st\"\n>>\n>> I have found one small bug: \"status\" is not listed in the help screen\n>> Git displays in that case.\n>>\n>> $ git st\n>> git: 'st' is not a git command. See 'git --help'.\n>>\n>> Did you mean one of these?\n>>        reset\n>>        stage\n>>        stash\n>\n> It's heuristics, based on the assumption that you mistype a command by\n> a letter or two.\n> It gives helpful suggestions most of the time, but\n> you can't expect it to be always right, especially when \"st\" is not a\n> mistyping. \"git --help\" does show \"status\" though so I guess it's ok.\n\nYes, I understood this, but given the list of base commands git comes\nwith, if \"st\" gives \"stage\" and \"stash\", it would find it logical to\ngive also \"status\", by listing commands that starts with 'st'\n\nst\nstage\nstash\nstatus\n\nThat's what the tab completion does:\n\n$ git st<tab>\nstage    stash    status\n\n\nCheers\nTarek\n\n> --\n> Duy\n>\n\n\n\n-- \nTarek Ziadé | http://ziade.org\n"},{"id":"156378","messageId":"AANLkTikxMXRiCYE=ny1tfrS64P0ywAHP_9eLJJzNUG3Q@mail.gmail.com","threadId":"25818","inReplyTo":"AANLkTinj3ryChGKV8c6fHSD=aickmz0TMos4k0RYGKvo@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-11-23T13:08:07Z","receivedAt":"2010-11-23T13:08:07Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Nov 23, 2010 at 7:49 PM, Tarek Ziadé <ziade.tarek@gmail.com> wrote:\n> On Tue, Nov 23, 2010 at 1:40 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:\n>> On Tue, Nov 23, 2010 at 7:23 PM, Tarek Ziadé <ziade.tarek@gmail.com> wrote:\n>>> Hello,\n>>>\n>>> I am new to Git and I tried to run \"git st\"\n>>>\n>>> I have found one small bug: \"status\" is not listed in the help screen\n>>> Git displays in that case.\n>>>\n>>> $ git st\n>>> git: 'st' is not a git command. See 'git --help'.\n>>>\n>>> Did you mean one of these?\n>>>        reset\n>>>        stage\n>>>        stash\n>>\n>> It's heuristics, based on the assumption that you mistype a command by\n>> a letter or two.\n>> It gives helpful suggestions most of the time, but\n>> you can't expect it to be always right, especially when \"st\" is not a\n>> mistyping. \"git --help\" does show \"status\" though so I guess it's ok.\n>\n> Yes, I understood this, but given the list of base commands git comes\n> with, if \"st\" gives \"stage\" and \"stash\", it would find it logical to\n> give also \"status\", by listing commands that starts with 'st'\n>\n> st\n> stage\n> stash\n> status\n\nThere's another command that starts with \"st\": stripspace (it's a\nlowlevel command by the way). It's going to be a lot more if you type\n\"git m\" and expect all commands starting with 'm'. Personally I would\ndo \"git help -a|grep st\" in that case. Hmm.. \"git apropos\" could be a\ngood idea.\n\n> That's what the tab completion does:\n>\n> $ git st<tab>\n> stage    stash    status\n\nAnd it does for tab _completion_ (notice stripspace is missing,\ngit-completion.sh only lists high level commands). The above case is\nto help mistyping.\n-- \nDuy\n"},{"id":"156380","messageId":"AANLkTi=FaZ4MhJ2gDFZGiJVHsuY9jtNGgdWxX3Dq4BY6@mail.gmail.com","threadId":"25818","inReplyTo":"AANLkTikxMXRiCYE=ny1tfrS64P0ywAHP_9eLJJzNUG3Q@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Tarek Ziadé","fromEmail":"ziade.tarek@gmail.com","sentAt":"2010-11-23T13:18:59Z","receivedAt":"2010-11-23T13:18:59Z","isPatch":false,"sender":{"key":"ziade.tarek@gmail.com","avatar":null},"body":"On Tue, Nov 23, 2010 at 2:08 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:\n...\n>\n> There's another command that starts with \"st\": stripspace (it's a\n> lowlevel command by the way). It's going to be a lot more if you type\n> \"git m\" and expect all commands starting with 'm'.\n\nMaybe so yeah. That's how Mercurial does.\n\n$  hg s\nhg: command 's' is ambiguous:\n    serve showconfig status strip summary\n\n\n> Personally I would\n> do \"git help -a|grep st\" in that case. Hmm.. \"git apropos\" could be a\n> good idea.\n\nI guess.\n\n>> That's what the tab completion does:\n>>\n>> $ git st<tab>\n>> stage    stash    status\n>\n> And it does for tab _completion_ (notice stripspace is missing,\n> git-completion.sh only lists high level commands). The above case is\n> to help mistyping.\n\nRight.  Overall, I guess it's just a cultural thing. Using mainly\nMercurial, \"st\" means for me \"status\" so I was surprised not to find\nit as a suggestion.\n\nCheers\nTarek\n\n-- \nTarek Ziadé | http://ziade.org\n"},{"id":"156381","messageId":"AANLkTinvM6OhLdeKt5MqEeNhZJx63X+KzOy_ngEsy0A2@mail.gmail.com","threadId":"25818","inReplyTo":"AANLkTimdKoGHapMTrA-bf_mEyMAEiiM0ALvLbZX8QJpv@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-11-23T13:22:43Z","receivedAt":"2010-11-23T13:22:43Z","isPatch":false,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Tue, Nov 23, 2010 at 1:23 PM, Tarek Ziadé <ziade.tarek@gmail.com> wrote:\n> Hello,\n>\n> I am new to Git and I tried to run \"git st\"\n>\n> I have found one small bug: \"status\" is not listed in the help screen\n> Git displays in that case.\n>\n> $ git st\n> git: 'st' is not a git command. See 'git --help'.\n>\n> Did you mean one of these?\n>        reset\n>        stage\n>        stash\n>\n\nThis isn't strictly speaking a bug. Git uses Levenshtein distance\n(http://en.wikipedia.org/wiki/Levenshtein_distance) to figure out what\nto suggest. If any command has a sLevenshtein distance of less than 6\n(given our coefficients), then all commands with that distance is\nsuggested. But perhaps we should do something different\n\nBut perhaps we could do better. We have some commands that are\nconsidered more \"important\", ie the ones listed when doing \"git help\"\nwithout \"--all\". \"status\" is one of these. Perhaps these commands\nshould always be included if they are below the Levenshtein distance\nthreshold or something?\n"},{"id":"156382","messageId":"AANLkTim72VK6SjtXSK7vAYxAS2p12=Nz73zJy+zEGCnP@mail.gmail.com","threadId":"25818","inReplyTo":"AANLkTi=FaZ4MhJ2gDFZGiJVHsuY9jtNGgdWxX3Dq4BY6@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-11-23T13:26:34Z","receivedAt":"2010-11-23T13:26:34Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Nov 23, 2010 at 8:18 PM, Tarek Ziadé <ziade.tarek@gmail.com> wrote:\n> Right.  Overall, I guess it's just a cultural thing. Using mainly\n> Mercurial, \"st\" means for me \"status\" so I was surprised not to find\n> it as a suggestion.\n\nGit does not have a standard set of aliases like others,\nunfortunately. You may want to set default aliases in ~/.gitconfig\nlike st, ci, co, di, br.. Also look around for fancy aliases like\ngit-lol [1]\n\n[1] http://blog.kfish.org/2010/04/git-lola.html\n-- \nDuy\n"},{"id":"156384","messageId":"AANLkTi=G1ZpiaRN8vWYBJ33_ZOXo1t616X5gQU+jNda_@mail.gmail.com","threadId":"25818","inReplyTo":"AANLkTinvM6OhLdeKt5MqEeNhZJx63X+KzOy_ngEsy0A2@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Tarek Ziadé","fromEmail":"ziade.tarek@gmail.com","sentAt":"2010-11-23T13:47:13Z","receivedAt":"2010-11-23T13:47:13Z","isPatch":false,"sender":{"key":"ziade.tarek@gmail.com","avatar":null},"body":"On Tue, Nov 23, 2010 at 2:22 PM, Erik Faye-Lund <kusmabite@gmail.com> wrote:\n> On Tue, Nov 23, 2010 at 1:23 PM, Tarek Ziadé <ziade.tarek@gmail.com> wrote:\n>> Hello,\n>>\n>> I am new to Git and I tried to run \"git st\"\n>>\n>> I have found one small bug: \"status\" is not listed in the help screen\n>> Git displays in that case.\n>>\n>> $ git st\n>> git: 'st' is not a git command. See 'git --help'.\n>>\n>> Did you mean one of these?\n>>        reset\n>>        stage\n>>        stash\n>>\n>\n> This isn't strictly speaking a bug. Git uses Levenshtein distance\n> (http://en.wikipedia.org/wiki/Levenshtein_distance) to figure out what\n> to suggest. If any command has a sLevenshtein distance of less than 6\n> (given our coefficients), then all commands with that distance is\n> suggested. But perhaps we should do something different\n>\n> But perhaps we could do better. We have some commands that are\n> considered more \"important\", ie the ones listed when doing \"git help\"\n> without \"--all\". \"status\" is one of these. Perhaps these commands\n> should always be included if they are below the Levenshtein distance\n> threshold or something?\n>\n\nOh, interesting ! Levenshtein is great for typos but highly depends on\nthe fact that the word I am entering has about the same length as the\ncommand I am looking for.\n\nWhen I typed \"st\" I was thinking about an alias/shortcut. So the\nquestion would be: is \"st\" a common alias in the git community for the\n\"status\" command ?\n\nIf the answer is yes, and if there are other common aliases used out\nthere, I would suggest keeping the Levenshtein distance as it is now,\nbut complete the list of suggestions by using a \"common aliases\nmapper.\"\n\nCheers\nTarek\n\n-- \nTarek Ziadé | http://ziade.org\n"},{"id":"156385","messageId":"AANLkTinu+Wq84x2H0vB3rUSXbwreumrDC7k2dr5nOfjC@mail.gmail.com","threadId":"25818","inReplyTo":"AANLkTi=G1ZpiaRN8vWYBJ33_ZOXo1t616X5gQU+jNda_@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-11-23T13:56:28Z","receivedAt":"2010-11-23T13:56:28Z","isPatch":false,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Tue, Nov 23, 2010 at 2:47 PM, Tarek Ziadé <ziade.tarek@gmail.com> wrote:\n> On Tue, Nov 23, 2010 at 2:22 PM, Erik Faye-Lund <kusmabite@gmail.com> wrote:\n>> On Tue, Nov 23, 2010 at 1:23 PM, Tarek Ziadé <ziade.tarek@gmail.com> wrote:\n>>> Hello,\n>>>\n>>> I am new to Git and I tried to run \"git st\"\n>>>\n>>> I have found one small bug: \"status\" is not listed in the help screen\n>>> Git displays in that case.\n>>>\n>>> $ git st\n>>> git: 'st' is not a git command. See 'git --help'.\n>>>\n>>> Did you mean one of these?\n>>>        reset\n>>>        stage\n>>>        stash\n>>>\n>>\n>> This isn't strictly speaking a bug. Git uses Levenshtein distance\n>> (http://en.wikipedia.org/wiki/Levenshtein_distance) to figure out what\n>> to suggest. If any command has a sLevenshtein distance of less than 6\n>> (given our coefficients), then all commands with that distance is\n>> suggested. But perhaps we should do something different\n>>\n>> But perhaps we could do better. We have some commands that are\n>> considered more \"important\", ie the ones listed when doing \"git help\"\n>> without \"--all\". \"status\" is one of these. Perhaps these commands\n>> should always be included if they are below the Levenshtein distance\n>> threshold or something?\n>>\n>\n> Oh, interesting ! Levenshtein is great for typos but highly depends on\n> the fact that the word I am entering has about the same length as the\n> command I am looking for.\n>\n> When I typed \"st\" I was thinking about an alias/shortcut. So the\n> question would be: is \"st\" a common alias in the git community for the\n> \"status\" command ?\n>\n> If the answer is yes, and if there are other common aliases used out\n> there, I would suggest keeping the Levenshtein distance as it is now,\n> but complete the list of suggestions by using a \"common aliases\n> mapper.\"\n>\n\nI experimented a bit around, and the last idea I played around with\nwas to keep the Levenshtein-suggestions as-is, but to add all common\ncommands that had the entered command as a prefix. That's a bit more\ngeneric than what you suggested, but also not as flexible as it would\nhave to be a strict prefix.\n"},{"id":"156386","messageId":"AANLkTina0tnOEE2+17W03pFPqg37Btss0HYBeW+pOEgn@mail.gmail.com","threadId":"25818","inReplyTo":"AANLkTinu+Wq84x2H0vB3rUSXbwreumrDC7k2dr5nOfjC@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Tarek Ziadé","fromEmail":"ziade.tarek@gmail.com","sentAt":"2010-11-23T13:58:51Z","receivedAt":"2010-11-23T13:58:51Z","isPatch":false,"sender":{"key":"ziade.tarek@gmail.com","avatar":null},"body":"On Tue, Nov 23, 2010 at 2:56 PM, Erik Faye-Lund <kusmabite@gmail.com> wrote:\n..\n> I experimented a bit around, and the last idea I played around with\n> was to keep the Levenshtein-suggestions as-is, but to add all common\n> commands that had the entered command as a prefix. That's a bit more\n> generic than what you suggested, but also not as flexible as it would\n> have to be a strict prefix.\n\n+1. That would improve it a lot\n"},{"id":"156433","messageId":"1290539473-2420-1-git-send-email-kusmabite@gmail.com","threadId":"25818","inReplyTo":"AANLkTina0tnOEE2+17W03pFPqg37Btss0HYBeW+pOEgn@mail.gmail.com","subject":"[PATCH] help: always suggest common-cmds if prefix of cmd","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-11-23T19:11:13Z","receivedAt":"2010-11-23T19:11:13Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"If someone runs \"git st\", the command \"git status\" is not suggested\nbecause it's not one of the closest levenshtein-neighbour.\n\nReserve the distance of 0 for common commands where the entered command\nis a prefixe, as these are often more likely to be what the user meant.\n\nThis way, \"git status\" is the first suggestion, while a list of possible\ntypos are still suggested as well.\n\nSigned-off-by: Erik Faye-Lund <kusmabite@gmail.com>\n---\n\nI guess something like this should do the trick. Thoughts?\n\n Makefile |    2 ++\n help.c   |   23 +++++++++++++++++------\n 2 files changed, 19 insertions(+), 6 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 1f1ce04..d6ba349 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1611,6 +1611,8 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \\\n \t\t$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)\n \n+help.o: common-cmds.h\n+\n builtin/help.o: common-cmds.h\n builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_SQ)\"' \\\ndiff --git a/help.c b/help.c\nindex 7f4928e..dc76a62 100644\n--- a/help.c\n+++ b/help.c\n@@ -3,6 +3,7 @@\n #include \"exec_cmd.h\"\n #include \"levenshtein.h\"\n #include \"help.h\"\n+#include \"common-cmds.h\"\n \n /* most GUI terminals set COLUMNS (although some don't export it) */\n static int term_columns(void)\n@@ -298,7 +299,7 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n }\n \n /* An empirically derived magic number */\n-#define SIMILAR_ENOUGH(x) ((x) < 6)\n+#define SIMILAR_ENOUGH(x) ((x) < 7)\n \n const char *help_unknown_cmd(const char *cmd)\n {\n@@ -320,9 +321,16 @@ const char *help_unknown_cmd(const char *cmd)\n \tuniq(&main_cmds);\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+\tfor (i = 0; i < main_cmds.cnt; ++i) {\n+\t\tmain_cmds.names[i]->len = 1 +\n \t\t\tlevenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);\n+\t\tfor (n = 0; n < ARRAY_SIZE(common_cmds); ++n) {\n+\t\t\tif (!strcmp(main_cmds.names[i]->name,\n+\t\t\t    common_cmds[n].name) &&\n+\t\t\t    !prefixcmp(main_cmds.names[i]->name, cmd))\n+\t\t\t\tmain_cmds.names[i]->len = 0;\n+\t\t}\n+\t}\n \n \tqsort(main_cmds.names, main_cmds.cnt,\n \t      sizeof(*main_cmds.names), levenshtein_compare);\n@@ -330,9 +338,12 @@ 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 \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+\tn = 0;\n+\tdo {\n+\t\tbest_similarity = main_cmds.names[n++]->len;\n+\t} while (!best_similarity);\n+\tn++;\n+\twhile (n < main_cmds.cnt && best_similarity >= main_cmds.names[n]->len)\n \t\t++n;\n \tif (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {\n \t\tconst char *assumed = main_cmds.names[0]->name;\n-- \n1.7.3.2\n"},{"id":"156446","messageId":"m262vn22sf.fsf@igel.home","threadId":"25818","inReplyTo":"AANLkTi=FaZ4MhJ2gDFZGiJVHsuY9jtNGgdWxX3Dq4BY6@mail.gmail.com","subject":"Re: bug: unexpected output for \"git st\" + suggestion","fromName":"Andreas Schwab","fromEmail":"schwab@linux-m68k.org","sentAt":"2010-11-23T20:38:56Z","receivedAt":"2010-11-23T20:38:56Z","isPatch":false,"sender":{"key":"schwab@linux-m68k.org","avatar":"https://avatars.githubusercontent.com/u/2175493?v=4"},"body":"Tarek Ziadé <ziade.tarek@gmail.com> writes:\n\n> On Tue, Nov 23, 2010 at 2:08 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:\n> ...\n>>\n>> There's another command that starts with \"st\": stripspace (it's a\n>> lowlevel command by the way). It's going to be a lot more if you type\n>> \"git m\" and expect all commands starting with 'm'.\n>\n> Maybe so yeah. That's how Mercurial does.\n>\n> $  hg s\n> hg: command 's' is ambiguous:\n>     serve showconfig status strip summary\n\nMercurial allows unique abbreviations.  Git doesn't.  Thus a git command\nis never ambiguous.\n\nAndreas.\n\n-- \nAndreas Schwab, schwab@linux-m68k.org\nGPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5\n\"And now for something completely different.\"\n"},{"id":"156493","messageId":"7v1v6atsbd.fsf@alter.siamese.dyndns.org","threadId":"25818","inReplyTo":"1290539473-2420-1-git-send-email-kusmabite@gmail.com","subject":"Re: [PATCH] help: always suggest common-cmds if prefix of cmd","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-11-24T19:49:58Z","receivedAt":"2010-11-24T19:49:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Erik Faye-Lund <kusmabite@gmail.com> writes:\n\n> @@ -320,9 +321,16 @@ const char *help_unknown_cmd(const char *cmd)\n>  \tuniq(&main_cmds);\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 = 1 +\n>  \t\t\tlevenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);\n> +\t\tfor (n = 0; n < ARRAY_SIZE(common_cmds); ++n) {\n> +\t\t\tif (!strcmp(main_cmds.names[i]->name,\n> +\t\t\t    common_cmds[n].name) &&\n> +\t\t\t    !prefixcmp(main_cmds.names[i]->name, cmd))\n> +\t\t\t\tmain_cmds.names[i]->len = 0;\n> +\t\t}\n> +\t}\n\nSo main_cmds.names[]->len (which is not \"len\" anymore at this point but is\njust a \"score\") gets levenshtein distance (i.e. a smaller number indicates\ncmd is more likely to be a typo of it), and in addition ->len == 0 is \"it\nis prefix\".  Overall, the smaller the score, the likelier the match.\n\n> @@ -330,9 +338,12 @@ 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>  \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> +\tn = 0;\n> +\tdo {\n> +\t\tbest_similarity = main_cmds.names[n++]->len;\n> +\t} while (!best_similarity);\n\nAt this point, main_cmds.names[] is sorted by the above score (smaller to\nlarger), and first you skip all the \"prefix\" ones that score 0.\n\nThis relies on the fact that there is at least one entry with non-zero\nscore, which in practice is true, but without even a comment?  I feel\ndirty.\n\nThe score of the first non-prefix entry is in best_similarity and that\nentry is at main_cmds.names[n-1] at this point.  You haven't checked\nmain_cmds.names[n] yet...\n\n> +\tn++;\n\n... but you increment n to skip that entry without even looking, and then\ngo on to ...\n\n> +\twhile (n < main_cmds.cnt && best_similarity >= main_cmds.names[n]->len)\n>  \t\t++n;\n\nYou skip the entries with the same similarity as the closest typo,\npresumably to point n to the first entry that is irrelevant (i.e. 0 thru n\nbut not including n are candidates).\n\nYour rewrite of the loop makes it very hard to read and spot bugs, I\nthink.\n\n>  \tif (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {\n>  \t\tconst char *assumed = main_cmds.names[0]->name;\n> -- \n> 1.7.3.2\n"},{"id":"156498","messageId":"AANLkTi=nxcODCvQ6hmaQe=q38e=bF7cRHWrRaFr+zen6@mail.gmail.com","threadId":"25818","inReplyTo":"7v1v6atsbd.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] help: always suggest common-cmds if prefix of cmd","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-11-24T20:20:45Z","receivedAt":"2010-11-24T20:20:45Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Wed, Nov 24, 2010 at 8:49 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Erik Faye-Lund <kusmabite@gmail.com> writes:\n>\n>> @@ -320,9 +321,16 @@ const char *help_unknown_cmd(const char *cmd)\n>>       uniq(&main_cmds);\n>>\n>>       /* This reuses cmdname->len for similarity index */\n>> +     for (i = 0; i < main_cmds.cnt; ++i) {\n>> +             main_cmds.names[i]->len = 1 +\n>>                       levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);\n>> +             for (n = 0; n < ARRAY_SIZE(common_cmds); ++n) {\n>> +                     if (!strcmp(main_cmds.names[i]->name,\n>> +                         common_cmds[n].name) &&\n>> +                         !prefixcmp(main_cmds.names[i]->name, cmd))\n>> +                             main_cmds.names[i]->len = 0;\n>> +             }\n>> +     }\n>\n> So main_cmds.names[]->len (which is not \"len\" anymore at this point but is\n> just a \"score\") gets levenshtein distance (i.e. a smaller number indicates\n> cmd is more likely to be a typo of it), and in addition ->len == 0 is \"it\n> is prefix\".  Overall, the smaller the score, the likelier the match.\n>\n\nCorrect. This was already the case, though. I just reserved len = 0 as\n\"this is a prefix of the entered command\".\n\n>> @@ -330,9 +338,12 @@ const char *help_unknown_cmd(const char *cmd)\n>>       if (!main_cmds.cnt)\n>>               die (\"Uh oh. Your system reports no Git commands at all.\");\n>>\n>> -     best_similarity = main_cmds.names[0]->len;\n>> -     n = 1;\n>> -     while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)\n>> +     n = 0;\n>> +     do {\n>> +             best_similarity = main_cmds.names[n++]->len;\n>> +     } while (!best_similarity);\n>\n> At this point, main_cmds.names[] is sorted by the above score (smaller to\n> larger), and first you skip all the \"prefix\" ones that score 0.\n>\n> This relies on the fact that there is at least one entry with non-zero\n> score, which in practice is true, but without even a comment?  I feel\n> dirty.\n>\n\nAh, yes. This needs clearer code badly. I'll see what I can cook up.\n\n> The score of the first non-prefix entry is in best_similarity and that\n> entry is at main_cmds.names[n-1] at this point.  You haven't checked\n> main_cmds.names[n] yet...\n>\n>> +     n++;\n>\n> ... but you increment n to skip that entry without even looking, and then\n> go on to ...\n>\n\nThis is a bug, thanks for spotting it. It was intended to be the same\nas \"i = 1\" in the old version, but I didn't think about it being\nincreased in the previous loop as well, silly me.\n\n>> +     while (n < main_cmds.cnt && best_similarity >= main_cmds.names[n]->len)\n>>               ++n;\n>\n> You skip the entries with the same similarity as the closest typo,\n> presumably to point n to the first entry that is irrelevant (i.e. 0 thru n\n> but not including n are candidates).\n>\n> Your rewrite of the loop makes it very hard to read and spot bugs, I\n> think.\n>\n\nIndeed. What about this intra-diff? Hopefully it's a bit clearer, as\nit's closer to the original, just reusing the same logic for the new\nsimilar loop... Also makes the final diff smaller, which is nice.\n\ndiff --git a/help.c b/help.c\nindex dc76a62..d02a019 100644\n--- a/help.c\n+++ b/help.c\n@@ -339,11 +339,10 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tdie (\"Uh oh. Your system reports no Git commands at all.\");\n\n \tn = 0;\n-\tdo {\n-\t\tbest_similarity = main_cmds.names[n++]->len;\n-\t} while (!best_similarity);\n-\tn++;\n-\twhile (n < main_cmds.cnt && best_similarity >= main_cmds.names[n]->len)\n+\twhile (n < main_cmds.cnt && !main_cmds.names[n]->len)\n+\t\t++n;\n+\tbest_similarity = main_cmds.names[n++]->len;\n+\twhile (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)\n \t\t++n;\n \tif (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {\n \t\tconst char *assumed = main_cmds.names[0]->name;\n"},{"id":"156512","messageId":"1290642821-2984-1-git-send-email-kusmabite@gmail.com","threadId":"25818","inReplyTo":"AANLkTi=nxcODCvQ6hmaQe=q38e=bF7cRHWrRaFr+zen6@mail.gmail.com","subject":"[PATCH] help: always suggest common-cmds if prefix of cmd","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-11-24T23:53:41Z","receivedAt":"2010-11-24T23:53:41Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"If someone runs \"git st\", the command \"git status\" is not suggested\nbecause it's not one of the closest levenshtein-neighbour.\n\nReserve the distance of 0 for common commands where the entered command\nis a prefixe, as these are often more likely to be what the user meant.\n\nThis way, \"git status\" is the first suggestion, while a list of possible\ntypos are still suggested as well.\n\nSigned-off-by: Erik Faye-Lund <kusmabite@gmail.com>\n---\n\nHere's an updated version, with the issues Junio fixed.\n\nI hope this is a bit clearer.\n\n Makefile |    2 ++\n help.c   |   26 ++++++++++++++++++++------\n 2 files changed, 22 insertions(+), 6 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 1f1ce04..d6ba349 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1611,6 +1611,8 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \\\n \t\t$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)\n \n+help.o: common-cmds.h\n+\n builtin/help.o: common-cmds.h\n builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_SQ)\"' \\\ndiff --git a/help.c b/help.c\nindex 7f4928e..dff5d6b 100644\n--- a/help.c\n+++ b/help.c\n@@ -3,6 +3,7 @@\n #include \"exec_cmd.h\"\n #include \"levenshtein.h\"\n #include \"help.h\"\n+#include \"common-cmds.h\"\n \n /* most GUI terminals set COLUMNS (although some don't export it) */\n static int term_columns(void)\n@@ -298,7 +299,7 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n }\n \n /* An empirically derived magic number */\n-#define SIMILAR_ENOUGH(x) ((x) < 6)\n+#define SIMILAR_ENOUGH(x) ((x) < 7)\n \n const char *help_unknown_cmd(const char *cmd)\n {\n@@ -320,9 +321,16 @@ const char *help_unknown_cmd(const char *cmd)\n \tuniq(&main_cmds);\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+\tfor (i = 0; i < main_cmds.cnt; ++i) {\n+\t\tmain_cmds.names[i]->len = 1 +\n \t\t\tlevenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);\n+\t\tfor (n = 0; n < ARRAY_SIZE(common_cmds); ++n) {\n+\t\t\tif (!strcmp(main_cmds.names[i]->name,\n+\t\t\t    common_cmds[n].name) &&\n+\t\t\t    !prefixcmp(main_cmds.names[i]->name, cmd))\n+\t\t\t\tmain_cmds.names[i]->len = 0;\n+\t\t}\n+\t}\n \n \tqsort(main_cmds.names, main_cmds.cnt,\n \t      sizeof(*main_cmds.names), levenshtein_compare);\n@@ -330,10 +338,16 @@ 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 \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+\tn = 0;\n+\twhile (n < main_cmds.cnt && !main_cmds.names[n]->len)\n \t\t++n;\n+\tif (n < main_cmds.cnt) {\n+\t\tbest_similarity = main_cmds.names[n++]->len;\n+\t\twhile (n < main_cmds.cnt &&\n+\t\t       best_similarity == main_cmds.names[n]->len)\n+\t\t\t++n;\n+\t} else\n+\t\tbest_similarity = 0;\n \tif (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {\n \t\tconst char *assumed = main_cmds.names[0]->name;\n \t\tmain_cmds.names[0] = NULL;\n-- \n1.7.3.2\n"},{"id":"156521","messageId":"7vfwuqrori.fsf@alter.siamese.dyndns.org","threadId":"25818","inReplyTo":"AANLkTi=nxcODCvQ6hmaQe=q38e=bF7cRHWrRaFr+zen6@mail.gmail.com","subject":"Re: [PATCH] help: always suggest common-cmds if prefix of cmd","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-11-25T04:49:37Z","receivedAt":"2010-11-25T04:49:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Erik Faye-Lund <kusmabite@gmail.com> writes:\n\n> Indeed. What about this intra-diff? Hopefully it's a bit clearer, as\n> it's closer to the original, just reusing the same logic for the new\n> similar loop... Also makes the final diff smaller, which is nice.\n>\n> diff --git a/help.c b/help.c\n> index dc76a62..d02a019 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -339,11 +339,10 @@ const char *help_unknown_cmd(const char *cmd)\n>  \t\tdie (\"Uh oh. Your system reports no Git commands at all.\");\n>\n>  \tn = 0;\n> -\tdo {\n> -\t\tbest_similarity = main_cmds.names[n++]->len;\n> -\t} while (!best_similarity);\n> -\tn++;\n> -\twhile (n < main_cmds.cnt && best_similarity >= main_cmds.names[n]->len)\n> +\twhile (n < main_cmds.cnt && !main_cmds.names[n]->len)\n> +\t\t++n;\n> +\tbest_similarity = main_cmds.names[n++]->len;\n> +\twhile (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)\n>  \t\t++n;\n\nPerhaps, but it is probably more conventional to write this kind of loop with:\n\n\tfor (n = 0; ...; n++)\n\t\t...\n\nno?\n\n>  \tif (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {\n>  \t\tconst char *assumed = main_cmds.names[0]->name;\n"},{"id":"156542","messageId":"AANLkTinKDqykfuV5=oHav9PRehDtJZct_q=zm7p8PAeo@mail.gmail.com","threadId":"25818","inReplyTo":"7vfwuqrori.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] help: always suggest common-cmds if prefix of cmd","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-11-25T10:39:27Z","receivedAt":"2010-11-25T10:39:27Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Thu, Nov 25, 2010 at 5:49 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Erik Faye-Lund <kusmabite@gmail.com> writes:\n>\n>> Indeed. What about this intra-diff? Hopefully it's a bit clearer, as\n>> it's closer to the original, just reusing the same logic for the new\n>> similar loop... Also makes the final diff smaller, which is nice.\n>>\n>> diff --git a/help.c b/help.c\n>> index dc76a62..d02a019 100644\n>> --- a/help.c\n>> +++ b/help.c\n>> @@ -339,11 +339,10 @@ const char *help_unknown_cmd(const char *cmd)\n>>               die (\"Uh oh. Your system reports no Git commands at all.\");\n>>\n>>       n = 0;\n>> -     do {\n>> -             best_similarity = main_cmds.names[n++]->len;\n>> -     } while (!best_similarity);\n>> -     n++;\n>> -     while (n < main_cmds.cnt && best_similarity >= main_cmds.names[n]->len)\n>> +     while (n < main_cmds.cnt && !main_cmds.names[n]->len)\n>> +             ++n;\n>> +     best_similarity = main_cmds.names[n++]->len;\n>> +     while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)\n>>               ++n;\n>\n> Perhaps, but it is probably more conventional to write this kind of loop with:\n>\n>        for (n = 0; ...; n++)\n>                ...\n>\n> no?\n>\n>>       if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {\n>>               const char *assumed = main_cmds.names[0]->name;\n>\n\nSure. I was just trying to match the existing code. But sure, I can\nchange that if you prefer. I think it makes the end-result slightly\nnicer.\n"},{"id":"156671","messageId":"1290787239-4508-1-git-send-email-kusmabite@gmail.com","threadId":"25818","inReplyTo":"AANLkTinKDqykfuV5=oHav9PRehDtJZct_q=zm7p8PAeo@mail.gmail.com","subject":"[PATCH v3] help: always suggest common-cmds if prefix of cmd","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-11-26T16:00:39Z","receivedAt":"2010-11-26T16:00:39Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"If someone runs \"git st\", the command \"git status\" is not suggested\nbecause it's not one of the closest levenshtein-neighbour.\n\nReserve the distance of 0 for common commands where the entered command\nis a prefixe, as these are often more likely to be what the user meant.\n\nThis way, \"git status\" is the first suggestion, while a list of possible\ntypos are still suggested as well.\n\nSigned-off-by: Erik Faye-Lund <kusmabite@gmail.com>\n---\n Makefile |    2 ++\n help.c   |   27 ++++++++++++++++++++-------\n 2 files changed, 22 insertions(+), 7 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 1f1ce04..d6ba349 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1611,6 +1611,8 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \\\n \t\t$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)\n \n+help.o: common-cmds.h\n+\n builtin/help.o: common-cmds.h\n builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_SQ)\"' \\\ndiff --git a/help.c b/help.c\nindex 7f4928e..0d76a82 100644\n--- a/help.c\n+++ b/help.c\n@@ -3,6 +3,7 @@\n #include \"exec_cmd.h\"\n #include \"levenshtein.h\"\n #include \"help.h\"\n+#include \"common-cmds.h\"\n \n /* most GUI terminals set COLUMNS (although some don't export it) */\n static int term_columns(void)\n@@ -298,7 +299,7 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n }\n \n /* An empirically derived magic number */\n-#define SIMILAR_ENOUGH(x) ((x) < 6)\n+#define SIMILAR_ENOUGH(x) ((x) < 7)\n \n const char *help_unknown_cmd(const char *cmd)\n {\n@@ -320,9 +321,16 @@ const char *help_unknown_cmd(const char *cmd)\n \tuniq(&main_cmds);\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+\tfor (i = 0; i < main_cmds.cnt; ++i) {\n+\t\tmain_cmds.names[i]->len = 1 +\n \t\t\tlevenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);\n+\t\tfor (n = 0; n < ARRAY_SIZE(common_cmds); ++n) {\n+\t\t\tif (!strcmp(main_cmds.names[i]->name,\n+\t\t\t    common_cmds[n].name) &&\n+\t\t\t    !prefixcmp(main_cmds.names[i]->name, cmd))\n+\t\t\t\tmain_cmds.names[i]->len = 0;\n+\t\t}\n+\t}\n \n \tqsort(main_cmds.names, main_cmds.cnt,\n \t      sizeof(*main_cmds.names), levenshtein_compare);\n@@ -330,10 +338,15 @@ 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 \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+\tfor (n = 0; n < main_cmds.cnt && !main_cmds.names[n]->len; ++n)\n+\t\t; /* nothing */\n+\tif (n < main_cmds.cnt) {\n+\t\tbest_similarity = main_cmds.names[n++]->len;\n+\t\twhile (n < main_cmds.cnt &&\n+\t\t       best_similarity == main_cmds.names[n]->len)\n+\t\t\t++n;\n+\t} else\n+\t\tbest_similarity = 0;\n \tif (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {\n \t\tconst char *assumed = main_cmds.names[0]->name;\n \t\tmain_cmds.names[0] = NULL;\n-- \n1.7.3.2\n"},{"id":"156700","messageId":"7voc9bpqj2.fsf@alter.siamese.dyndns.org","threadId":"25818","inReplyTo":"1290787239-4508-1-git-send-email-kusmabite@gmail.com","subject":"Re: [PATCH v3] help: always suggest common-cmds if prefix of cmd","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-11-27T00:18:57Z","receivedAt":"2010-11-27T00:18:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Erik Faye-Lund <kusmabite@gmail.com> writes:\n\n> @@ -320,9 +321,16 @@ const char *help_unknown_cmd(const char *cmd)\n>  \tuniq(&main_cmds);\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> +\tfor (i = 0; i < main_cmds.cnt; ++i) {\n> +\t\tmain_cmds.names[i]->len = 1 +\n>  \t\t\tlevenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);\n> +\t\tfor (n = 0; n < ARRAY_SIZE(common_cmds); ++n) {\n> +\t\t\tif (!strcmp(main_cmds.names[i]->name,\n> +\t\t\t    common_cmds[n].name) &&\n> +\t\t\t    !prefixcmp(main_cmds.names[i]->name, cmd))\n> +\t\t\t\tmain_cmds.names[i]->len = 0;\n> +\t\t}\n> +\t}\n\nThis is an error codepath so performance would not matter much, but this\nis doing it in an unnecessarily slow way, no?  At this point, both arrays\nare sorted the same way, so we should be able to walk common_cmds[]\nalongside the main_cmds.names[] (see below).\n\n> +\tif (n < main_cmds.cnt) {\n> +\t\tbest_similarity = main_cmds.names[n++]->len;\n> +\t\twhile (n < main_cmds.cnt &&\n> +\t\t       best_similarity == main_cmds.names[n]->len)\n> +\t\t\t++n;\n> +\t} else\n> +\t\tbest_similarity = 0;\n\nThink about what does this case _means_... The end user input was so\nambiguous that it prefix matched all the common commands!  Is it really\nsimilar enough?\n\nNote that most of the time main_cmds[] has more than what common_cmds[]\nhas, and because prefix match is done only against common_cmds[],\n\"everything is a prefix-match\" never happens.  You might want to mark it\nas a BUG(), but someday we may change the rules to give 0 to non common\ncommands with prefix match under some condition, so thinking these rare\ncorner cases through would defend ourselves from future gotchas.\n\nHow about doing it this way instead?  Isn't it more readable?\n\ndiff --git a/help.c b/help.c\nindex 7f4928e..7654f1b 100644\n--- a/help.c\n+++ b/help.c\n@@ -3,6 +3,7 @@\n #include \"exec_cmd.h\"\n #include \"levenshtein.h\"\n #include \"help.h\"\n+#include \"common-cmds.h\"\n \n /* most GUI terminals set COLUMNS (although some don't export it) */\n static int term_columns(void)\n@@ -298,7 +299,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n }\n \n /* An empirically derived magic number */\n-#define SIMILAR_ENOUGH(x) ((x) < 6)\n+#define SIMILARITY_FLOOR 7\n+#define SIMILAR_ENOUGH(x) ((x) < SIMILARITY_FLOOR)\n \n const char *help_unknown_cmd(const char *cmd)\n {\n@@ -319,10 +321,28 @@ const char *help_unknown_cmd(const char *cmd)\n \t      sizeof(main_cmds.names), cmdname_compare);\n \tuniq(&main_cmds);\n \n-\t/* This reuses cmdname->len for similarity index */\n-\tfor (i = 0; i < main_cmds.cnt; ++i)\n+\t/* This abuses cmdname->len for levenshtein distance */\n+\tfor (i = 0, n = 0; i < main_cmds.cnt; i++) {\n+\t\tint cmp = 0; /* avoid compiler stupidity */\n+\t\tconst char *candidate = main_cmds.names[i]->name;\n+\n+\t\t/* Does the candidate appear in common_cmds list? */\n+\t\twhile (n < ARRAY_SIZE(common_cmds) &&\n+\t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n+\t\t\tn++;\n+\t\tif ((n < ARRAY_SIZE(common_cmds)) && !cmp) {\n+\t\t\t/* Yes, this is one of the common commands */\n+\t\t\tn++; /* use the entry from common_cmds[] */\n+\t\t\tif (!prefixcmp(candidate, cmd)) {\n+\t\t\t\t/* Give prefix match a very good score */\n+\t\t\t\tmain_cmds.names[i]->len = 0;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t}\n+\n \t\tmain_cmds.names[i]->len =\n-\t\t\tlevenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);\n+\t\t\tlevenshtein(cmd, candidate, 0, 2, 1, 4) + 1;\n+\t}\n \n \tqsort(main_cmds.names, main_cmds.cnt,\n \t      sizeof(*main_cmds.names), levenshtein_compare);\n@@ -330,10 +350,21 @@ 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 \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+\t/* skip and count prefix matches */\n+\tfor (n = 0; n < main_cmds.cnt && !main_cmds.names[n]->len; n++)\n+\t\t; /* still counting */\n+\n+\tif (main_cmds.cnt <= n) {\n+\t\t/* prefix matches with everything? that is too ambiguous */\n+\t\tbest_similarity = SIMILARITY_FLOOR + 1;\n+\t} else {\n+\t\t/* count all the most similar ones */\n+\t\tfor (best_similarity = main_cmds.names[n++]->len;\n+\t\t     (n < main_cmds.cnt &&\n+\t\t      best_similarity == main_cmds.names[n]->len);\n+\t\t     n++)\n+\t\t\t; /* still counting */\n+\t}\n \tif (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {\n \t\tconst char *assumed = main_cmds.names[0]->name;\n \t\tmain_cmds.names[0] = NULL;\n"},{"id":"156797","messageId":"AANLkTin34AfYnFY5e9B1cuyckfLXU2=qXFciFaaNGt9f@mail.gmail.com","threadId":"25818","inReplyTo":"7voc9bpqj2.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3] help: always suggest common-cmds if prefix of cmd","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-11-29T11:20:35Z","receivedAt":"2010-11-29T11:20:35Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"Sorry for the late reply, I've been out sick.\n\nOn Sat, Nov 27, 2010 at 1:18 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Erik Faye-Lund <kusmabite@gmail.com> writes:\n>\n>> @@ -320,9 +321,16 @@ const char *help_unknown_cmd(const char *cmd)\n>>       uniq(&main_cmds);\n>>\n>>       /* This reuses cmdname->len for similarity index */\n>> -     for (i = 0; i < main_cmds.cnt; ++i)\n>> -             main_cmds.names[i]->len =\n>> +     for (i = 0; i < main_cmds.cnt; ++i) {\n>> +             main_cmds.names[i]->len = 1 +\n>>                       levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);\n>> +             for (n = 0; n < ARRAY_SIZE(common_cmds); ++n) {\n>> +                     if (!strcmp(main_cmds.names[i]->name,\n>> +                         common_cmds[n].name) &&\n>> +                         !prefixcmp(main_cmds.names[i]->name, cmd))\n>> +                             main_cmds.names[i]->len = 0;\n>> +             }\n>> +     }\n>\n> This is an error codepath so performance would not matter much, but this\n> is doing it in an unnecessarily slow way, no?  At this point, both arrays\n> are sorted the same way, so we should be able to walk common_cmds[]\n> alongside the main_cmds.names[] (see below).\n>\n\nI like it, thanks!\n\n>> +     if (n < main_cmds.cnt) {\n>> +             best_similarity = main_cmds.names[n++]->len;\n>> +             while (n < main_cmds.cnt &&\n>> +                    best_similarity == main_cmds.names[n]->len)\n>> +                     ++n;\n>> +     } else\n>> +             best_similarity = 0;\n>\n> Think about what does this case _means_... The end user input was so\n> ambiguous that it prefix matched all the common commands!  Is it really\n> similar enough?\n>\n> Note that most of the time main_cmds[] has more than what common_cmds[]\n> has, and because prefix match is done only against common_cmds[],\n> \"everything is a prefix-match\" never happens.  You might want to mark it\n> as a BUG(), but someday we may change the rules to give 0 to non common\n> commands with prefix match under some condition, so thinking these rare\n> corner cases through would defend ourselves from future gotchas.\n>\n> How about doing it this way instead?  Isn't it more readable?\n>\n\nYes, this is better. But:\n\n> diff --git a/help.c b/help.c\n> index 7f4928e..7654f1b 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -3,6 +3,7 @@\n>  #include \"exec_cmd.h\"\n>  #include \"levenshtein.h\"\n>  #include \"help.h\"\n> +#include \"common-cmds.h\"\n>\n>  /* most GUI terminals set COLUMNS (although some don't export it) */\n>  static int term_columns(void)\n> @@ -298,7 +299,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n>  }\n>\n>  /* An empirically derived magic number */\n> -#define SIMILAR_ENOUGH(x) ((x) < 6)\n> +#define SIMILARITY_FLOOR 7\n> +#define SIMILAR_ENOUGH(x) ((x) < SIMILARITY_FLOOR)\n>\n>  const char *help_unknown_cmd(const char *cmd)\n>  {\n> @@ -319,10 +321,28 @@ const char *help_unknown_cmd(const char *cmd)\n>              sizeof(main_cmds.names), cmdname_compare);\n>        uniq(&main_cmds);\n>\n> -       /* This reuses cmdname->len for similarity index */\n> -       for (i = 0; i < main_cmds.cnt; ++i)\n> +       /* This abuses cmdname->len for levenshtein distance */\n> +       for (i = 0, n = 0; i < main_cmds.cnt; i++) {\n> +               int cmp = 0; /* avoid compiler stupidity */\n> +               const char *candidate = main_cmds.names[i]->name;\n> +\n> +               /* Does the candidate appear in common_cmds list? */\n> +               while (n < ARRAY_SIZE(common_cmds) &&\n> +                      (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n> +                       n++;\n> +               if ((n < ARRAY_SIZE(common_cmds)) && !cmp) {\n> +                       /* Yes, this is one of the common commands */\n> +                       n++; /* use the entry from common_cmds[] */\n> +                       if (!prefixcmp(candidate, cmd)) {\n> +                               /* Give prefix match a very good score */\n> +                               main_cmds.names[i]->len = 0;\n> +                               continue;\n> +                       }\n> +               }\n> +\n>                main_cmds.names[i]->len =\n> -                       levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);\n> +                       levenshtein(cmd, candidate, 0, 2, 1, 4) + 1;\n> +       }\n>\n>        qsort(main_cmds.names, main_cmds.cnt,\n>              sizeof(*main_cmds.names), levenshtein_compare);\n> @@ -330,10 +350,21 @@ const char *help_unknown_cmd(const char *cmd)\n>        if (!main_cmds.cnt)\n>                die (\"Uh oh. Your system reports no Git commands at all.\");\n>\n> -       best_similarity = main_cmds.names[0]->len;\n> -       n = 1;\n> -       while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)\n> -               ++n;\n> +       /* skip and count prefix matches */\n> +       for (n = 0; n < main_cmds.cnt && !main_cmds.names[n]->len; n++)\n> +               ; /* still counting */\n> +\n> +       if (main_cmds.cnt <= n) {\n> +               /* prefix matches with everything? that is too ambiguous */\n> +               best_similarity = SIMILARITY_FLOOR + 1;\n\nFor this code-path to trigger we would have to be able to prefix-match\nevery common command AND every \"main command\" must be included in\ncommon commands. At the same time. The only possible way to\nprefix-match all commands is if they all start with the same letter.\nDo you really think this is a situation we could ever end up in? Every\ngit command being a common-command, starting with the same letter?\n\nThis is basically unreachable code. Perhaps it'd be even clearer just to die:\n\nif (main_cmds.cnt <= n)\n\tdie(\"Prefix-matched everyting, what's going on?\");\n\n\n> +       } else {\n> +               /* count all the most similar ones */\n> +               for (best_similarity = main_cmds.names[n++]->len;\n> +                    (n < main_cmds.cnt &&\n> +                     best_similarity == main_cmds.names[n]->len);\n> +                    n++)\n> +                       ; /* still counting */\n> +       }\n>        if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) {\n>                const char *assumed = main_cmds.names[0]->name;\n>                main_cmds.names[0] = NULL;\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n>\n"},{"id":"156811","messageId":"20101129164049.GH8037@burratino","threadId":"25818","inReplyTo":"AANLkTin34AfYnFY5e9B1cuyckfLXU2=qXFciFaaNGt9f@mail.gmail.com","subject":"Re: [PATCH v3] help: always suggest common-cmds if prefix of cmd","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-11-29T16:40:49Z","receivedAt":"2010-11-29T16:40:49Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Erik Faye-Lund wrote:\n\n> For this code-path to trigger we would have to be able to prefix-match\n> every common command AND every \"main command\" must be included in\n> common commands. At the same time. The only possible way to\n> prefix-match all commands is if they all start with the same letter.\n> Do you really think this is a situation we could ever end up in? Every\n> git command being a common-command, starting with the same letter?\n> \n> This is basically unreachable code. Perhaps it'd be even clearer just to die:\n> \n> if (main_cmds.cnt <= n)\n> \tdie(\"Prefix-matched everyting, what's going on?\");\n\n(I haven't checked.)  Maybe\n\n\t$ git \"\"\n\n?\n"},{"id":"156814","messageId":"AANLkTim_TiC-CSGz6x4cH44meJ6SpQv0sg3-rVWsDcKK@mail.gmail.com","threadId":"25818","inReplyTo":"20101129164049.GH8037@burratino","subject":"Re: [PATCH v3] help: always suggest common-cmds if prefix of cmd","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-11-29T16:53:25Z","receivedAt":"2010-11-29T16:53:25Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Mon, Nov 29, 2010 at 5:40 PM, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> Erik Faye-Lund wrote:\n>\n>> For this code-path to trigger we would have to be able to prefix-match\n>> every common command AND every \"main command\" must be included in\n>> common commands. At the same time. The only possible way to\n>> prefix-match all commands is if they all start with the same letter.\n>> Do you really think this is a situation we could ever end up in? Every\n>> git command being a common-command, starting with the same letter?\n>>\n>> This is basically unreachable code. Perhaps it'd be even clearer just to die:\n>>\n>> if (main_cmds.cnt <= n)\n>>       die(\"Prefix-matched everyting, what's going on?\");\n>\n> (I haven't checked.)  Maybe\n>\n>        $ git \"\"\n>\n> ?\n>\n\nAh, yes. This does indeed work, both on Linux and Windows, and it does\nweaken my point about the unlikeliness of the code ever reaching it.\n\nBut I must say that I think the most sane thing to do in this case\nwould be to just display the normal help-page (like \"git\" does).\n"},{"id":"156821","messageId":"7vvd3g58ja.fsf@alter.siamese.dyndns.org","threadId":"25818","inReplyTo":"AANLkTin34AfYnFY5e9B1cuyckfLXU2=qXFciFaaNGt9f@mail.gmail.com","subject":"Re: [PATCH v3] help: always suggest common-cmds if prefix of cmd","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-11-29T17:44:41Z","receivedAt":"2010-11-29T17:44:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Erik Faye-Lund <kusmabite@gmail.com> writes:\n\n> For this code-path to trigger we would have to be able to prefix-match\n> every common command AND every \"main command\" must be included in\n> common commands. At the same time. The only possible way to\n> prefix-match all commands is if they all start with the same letter.\n> Do you really think this is a situation we could ever end up in? Every\n> git command being a common-command, starting with the same letter?\n>\n> This is basically unreachable code. Perhaps it'd be even clearer just to die:\n>\n> if (main_cmds.cnt <= n)\n> \tdie(\"Prefix-matched everyting, what's going on?\");\n\nWell, the same letter can be an empty string:\n\n\t$ git ''\n\nDidn't I already suggest BUG() there?  Also, saying \"too ambiguous\" would\nmake the codepath give \"... See 'git --help'\" message, I think.\n"},{"id":"156930","messageId":"AANLkTi=OyK+Qvin9FjrUTyEacxHVLjBG77Qg_PPoC6kK@mail.gmail.com","threadId":"25818","inReplyTo":"7vvd3g58ja.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3] help: always suggest common-cmds if prefix of cmd","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2010-12-01T14:33:06Z","receivedAt":"2010-12-01T14:33:06Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Mon, Nov 29, 2010 at 6:44 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Erik Faye-Lund <kusmabite@gmail.com> writes:\n>\n>> For this code-path to trigger we would have to be able to prefix-match\n>> every common command AND every \"main command\" must be included in\n>> common commands. At the same time. The only possible way to\n>> prefix-match all commands is if they all start with the same letter.\n>> Do you really think this is a situation we could ever end up in? Every\n>> git command being a common-command, starting with the same letter?\n>>\n>> This is basically unreachable code. Perhaps it'd be even clearer just to die:\n>>\n>> if (main_cmds.cnt <= n)\n>>       die(\"Prefix-matched everyting, what's going on?\");\n>\n> Well, the same letter can be an empty string:\n>\n>        $ git ''\n>\n\nIndeed, my bad.\n\n> Didn't I already suggest BUG() there?  Also, saying \"too ambiguous\" would\n> make the codepath give \"... See 'git --help'\" message, I think.\n>\n\nSure. I was considering just taking your version verbatim. But let's\nsee what happens, perhaps I get inspired ;)\n"},{"id":"363669","messageId":"87y39oztzf.fsf@evledraar.gmail.com","threadId":"25818","inReplyTo":"1290787239-4508-1-git-send-email-kusmabite@gmail.com","subject":"help.autoCorrect prefix selection considered a bit dangerous","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-11-19T20:35:00Z","receivedAt":"2018-11-19T20:35:05Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Replying to this blast from the past:\nhttps://public-inbox.org/git/1290787239-4508-1-git-send-email-kusmabite@gmail.com/\n\nI apparently like to live dangerously and have help.autoCorrect\nenabled. I just had:\n\n    git puss\n\nAuto-corrected to:\n\n    git push\n\nWhen I meant:\n\n    git pull\n\n(For those wondering how I could have mistyped that, \"l\" and \"s\" are\nright next to each other on a Dvorak layout).\n\nAs seen in the E-Mail from 2010 this intentional, i.e. \"pull\" is pruned\nsince the \"pu\" prefix isn't matched, but \"pus\" is. This was meant to\ncorrect e.g. \"git st\" to \"git status\".\n\nI don't have time to poke at this now, but wonder if:\n\n 1) The correction facility shouldn't at least have a list of \"this does\n    stuff over the wire\" commands and would then use a more conservative\n    estimate.\n\n 2) Whether we can do better with typo detection. E.g. add commands like\n    \"pull\" to the list if we have a long enough prefix for them, and if\n    the number of characters entered matches the number of characters in\n    another command.\n"},{"id":"363695","messageId":"xmqqftvwbfe8.fsf@gitster-ct.c.googlers.com","threadId":"25818","inReplyTo":"87y39oztzf.fsf@evledraar.gmail.com","subject":"Re: help.autoCorrect prefix selection considered a bit dangerous","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-11-20T03:23:59Z","receivedAt":"2018-11-20T03:24:07Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> I don't have time to poke at this now, but wonder if:\n>\n>  1) The correction facility shouldn't at least have a list of \"this does\n>     stuff over the wire\" commands and would then use a more conservative\n>     estimate.\n\nNot limited to 'over the wire' but 'can have consequences that might\ncause regret' would be a reasonable list to have.\n\nOn a similar topic, it would be a disaster for \"git reset --h<RET>\"\nto complete to \"--hard\" instead of \"--help\", for example.  Perhaps\nparse-options API also needs to learn a list of possibly regrettable\noptions.\n"}]}