aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry Jeffery <harry@exec64.co.uk>2019-09-02 15:39:50 +0100
committerHarry Jeffery <harry@exec64.co.uk>2019-09-02 15:54:50 +0100
commit14f3b8ac56875d2be066a1a93e7ebebb5927023d (patch)
treedf83add8b517ce7307764c0d1b98a2c0cc5364f6
parent5bb3308d8b81b47f940f64b70efcaac91bde1755 (diff)
downloadimv-14f3b8ac56875d2be066a1a93e7ebebb5927023d.tar.gz
console: Implement command history
-rw-r--r--src/console.c94
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;