terminal: work around macos poll() bug

On macos the builtin "add -p" does not handle keys that generate escape sequences because poll() does not work with terminals there. Switch to using select() on non-windows platforms to work around this. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Phillip Wood committed Mar 16, 2022 at 18:54 UTC 6606d99bae4161289d498b51a21acd11aa09e6ef
1 file changed +36 -6
compat/terminal.c
+36 -6
@@ -92,6 +92,31 @@ static int enable_non_canonical(enum save_term_flags flags)
92 return disable_bits(flags, ICANON | ECHO);
93 }
94
95 +/*
96 + * On macos it is not possible to use poll() with a terminal so use select
97 + * instead.
98 + */
99 +static int getchar_with_timeout(int timeout)
100 +{
101 + struct timeval tv, *tvp = NULL;
102 + fd_set readfds;
103 + int res;
104 +
105 + if (timeout >= 0) {
106 + tv.tv_sec = timeout / 1000;
107 + tv.tv_usec = (timeout % 1000) * 1000;
108 + tvp = &tv;
109 + }
110 +
111 + FD_ZERO(&readfds);
112 + FD_SET(0, &readfds);
113 + res = select(1, &readfds, NULL, NULL, tvp);
114 + if (res <= 0)
115 + return EOF;
116 +
117 + return getchar();
118 +}
119 +
120 #elif defined(GIT_WINDOWS_NATIVE)
121
122 #define INPUT_PATH "CONIN$"
@@ -257,6 +282,16 @@ static int mingw_getchar(void)
282 }
283 #define getchar mingw_getchar
284
285 +static int getchar_with_timeout(int timeout)
286 +{
287 + struct pollfd pfd = { .fd = 0, .events = POLLIN };
288 +
289 + if (poll(&pfd, 1, timeout) < 1)
290 + return EOF;
291 +
292 + return getchar();
293 +}
294 +
295 #endif
296
297 #ifndef FORCE_TEXT
@@ -407,12 +442,7 @@ int read_key_without_echo(struct strbuf *buf)
442 * half a second when we know that the sequence is complete.
443 */
444 while (!is_known_escape_sequence(buf->buf)) {
410 - struct pollfd pfd = { .fd = 0, .events = POLLIN };
411 -
412 - if (poll(&pfd, 1, 500) < 1)
413 - break;
414 -
415 - ch = getchar();
445 + ch = getchar_with_timeout(500);
446 if (ch == EOF)
447 break;
448 strbuf_addch(buf, ch);