| ... | ... |
@@ -151,10 +151,6 @@ static void append_search(tty_interface_t *state, char ch) {
|
| 151 | 151 |
} |
| 152 | 152 |
} |
| 153 | 153 |
|
| 154 |
-#define KEY_CTRL(key) ((key) - ('@'))
|
|
| 155 |
-#define KEY_DEL 127 |
|
| 156 |
-#define KEY_ESC 27 |
|
| 157 |
- |
|
| 158 | 154 |
static void update_search(tty_interface_t *state) {
|
| 159 | 155 |
choices_search(state->choices, state->search); |
| 160 | 156 |
strcpy(state->last_search, state->search); |
| ... | ... |
@@ -170,6 +166,7 @@ void tty_interface_init(tty_interface_t *state, tty_t *tty, choices_t *choices, |
| 170 | 166 |
state->choices = choices; |
| 171 | 167 |
state->options = options; |
| 172 | 168 |
|
| 169 |
+ strcpy(state->input, ""); |
|
| 173 | 170 |
strcpy(state->search, ""); |
| 174 | 171 |
strcpy(state->last_search, ""); |
| 175 | 172 |
|
| ... | ... |
@@ -181,42 +178,67 @@ void tty_interface_init(tty_interface_t *state, tty_t *tty, choices_t *choices, |
| 181 | 178 |
update_search(state); |
| 182 | 179 |
} |
| 183 | 180 |
|
| 184 |
-int tty_interface_run(tty_interface_t *state) {
|
|
| 185 |
- tty_t *tty = state->tty; |
|
| 181 |
+typedef struct {
|
|
| 182 |
+ const char *key; |
|
| 183 |
+ void (*action)(tty_interface_t *); |
|
| 184 |
+} keybinding_t; |
|
| 185 |
+ |
|
| 186 |
+#define KEY_CTRL(key) ((const char[]){((key) - ('@')), '\0'})
|
|
| 187 |
+ |
|
| 188 |
+static const keybinding_t keybindings[] = {{"\x7f", action_del_char}, /* DEL */
|
|
| 189 |
+ {KEY_CTRL('H'), action_del_char}, /* Backspace (C-H) */
|
|
| 190 |
+ {KEY_CTRL('W'), action_del_word}, /* C-W */
|
|
| 191 |
+ {KEY_CTRL('U'), action_del_all}, /* C-U */
|
|
| 192 |
+ {KEY_CTRL('I'), action_autocomplete}, /* TAB (C-I ) */
|
|
| 193 |
+ {KEY_CTRL('C'), action_exit}, /* C-C */
|
|
| 194 |
+ {KEY_CTRL('D'), action_exit}, /* C-D */
|
|
| 195 |
+ {KEY_CTRL('M'), action_emit}, /* CR */
|
|
| 196 |
+ {KEY_CTRL('P'), action_prev}, /* C-P */
|
|
| 197 |
+ {KEY_CTRL('N'), action_next}, /* C-N */
|
|
| 198 |
+ |
|
| 199 |
+ {"\x1b[A", action_prev}, /* UP */
|
|
| 200 |
+ {"\x1bOA", action_prev}, /* UP */
|
|
| 201 |
+ {"\x1b[B", action_next}, /* DOWN */
|
|
| 202 |
+ {"\x1bOB", action_next}, /* DOWN */
|
|
| 203 |
+ {NULL, NULL}};
|
|
| 204 |
+ |
|
| 205 |
+#undef KEY_CTRL |
|
| 206 |
+ |
|
| 207 |
+void handle_input(tty_interface_t *state) {
|
|
| 208 |
+ char *input = state->input; |
|
| 209 |
+ |
|
| 210 |
+ /* See if we have matched a keybinding */ |
|
| 211 |
+ for (int i = 0; keybindings[i].key; i++) {
|
|
| 212 |
+ if (!strcmp(input, keybindings[i].key)) {
|
|
| 213 |
+ keybindings[i].action(state); |
|
| 214 |
+ strcpy(input, ""); |
|
| 215 |
+ return; |
|
| 216 |
+ } |
|
| 217 |
+ } |
|
| 218 |
+ |
|
| 219 |
+ /* Check if we are in the middle of a keybinding */ |
|
| 220 |
+ for (int i = 0; keybindings[i].key; i++) |
|
| 221 |
+ if (!strncmp(input, keybindings[i].key, strlen(input))) |
|
| 222 |
+ return; |
|
| 186 | 223 |
|
| 187 |
- char ch; |
|
| 224 |
+ /* No matching keybinding, add to search */ |
|
| 225 |
+ for (int i = 0; input[i]; i++) |
|
| 226 |
+ if (isprint(input[i])) |
|
| 227 |
+ append_search(state, input[i]); |
|
| 228 |
+ |
|
| 229 |
+ /* We have processed the input, so clear it */ |
|
| 230 |
+ strcpy(input, ""); |
|
| 231 |
+} |
|
| 232 |
+ |
|
| 233 |
+int tty_interface_run(tty_interface_t *state) {
|
|
| 188 | 234 |
while (state->exit < 0) {
|
| 189 | 235 |
draw(state); |
| 190 |
- ch = tty_getchar(tty); |
|
| 191 |
- if (isprint(ch)) {
|
|
| 192 |
- append_search(state, ch); |
|
| 193 |
- } else if (ch == KEY_DEL || ch == KEY_CTRL('H')) { /* DEL || Backspace (C-H) */
|
|
| 194 |
- action_del_char(state); |
|
| 195 |
- } else if (ch == KEY_CTRL('U')) { /* C-U */
|
|
| 196 |
- action_del_all(state); |
|
| 197 |
- } else if (ch == KEY_CTRL('W')) { /* C-W */
|
|
| 198 |
- action_del_word(state); |
|
| 199 |
- } else if (ch == KEY_CTRL('N')) { /* C-N */
|
|
| 200 |
- action_next(state); |
|
| 201 |
- } else if (ch == KEY_CTRL('P')) { /* C-P */
|
|
| 202 |
- action_prev(state); |
|
| 203 |
- } else if (ch == KEY_CTRL('I')) { /* TAB (C-I) */
|
|
| 204 |
- action_autocomplete(state); |
|
| 205 |
- } else if (ch == KEY_CTRL('C') || ch == KEY_CTRL('D')) { /* ^C || ^D */
|
|
| 206 |
- action_exit(state); |
|
| 207 |
- } else if (ch == KEY_CTRL('M')) { /* CR */
|
|
| 208 |
- action_emit(state); |
|
| 209 |
- } else if (ch == KEY_ESC) { /* ESC */
|
|
| 210 |
- ch = tty_getchar(tty); |
|
| 211 |
- if (ch == '[' || ch == 'O') {
|
|
| 212 |
- ch = tty_getchar(tty); |
|
| 213 |
- if (ch == 'A') { /* UP ARROW */
|
|
| 214 |
- action_prev(state); |
|
| 215 |
- } else if (ch == 'B') { /* DOWN ARROW */
|
|
| 216 |
- action_next(state); |
|
| 217 |
- } |
|
| 218 |
- } |
|
| 219 |
- } |
|
| 236 |
+ |
|
| 237 |
+ char s[2] = {tty_getchar(state->tty), '\0'};
|
|
| 238 |
+ strcat(state->input, s); |
|
| 239 |
+ |
|
| 240 |
+ handle_input(state); |
|
| 241 |
+ |
|
| 220 | 242 |
update_state(state); |
| 221 | 243 |
} |
| 222 | 244 |
|