Browse code

Merge branch 'abort_on_escape'

John Hawthorn authored on 10/09/2018 04:02:45
Showing 5 changed files

... ...
@@ -54,6 +54,9 @@ Usage help.
54 54
 .BR "ENTER"
55 55
 Print the selected item to stdout and exit
56 56
 .TP
57
+.BR "Ctrl+c, Esc"
58
+Abort selecting and exit
59
+.TP
57 60
 .BR "Up Arrow, Ctrl+p"
58 61
 Select the previous item
59 62
 .TP
... ...
@@ -87,9 +87,10 @@ char tty_getchar(tty_t *tty) {
87 87
 	}
88 88
 }
89 89
 
90
-int tty_input_ready(tty_t *tty) {
90
+int tty_input_ready(tty_t *tty, int pending) {
91 91
 	fd_set readfs;
92
-	struct timeval tv = {0, 0};
92
+	struct timeval tv = {0, pending ? 500000 : 0};
93
+	FD_ZERO(&readfs);
93 94
 	FD_SET(tty->fdin, &readfs);
94 95
 	select(tty->fdin + 1, &readfs, NULL, NULL, &tv);
95 96
 	return FD_ISSET(tty->fdin, &readfs);
... ...
@@ -17,7 +17,7 @@ void tty_close(tty_t *tty);
17 17
 void tty_init(tty_t *tty, const char *tty_filename);
18 18
 void tty_getwinsz(tty_t *tty);
19 19
 char tty_getchar(tty_t *tty);
20
-int tty_input_ready(tty_t *tty);
20
+int tty_input_ready(tty_t *tty, int pending);
21 21
 
22 22
 void tty_setfg(tty_t *tty, int fg);
23 23
 void tty_setinvert(tty_t *tty);
... ...
@@ -257,6 +257,7 @@ void tty_interface_init(tty_interface_t *state, tty_t *tty, choices_t *choices,
257 257
 	state->tty = tty;
258 258
 	state->choices = choices;
259 259
 	state->options = options;
260
+	state->ambiguous_key_pending = 0;
260 261
 
261 262
 	strcpy(state->input, "");
262 263
 	strcpy(state->search, "");
... ...
@@ -279,7 +280,9 @@ typedef struct {
279 280
 
280 281
 #define KEY_CTRL(key) ((const char[]){((key) - ('@')), '\0'})
281 282
 
282
-static const keybinding_t keybindings[] = {{"\x7f", action_del_char},	/* DEL */
283
+static const keybinding_t keybindings[] = {{"\x1b", action_exit},       /* ESC */
284
+					   {"\x7f", action_del_char},	/* DEL */
285
+
283 286
 					   {KEY_CTRL('H'), action_del_char}, /* Backspace (C-H) */
284 287
 					   {KEY_CTRL('W'), action_del_word}, /* C-W */
285 288
 					   {KEY_CTRL('U'), action_del_all},  /* C-U */
... ...
@@ -314,23 +317,40 @@ static const keybinding_t keybindings[] = {{"\x7f", action_del_char},	/* DEL */
314 317
 
315 318
 #undef KEY_CTRL
316 319
 
317
-static void handle_input(tty_interface_t *state, const char *s) {
320
+static void handle_input(tty_interface_t *state, const char *s, int handle_ambiguous_key) {
321
+	state->ambiguous_key_pending = 0;
322
+
318 323
 	char *input = state->input;
319 324
 	strcat(state->input, s);
320 325
 
321
-	/* See if we have matched a keybinding */
326
+	/* Figure out if we have completed a keybinding and whether we're in the
327
+	 * middle of one (both can happen, because of Esc). */
328
+	int found_keybinding = -1;
329
+	int in_middle = 0;
322 330
 	for (int i = 0; keybindings[i].key; i++) {
323
-		if (!strcmp(input, keybindings[i].key)) {
324
-			keybindings[i].action(state);
325
-			strcpy(input, "");
326
-			return;
327
-		}
331
+		if (!strcmp(input, keybindings[i].key))
332
+			found_keybinding = i;
333
+		else if (!strncmp(input, keybindings[i].key, strlen(state->input)))
334
+			in_middle = 1;
328 335
 	}
329 336
 
330
-	/* Check if we are in the middle of a keybinding */
331
-	for (int i = 0; keybindings[i].key; i++)
332
-		if (!strncmp(input, keybindings[i].key, strlen(input)))
333
-			return;
337
+	/* If we have an unambiguous keybinding, run it.  */
338
+	if (found_keybinding != -1 && (!in_middle || handle_ambiguous_key)) {
339
+		keybindings[found_keybinding].action(state);
340
+		strcpy(input, "");
341
+		return;
342
+	}
343
+
344
+	/* We could have a complete keybinding, or could be in the middle of one.
345
+	 * We'll need to wait a few milliseconds to find out. */
346
+	if (found_keybinding != -1 && in_middle) {
347
+		state->ambiguous_key_pending = 1;
348
+		return;
349
+	}
350
+
351
+	/* Wait for more if we are in the middle of a keybinding */
352
+	if (in_middle)
353
+		return;
334 354
 
335 355
 	/* No matching keybinding, add to search */
336 356
 	for (int i = 0; input[i]; i++)
... ...
@@ -347,13 +367,21 @@ int tty_interface_run(tty_interface_t *state) {
347 367
 	for (;;) {
348 368
 		do {
349 369
 			char s[2] = {tty_getchar(state->tty), '\0'};
350
-			handle_input(state, s);
370
+			handle_input(state, s, 0);
351 371
 
352 372
 			if (state->exit >= 0)
353 373
 				return state->exit;
354 374
 
355 375
 			draw(state);
356
-		} while (tty_input_ready(state->tty));
376
+		} while (tty_input_ready(state->tty, state->ambiguous_key_pending));
377
+
378
+		if (state->ambiguous_key_pending) {
379
+			char s[1] = "";
380
+			handle_input(state, s, 1);
381
+
382
+			if (state->exit >= 0)
383
+				return state->exit;
384
+		}
357 385
 
358 386
 		update_state(state);
359 387
 	}
... ...
@@ -16,6 +16,7 @@ typedef struct {
16 16
 	char last_search[SEARCH_SIZE_MAX + 1];
17 17
 	size_t cursor;
18 18
 
19
+	int ambiguous_key_pending;
19 20
 	char input[32]; /* Pending input buffer */
20 21
 
21 22
 	int exit;