feat: history browsing with arrow keys
This commit is contained in:
109
src/msh.c
109
src/msh.c
@@ -153,6 +153,8 @@ int main(int argc, char** argv) {
|
||||
char** history = NULL;
|
||||
size_t historycapacity = 0;
|
||||
size_t historyi = 0;
|
||||
size_t historyoffset = 0;
|
||||
char* oldline = NULL;
|
||||
|
||||
|
||||
int pid;
|
||||
@@ -324,6 +326,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
memset(line, 0, linecapacity);
|
||||
|
||||
historyoffset = 0;
|
||||
|
||||
while ((readc = getchar()) != '\n') {
|
||||
if (readc == EOF) {
|
||||
printf("^D\n");
|
||||
@@ -341,6 +345,56 @@ int main(int argc, char** argv) {
|
||||
if (cursor < linelen) {
|
||||
cursor++;
|
||||
}
|
||||
|
||||
} else if (ansi == ANSI_CURSOR_UP || ansi == ANSI_CURSOR_DOWN) {
|
||||
int changed = 1;
|
||||
|
||||
if (ansi == ANSI_CURSOR_UP && historyoffset < historyi) {
|
||||
historyoffset++;
|
||||
} else if (ansi == ANSI_CURSOR_DOWN && historyoffset > 0) {
|
||||
historyoffset--;
|
||||
|
||||
if (historyoffset == 0) {
|
||||
free(line);
|
||||
line = oldline;
|
||||
linelen = strlen(line);
|
||||
linecapacity = linelen + 1;
|
||||
cursor = linelen;
|
||||
|
||||
oldline = NULL;
|
||||
|
||||
// Don't look up from history
|
||||
changed = 0;
|
||||
}
|
||||
} else {
|
||||
// We didn't actually change anything
|
||||
changed = 0;
|
||||
}
|
||||
|
||||
|
||||
if (changed == 1) {
|
||||
if (oldline != NULL) {
|
||||
free(oldline);
|
||||
}
|
||||
|
||||
oldline = line;
|
||||
char* historyline = history[historyi - (historyoffset)];
|
||||
size_t historylinelen = strlen(historyline);
|
||||
line = malloc(historylinelen + 1);
|
||||
if (line == NULL) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
line = strcpy(line, historyline);
|
||||
if (line == NULL) {
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cursor = historylinelen;
|
||||
linecapacity = historylinelen + 1;
|
||||
linelen = historylinelen;
|
||||
}
|
||||
} else if (ansi == ANSI_DELETE_WORD) {
|
||||
if (cursor > 0) {
|
||||
size_t index = strnrcspn(line, cursor, " \t");
|
||||
@@ -355,12 +409,8 @@ int main(int argc, char** argv) {
|
||||
size_t index = strnocspn(line, linelen, cursor, " \t");
|
||||
cursor = index;
|
||||
}
|
||||
|
||||
goto print_prompt;
|
||||
}
|
||||
|
||||
// backspace
|
||||
if (readc == 127) {
|
||||
} else if (readc == 127) {
|
||||
// backspace
|
||||
if (cursor > 0) {
|
||||
cursor--;
|
||||
linelen--;
|
||||
@@ -371,33 +421,30 @@ int main(int argc, char** argv) {
|
||||
} else {
|
||||
memmove(line + cursor, line + cursor + 1, LINESIZE - (cursor));
|
||||
}
|
||||
|
||||
// We don't want to change the line
|
||||
goto print_prompt;
|
||||
}
|
||||
|
||||
if (cursor != linelen) {
|
||||
memmove(line + cursor + 1, line + cursor, LINESIZE - cursor - 1);
|
||||
}
|
||||
|
||||
line[cursor] = readc;
|
||||
cursor++;
|
||||
linelen++;
|
||||
|
||||
// Are we out of capacity? Double line length
|
||||
while (linelen >= linecapacity - 1) {
|
||||
linecapacity *= 2;
|
||||
line = realloc(line, linecapacity);
|
||||
if (line == NULL) {
|
||||
fprintf(stderr, "Error: Failed to re-allocated line buffer");
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
} else {
|
||||
// We are typing
|
||||
if (cursor != linelen) {
|
||||
memmove(line + cursor + 1, line + cursor, LINESIZE - cursor - 1);
|
||||
}
|
||||
|
||||
memset(line + linecapacity / 2, 0, linecapacity / 2);
|
||||
line[cursor] = readc;
|
||||
cursor++;
|
||||
linelen++;
|
||||
|
||||
// Are we out of capacity? Double line length
|
||||
while (linelen >= linecapacity - 1) {
|
||||
linecapacity *= 2;
|
||||
line = realloc(line, linecapacity);
|
||||
if (line == NULL) {
|
||||
fprintf(stderr, "Error: Failed to re-allocated line buffer");
|
||||
retval = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memset(line + linecapacity / 2, 0, linecapacity / 2);
|
||||
}
|
||||
}
|
||||
|
||||
print_prompt:
|
||||
// Manual echo
|
||||
printf(ANSI_ESC "[2K" ANSI_ESC "[0G" "%s%s", prompt, line);
|
||||
for (int j = 0; j < linelen - cursor; j++) {
|
||||
@@ -530,6 +577,10 @@ cleanup:
|
||||
free(line);
|
||||
}
|
||||
|
||||
if (oldline != NULL) {
|
||||
free(oldline);
|
||||
}
|
||||
|
||||
if (tokenwork != NULL) {
|
||||
free(tokenwork);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user