built-in add -p: handle Escape sequences in interactive.singlekey mode
This recapitulates part of b5cc003253 (add -i: ignore terminal escape
sequences, 2011-05-17):
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
displayed.
Note that we leave part for later which uses "Term::Cap to get all
terminal capabilities", for several reasons:
1. it is actually not really necessary, as the timeout of 0.5 seconds
should be plenty sufficient to catch Escape sequences,
2. it is cleaner to keep the change to special-case Escape sequences
separate from the change that reads all terminal capabilities to
speed things up, and
3. in practice, relying on the terminal capabilities is a bit overrated,
as the information could be incomplete, or plain wrong. For example,
in this developer's tmux sessions, the terminal capabilities claim
that the "cursor up" sequence is ^[M, but the actual sequence
produced by the "cursor up" key is ^[[A.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
parent
04f816b125
commit
e118f06396
|
|
@ -161,6 +161,37 @@ static int enable_non_canonical(void)
|
||||||
return disable_bits(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
|
return disable_bits(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Override `getchar()`, as the default implementation does not use
|
||||||
|
* `ReadFile()`.
|
||||||
|
*
|
||||||
|
* This poses a problem when we want to see whether the standard
|
||||||
|
* input has more characters, as the default of Git for Windows is to start the
|
||||||
|
* Bash in a MinTTY, which uses a named pipe to emulate a pty, in which case
|
||||||
|
* our `poll()` emulation calls `PeekNamedPipe()`, which seems to require
|
||||||
|
* `ReadFile()` to be called first to work properly (it only reports 0
|
||||||
|
* available bytes, otherwise).
|
||||||
|
*
|
||||||
|
* So let's just override `getchar()` with a version backed by `ReadFile()` and
|
||||||
|
* go our merry ways from here.
|
||||||
|
*/
|
||||||
|
static int mingw_getchar(void)
|
||||||
|
{
|
||||||
|
DWORD read = 0;
|
||||||
|
unsigned char ch;
|
||||||
|
|
||||||
|
if (!ReadFile(GetStdHandle(STD_INPUT_HANDLE), &ch, 1, &read, NULL))
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
if (!read) {
|
||||||
|
error("Unexpected 0 read");
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
#define getchar mingw_getchar
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FORCE_TEXT
|
#ifndef FORCE_TEXT
|
||||||
|
|
@ -228,8 +259,31 @@ int read_key_without_echo(struct strbuf *buf)
|
||||||
restore_term();
|
restore_term();
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
strbuf_addch(buf, ch);
|
strbuf_addch(buf, ch);
|
||||||
|
|
||||||
|
if (ch == '\033' /* ESC */) {
|
||||||
|
/*
|
||||||
|
* We are most likely looking at an Escape sequence. Let's try
|
||||||
|
* to read more bytes, waiting at most half a second, assuming
|
||||||
|
* that the sequence is complete if we did not receive any byte
|
||||||
|
* within that time.
|
||||||
|
*
|
||||||
|
* Start by replacing the Escape byte with ^[ */
|
||||||
|
strbuf_splice(buf, buf->len - 1, 1, "^[", 2);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
struct pollfd pfd = { .fd = 0, .events = POLLIN };
|
||||||
|
|
||||||
|
if (poll(&pfd, 1, 500) < 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ch = getchar();
|
||||||
|
if (ch == EOF)
|
||||||
|
return 0;
|
||||||
|
strbuf_addch(buf, ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
restore_term();
|
restore_term();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue