add -i: ignore terminal escape sequences

On the author's terminal, the up-arrow input sequence is ^[[A, and
thus fat-fingering an up-arrow into 'git checkout -p' is quite
dangerous: git-add--interactive.perl will ignore the ^[ and [
characters and happily treat A as "discard everything".

As a band-aid fix, use Term::Cap to get all terminal capabilities.
Then use the heuristic that any capability value that starts with ^[
(i.e., \e in perl) must be a key input sequence.  Finally, given an
input that starts with ^[, read more characters until we have read a
full escape sequence, then return that to the caller.  We use a
timeout of 0.5 seconds on the subsequent reads to avoid getting stuck
if the user actually input a lone ^[.

Since none of the currently recognized keys start with ^[, the net
result is that the sequence as a whole will be ignored and the help

Signed-off-by: Thomas Rast <>
Signed-off-by: Junio C Hamano <>
Thomas Rast 12 years ago committed by Junio C Hamano
parent ea1ab4b280
commit b5cc003253
  1. 19

@ -45,6 +45,9 @@ my ($diff_new_color) =
my $normal_color = $repo->get_color("", "reset");
my $use_readkey = 0;
my $use_termcap = 0;
my %term_escapes;
sub ReadMode;
sub ReadKey;
if ($repo->config_bool("interactive.singlekey")) {
@ -53,6 +56,14 @@ if ($repo->config_bool("interactive.singlekey")) {
$use_readkey = 1;
eval {
require Term::Cap;
my $termcap = Term::Cap->Tgetent;
foreach (values %$termcap) {
$term_escapes{$_} = 1 if /^\e/;
$use_termcap = 1;
sub colored {
@ -1067,6 +1078,14 @@ sub prompt_single_character {
ReadMode 'cbreak';
my $key = ReadKey 0;
ReadMode 'restore';
if ($use_termcap and $key eq "\e") {
while (!defined $term_escapes{$key}) {
my $next = ReadKey 0.5;
last if (!defined $next);
$key .= $next;
$key =~ s/\e/^[/;
print "$key" if defined $key;
print "\n";
return $key;