Browse code

Abort if Esc is pressed

Jason Felice authored on 04/05/2018 16:32:40
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,9 @@ 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 93
 	FD_ZERO(&readfs);
94 94
 	FD_SET(tty->fdin, &readfs);
95 95
 	select(tty->fdin + 1, &readfs, NULL, NULL, &tv);
... ...
@@ -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);
... ...
@@ -238,6 +238,7 @@ void tty_interface_init(tty_interface_t *state, tty_t *tty, choices_t *choices,
238 238
 	state->tty = tty;
239 239
 	state->choices = choices;
240 240
 	state->options = options;
241
+	state->ambiguous_key_pending = 0;
241 242
 
242 243
 	strcpy(state->input, "");
243 244
 	strcpy(state->search, "");
... ...
@@ -260,7 +261,9 @@ typedef struct {
260 261
 
261 262
 #define KEY_CTRL(key) ((const char[]){((key) - ('@')), '\0'})
262 263
 
263
-static const keybinding_t keybindings[] = {{"\x7f", action_del_char},	/* DEL */
264
+static const keybinding_t keybindings[] = {{"\x1b", action_exit},       /* ESC */
265
+					   {"\x7f", action_del_char},	/* DEL */
266
+
264 267
 					   {KEY_CTRL('H'), action_del_char}, /* Backspace (C-H) */
265 268
 					   {KEY_CTRL('W'), action_del_word}, /* C-W */
266 269
 					   {KEY_CTRL('U'), action_del_all},  /* C-U */
... ...
@@ -295,23 +298,40 @@ static const keybinding_t keybindings[] = {{"\x7f", action_del_char},	/* DEL */
295 298
 
296 299
 #undef KEY_CTRL
297 300
 
298
-static void handle_input(tty_interface_t *state, const char *s) {
301
+static void handle_input(tty_interface_t *state, const char *s, int handle_ambiguous_key) {
302
+	state->ambiguous_key_pending = 0;
303
+
299 304
 	char *input = state->input;
300 305
 	strcat(state->input, s);
301 306
 
302
-	/* See if we have matched a keybinding */
307
+	/* Figure out if we have completed a keybinding and whether we're in the
308
+	 * middle of one (both can happen, because of Esc). */
309
+	int found_keybinding = -1;
310
+	int in_middle = 0;
303 311
 	for (int i = 0; keybindings[i].key; i++) {
304
-		if (!strcmp(input, keybindings[i].key)) {
305
-			keybindings[i].action(state);
306
-			strcpy(input, "");
307
-			return;
308
-		}
312
+		if (!strcmp(input, keybindings[i].key))
313
+			found_keybinding = i;
314
+		else if (!strncmp(input, keybindings[i].key, strlen(state->input)))
315
+			in_middle = 1;
309 316
 	}
310 317
 
311
-	/* Check if we are in the middle of a keybinding */
312
-	for (int i = 0; keybindings[i].key; i++)
313
-		if (!strncmp(input, keybindings[i].key, strlen(input)))
314
-			return;
318
+	/* If we have an unambiguous keybinding, run it.  */
319
+	if (found_keybinding != -1 && (!in_middle || handle_ambiguous_key)) {
320
+		keybindings[found_keybinding].action(state);
321
+		strcpy(input, "");
322
+		return;
323
+	}
324
+
325
+	/* We could have a complete keybinding, or could be in the middle of one.
326
+	 * We'll need to wait a few milliseconds to find out. */
327
+	if (found_keybinding != -1 && in_middle) {
328
+		state->ambiguous_key_pending = 1;
329
+		return;
330
+	}
331
+
332
+	/* Wait for more if we are in the middle of a keybinding */
333
+	if (in_middle)
334
+		return;
315 335
 
316 336
 	/* No matching keybinding, add to search */
317 337
 	for (int i = 0; input[i]; i++)
... ...
@@ -328,13 +348,21 @@ int tty_interface_run(tty_interface_t *state) {
328 348
 	for (;;) {
329 349
 		do {
330 350
 			char s[2] = {tty_getchar(state->tty), '\0'};
331
-			handle_input(state, s);
351
+			handle_input(state, s, 0);
332 352
 
333 353
 			if (state->exit >= 0)
334 354
 				return state->exit;
335 355
 
336 356
 			draw(state);
337
-		} while (tty_input_ready(state->tty));
357
+		} while (tty_input_ready(state->tty, state->ambiguous_key_pending));
358
+
359
+		if (state->ambiguous_key_pending) {
360
+			char s[1] = "";
361
+			handle_input(state, s, 1);
362
+
363
+			if (state->exit >= 0)
364
+				return state->exit;
365
+		}
338 366
 
339 367
 		update_state(state);
340 368
 	}
... ...
@@ -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;