git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Tay Ray Chuan <rctay89@gmail.com>
To: "Git Mailing List" <git@vger.kernel.org>
Cc: "Junio C Hamano" <gitster@pobox.com>, "Jeff King" <peff@peff.net>
Subject: [PATCH v3 2/2] allow recovery from command name typos
Date: Mon,  6 Aug 2012 02:45:40 +0800	[thread overview]
Message-ID: <1344192340-19415-3-git-send-email-rctay89@gmail.com> (raw)
In-Reply-To: <1344192340-19415-2-git-send-email-rctay89@gmail.com>

If suggestions are available (based on Levenshtein distance) and if the
terminal isatty(), present a prompt to the user to select one of the
computed suggestions.

In the case where there is a single suggestion, present the prompt
"[Y/n]", such that "" (ie. the default), "y" and "Y" as input leads git
to proceed executing the suggestion, while everything else (possibly
"n") leads git to terminate.

In the case where there are multiple suggestions, number the suggestions
1 to <n> (the number of suggestions), and accept an integer as input,
while everything else (possibly "n") leads git to terminate. In this
case there is no default; an empty input leads git to terminate. A
sample run:

  $ git sh --pretty=oneline
  git: 'sh' is not a git command. See 'git --help'.

  Did you mean one of these?
  1:    show
  2:    push
  [N/1/2/...]

This prompt is enabled only if help.autocorrect is set to ask; if unset,
advise the user about this ability.

Helped-by: Thomas Rast <trast@student.ethz.ch>
Signed-off-by: Tay Ray Chuan <rctay89@gmail.com>
---

Changed in v3:
 - say do_* instead of shall_*
 - use new terminal interface

 Documentation/config.txt | 30 ++++++++++++++++-----
 advice.c                 |  2 ++
 advice.h                 |  1 +
 help.c                   | 68 +++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 0bcea8a..0bb175a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -177,6 +177,10 @@ advice.*::
 		Advice shown when you used linkgit:git-checkout[1] to
 		move to the detach HEAD state, to instruct how to create
 		a local branch after the fact.
+	typoPrompt::
+		Upon a mistyped command, if 'help.autocorrect' is unset
+		advise that an interactive prompt can be displayed to
+		recover from the typo.
 --
 
 core.fileMode::
@@ -1323,13 +1327,25 @@ help.format::
 	the default. 'web' and 'html' are the same.
 
 help.autocorrect::
-	Automatically correct and execute mistyped commands after
-	waiting for the given number of deciseconds (0.1 sec). If more
-	than one command can be deduced from the entered text, nothing
-	will be executed.  If the value of this option is negative,
-	the corrected command will be executed immediately. If the
-	value is 0 - the command will be just shown but not executed.
-	This is the default.
+	Specifies behaviour to recover from mistyped commands.
++
+When set to `ask`, an interactive prompt is displayed, allowing the user
+to select a suggested command for execution.
++
+When set to `off`, no attempt to recover is made.
++
+If a number is given, it will be interpreted as the deciseconds (0.1
+sec) to wait before automatically correcting and executing the mistyped
+command, with the following behaviour:
++
+* If more than one command can be deduced from the entered text, nothing
+  will be executed.
+* If the value of this option is negative, the corrected command will be
+  executed immediately.
+* If the value is 0 - the command will be just shown but not executed.
++
+The default is to display a message suggesting that this option be set
+to `ask`, without attempting to recover (see `advice.typoPrompt`).
 
 http.proxy::
 	Override the HTTP proxy, normally configured using the 'http_proxy',
diff --git a/advice.c b/advice.c
index a492eea..d070a05 100644
--- a/advice.c
+++ b/advice.c
@@ -9,6 +9,7 @@ int advice_commit_before_merge = 1;
 int advice_resolve_conflict = 1;
 int advice_implicit_identity = 1;
 int advice_detached_head = 1;
+int advice_typo_prompt = 1;
 
 static struct {
 	const char *name;
@@ -23,6 +24,7 @@ static struct {
 	{ "resolveconflict", &advice_resolve_conflict },
 	{ "implicitidentity", &advice_implicit_identity },
 	{ "detachedhead", &advice_detached_head },
+	{ "typoprompt", &advice_typo_prompt },
 };
 
 void advise(const char *advice, ...)
diff --git a/advice.h b/advice.h
index f3cdbbf..050068d 100644
--- a/advice.h
+++ b/advice.h
@@ -12,6 +12,7 @@ extern int advice_commit_before_merge;
 extern int advice_resolve_conflict;
 extern int advice_implicit_identity;
 extern int advice_detached_head;
+extern int advice_typo_prompt;
 
 int git_default_advice_config(const char *var, const char *value);
 void advise(const char *advice, ...);
diff --git a/help.c b/help.c
index c4285a5..cc13b92 100644
--- a/help.c
+++ b/help.c
@@ -7,6 +7,7 @@
 #include "string-list.h"
 #include "column.h"
 #include "version.h"
+#include "compat/terminal.h"
 
 void add_cmdname(struct cmdnames *cmds, const char *name, int len)
 {
@@ -233,12 +234,30 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)
 }
 
 static int autocorrect;
+static int do_advise = 1;
+static int do_prompt;
+static const char message_advice_prompt_ability[] =
+	N_("I can display an interactive prompt to proceed with one of the above\n"
+	   "suggestions; if you wish me to do so, use\n"
+	   "\n"
+	   "  git config --global help.autocorrect ask\n"
+	   "\n"
+	   "See 'git help config' and search for 'help.autocorrect' for further\n"
+	   "information.\n");
 static struct cmdnames aliases;
 
 static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
 {
-	if (!strcmp(var, "help.autocorrect"))
-		autocorrect = git_config_int(var,value);
+	if (!strcmp(var, "help.autocorrect") && value) {
+		do_advise = 0;
+		if (!strcasecmp(value, "off"))
+			;
+		else if (!strcasecmp(value, "ask"))
+			do_prompt = 1;
+		else
+			autocorrect = git_config_int(var, value);
+	}
+
 	/* Also use aliases for command lookup */
 	if (!prefixcmp(var, "alias."))
 		add_cmdname(&aliases, var + 6, strlen(var + 6));
@@ -366,13 +385,54 @@ const char *help_unknown_cmd(const char *cmd)
 	fprintf_ln(stderr, _("git: '%s' is not a git command. See 'git --help'."), cmd);
 
 	if (SIMILAR_ENOUGH(best_similarity)) {
+		term_t term;
+
 		fprintf_ln(stderr,
 			   Q_("\nDid you mean this?",
 			      "\nDid you mean one of these?",
 			   n));
 
-		for (i = 0; i < n; i++)
-			fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
+		term = terminal_open();
+		if (!term || !do_prompt) {
+			for (i = 0; i < n; i++)
+				fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
+			if (isatty(2) && do_advise && advice_typo_prompt) {
+				fprintf(stderr, "\n");
+				advise(_(message_advice_prompt_ability));
+			}
+		} else if (n == 1) {
+			char *in;
+			const char *ret;
+			fprintf(stderr, "\t%s\n", main_cmds.names[0]->name);
+			in = terminal_prompt(term, "[Y/n] ", 1);
+			terminal_close(term);
+			switch (in[0]) {
+			case 'y': case 'Y': case 0:
+				ret = xstrdup(main_cmds.names[0]->name);
+				clean_cmdnames(&main_cmds);
+				return ret;
+			/* otherwise, don't do anything */
+			}
+		} else {
+			char *in;
+			const char *ret;
+			int opt;
+			for (i = 0; i < n; i++)
+				fprintf(stderr, "%d:\t%s\n", i + 1, main_cmds.names[i]->name);
+			in = terminal_prompt(term, "[N/1/2/...] ", 1);
+			terminal_close(term);
+			switch (in[0]) {
+			case 'n': case 'N': case 0:
+				;
+			default:
+				opt = atoi(in);
+				if (0 < opt && opt <= n) {
+					ret = xstrdup(main_cmds.names[opt - 1]->name);
+					clean_cmdnames(&main_cmds);
+					return ret;
+				}
+			}
+		}
 	}
 
 	exit(1);
-- 
1.7.12.rc1.187.g6dd9156

  reply	other threads:[~2012-08-05 18:46 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-05-06  6:55 [PATCH 0/4] allow recovery from command name typos Tay Ray Chuan
2012-05-06  6:55 ` [PATCH 1/4] help.c::uniq: plug a leak Tay Ray Chuan
2012-05-06  6:55   ` [PATCH 2/4] help.c::exclude_cmds: " Tay Ray Chuan
2012-05-06  6:55     ` [PATCH 3/4] help.c: plug a leak when help.autocorrect is set Tay Ray Chuan
2012-05-06  6:55       ` [PATCH 4/4] allow recovery from command name typos Tay Ray Chuan
2012-05-06  8:21         ` Jeff King
2012-05-06 16:07           ` Tay Ray Chuan
2012-05-07  9:43             ` Thomas Rast
2012-05-07 15:49               ` Tay Ray Chuan
2012-05-07 17:41               ` Junio C Hamano
2012-05-09 15:06                 ` Tay Ray Chuan
2012-05-09 17:03                   ` Junio C Hamano
     [not found]         ` <CAOBOgRaDEgAqXWmdC6hrudkL5OwzeMffbj2RtKMxf2TsYWzotA@mail.gmail.com>
2012-05-06 16:04           ` Tay Ray Chuan
2012-05-06  8:12   ` [PATCH 1/4] help.c::uniq: plug a leak Jeff King
2012-05-06 15:54     ` Tay Ray Chuan
2012-05-07  7:30       ` Jeff King
2012-07-25 16:16 ` [PATCH v2 0/4] allow recovery from command name typos Tay Ray Chuan
2012-07-25 16:16   ` [PATCH v2 1/4] help.c::uniq: plug a leak Tay Ray Chuan
2012-07-25 16:16     ` [PATCH v2 2/4] help.c::exclude_cmds: realloc() before copy, " Tay Ray Chuan
2012-07-25 16:16       ` [PATCH v2 3/4] help.c: plug leaks with(out) help.autocorrect Tay Ray Chuan
2012-07-25 16:16         ` [PATCH v2 4/4] allow recovery from command name typos Tay Ray Chuan
2012-07-25 17:57           ` Junio C Hamano
2012-07-26 17:08             ` Tay Ray Chuan
2012-07-26 17:26               ` Jeff King
2012-07-26 17:59                 ` Junio C Hamano
2012-07-26 18:37                   ` Jeff King
2012-07-26 17:53               ` Junio C Hamano
2012-07-25 17:47         ` [PATCH v2 3/4] help.c: plug leaks with(out) help.autocorrect Junio C Hamano
2012-07-25 17:39       ` [PATCH v2 2/4] help.c::exclude_cmds: realloc() before copy, plug a leak Junio C Hamano
2012-08-05 18:45 ` [PATCH v3 0/2] allow recovery from command name typos Tay Ray Chuan
2012-08-05 18:45   ` [PATCH v3 1/2] add interface for /dev/tty interaction Tay Ray Chuan
2012-08-05 18:45     ` Tay Ray Chuan [this message]
2012-08-06  0:50       ` [PATCH v3 2/2] allow recovery from command name typos Junio C Hamano
2012-08-05 20:11     ` [PATCH v3 1/2] add interface for /dev/tty interaction Junio C Hamano
2012-08-06 19:45       ` Jeff King
2012-08-06 19:56         ` Jeff King
2012-08-06 20:01           ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1344192340-19415-3-git-send-email-rctay89@gmail.com \
    --to=rctay89@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=peff@peff.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).