Add history
This commit is contained in:
@@ -15,7 +15,8 @@ sh_OBJS=$(O)/sh.o \
|
||||
$(O)/parse.o \
|
||||
$(O)/builtin.o \
|
||||
$(O)/job.o \
|
||||
$(O)/env.o
|
||||
$(O)/env.o \
|
||||
$(O)/history.o
|
||||
|
||||
all: mkdirs $(O)/sh
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#define HISTORY_SIZE 128
|
||||
|
||||
struct history_entry {
|
||||
char data[256];
|
||||
struct history_entry *prev, *next;
|
||||
};
|
||||
|
||||
void history_insert(const char *cmd);
|
||||
struct history_entry *history_head(void);
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "history.h"
|
||||
|
||||
static struct history_entry *g_history_head, *g_history_tail;
|
||||
size_t history_size = 0;
|
||||
|
||||
struct history_entry *history_head(void) {
|
||||
return g_history_head;
|
||||
}
|
||||
|
||||
void history_insert(const char *command) {
|
||||
struct history_entry *ent;
|
||||
if (history_size == HISTORY_SIZE) {
|
||||
// Just resuse the last entry
|
||||
assert(g_history_tail && g_history_tail->prev);
|
||||
ent = g_history_tail;
|
||||
g_history_tail = g_history_tail->prev;
|
||||
g_history_tail->next = NULL;
|
||||
} else {
|
||||
ent = malloc(sizeof(struct history_entry));
|
||||
assert(ent);
|
||||
}
|
||||
|
||||
strcpy(ent->data, command);
|
||||
ent->prev = NULL;
|
||||
ent->next = g_history_head;
|
||||
if (!g_history_tail) {
|
||||
assert(!g_history_head);
|
||||
g_history_tail = ent;
|
||||
} else {
|
||||
g_history_head->prev = ent;
|
||||
}
|
||||
g_history_head = ent;
|
||||
++history_size;
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
#include <termios.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include "history.h"
|
||||
|
||||
#define KEY_UP (256)
|
||||
#define KEY_DOWN (257)
|
||||
@@ -86,6 +88,7 @@ int readline(char *buf, size_t lim) {
|
||||
int cur = 0;
|
||||
int chr;
|
||||
|
||||
struct history_entry *ent = NULL;
|
||||
struct termios t0, t1;
|
||||
|
||||
tcgetattr(STDIN_FILENO, &t0);
|
||||
@@ -118,8 +121,65 @@ int readline(char *buf, size_t lim) {
|
||||
++cur;
|
||||
}
|
||||
break;
|
||||
case KEY_UP:
|
||||
if (!ent) {
|
||||
ent = history_head();
|
||||
} else {
|
||||
ent = ent->next;
|
||||
}
|
||||
|
||||
if (ent) {
|
||||
if (cur) {
|
||||
fprintf(stdout, "\033[%dD", cur);
|
||||
}
|
||||
fputs("\033[K", stdout);
|
||||
fputs(ent->data, stdout);
|
||||
fflush(stdout);
|
||||
len = strlen(ent->data);
|
||||
cur = len;
|
||||
} else {
|
||||
if (cur) {
|
||||
fprintf(stdout, "\033[%dD", cur);
|
||||
}
|
||||
fputs("\033[K", stdout);
|
||||
fflush(stdout);
|
||||
cur = 0;
|
||||
len = 0;
|
||||
}
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if (ent) {
|
||||
ent = ent->prev;
|
||||
|
||||
if (ent) {
|
||||
if (cur) {
|
||||
fprintf(stdout, "\033[%dD", cur);
|
||||
}
|
||||
fputs("\033[K", stdout);
|
||||
fputs(ent->data, stdout);
|
||||
fflush(stdout);
|
||||
len = strlen(ent->data);
|
||||
cur = len;
|
||||
} else {
|
||||
if (cur) {
|
||||
fprintf(stdout, "\033[%dD", cur);
|
||||
}
|
||||
fputs("\033[K", stdout);
|
||||
fflush(stdout);
|
||||
cur = 0;
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (chr == KEY_UP || chr == KEY_DOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Any other move resets history position
|
||||
ent = NULL;
|
||||
|
||||
if (chr == 4) {
|
||||
if (len == 0) {
|
||||
fputs("exit\n", stderr);
|
||||
@@ -162,6 +222,13 @@ int readline(char *buf, size_t lim) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *e = buf;
|
||||
while (isspace(*e)) {
|
||||
++e;
|
||||
}
|
||||
if (*e) {
|
||||
history_insert(buf);
|
||||
}
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t0);
|
||||
return len;
|
||||
|
||||
Reference in New Issue
Block a user