| ... | ... |
@@ -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 |
} |