diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/console.c | 94 |
1 files changed, 90 insertions, 4 deletions
diff --git a/src/console.c b/src/console.c index 9243e24..073274f 100644 --- a/src/console.c +++ b/src/console.c @@ -1,5 +1,7 @@ #include "console.h" +#include "list.h" + #include <assert.h> #include <ctype.h> #include <stdlib.h> @@ -14,6 +16,10 @@ struct imv_console { imv_console_callback callback; void *callback_data; + + struct list *history; + ssize_t history_item; /* -1 when not traversing history */ + char *history_before; /* contents of line before history was opened */ }; /* Iterates forwards over characters in a UTF-8 string */ @@ -60,20 +66,88 @@ static size_t prev_char(char *buffer, size_t position) return result; } +static void add_to_history(struct list *history, const char *line) +{ + /* Don't add blank lines */ + if (line[0] == '\0') { + return; + } + + /* Don't add the same line consecutively */ + if (history->len > 0 && !strcmp(history->items[history->len - 1], line)) { + return; + } + + list_append(history, strdup(line)); +} + +static void history_back(struct imv_console *console) +{ + if (console->history->len < 1) { + /* No history to browse */ + return; + } + + if (console->history_item == 0) { + /* At the top of history. Do nothing. */ + return; + } + + if (console->history_item == -1) { + /* Enter history from the bottom */ + free(console->history_before); + console->history_before = strdup(console->buffer); + console->history_item = console->history->len - 1; + } else { + /* Move back in history */ + console->history_item--; + } + + strncpy(console->buffer, + console->history->items[console->history_item], + console->buffer_len); + console->cursor = strlen(console->buffer); +} + +static void history_forward(struct imv_console *console) +{ + if (console->history_item == -1) { + /* Not in history, do nothing */ + return; + } + + if ((size_t)console->history_item == console->history->len - 1) { + /* At the end of history, restore the backup */ + strncpy(console->buffer, console->history_before, console->buffer_len); + console->cursor = strlen(console->buffer); + free(console->history_before); + console->history_before = NULL; + console->history_item = -1; + } else { + /* Move forward in history */ + console->history_item++; + strncpy(console->buffer, + console->history->items[console->history_item], + console->buffer_len); + console->cursor = strlen(console->buffer); + } + +} struct imv_console *imv_console_create(void) { struct imv_console *console = calloc(1, sizeof *console); console->buffer_len = 1024; + console->history_item = -1; + console->history = list_create(); return console; } void imv_console_free(struct imv_console *console) { - if (console->buffer) { - free(console->buffer); - console->buffer = NULL; - } + free(console->buffer); + list_deep_free(console->history); + free(console->history_before); free(console); } @@ -97,6 +171,7 @@ void imv_console_activate(struct imv_console *console) console->buffer = calloc(1, console->buffer_len); console->cursor = 0; + console->history_item = -1; } void imv_console_input(struct imv_console *console, const char *text) @@ -143,6 +218,7 @@ bool imv_console_key(struct imv_console *console, const char *key) if (console->callback) { console->callback(console->buffer, console->callback_data); } + add_to_history(console->history, console->buffer); free(console->buffer); console->buffer = NULL; return true; @@ -158,6 +234,16 @@ bool imv_console_key(struct imv_console *console, const char *key) return true; } + if (!strcmp("Up", key) || !strcmp("Ctrl+p", key)) { + history_back(console); + return true; + } + + if (!strcmp("Down", key) || !strcmp("Ctrl+n", key)) { + history_forward(console); + return true; + } + if (!strcmp("Ctrl+a", key)) { console->cursor = 0; return true; |