feat: history browsing with arrow keys

This commit is contained in:
2026-10-10 01:44:12 +02:00
parent a1df9fca4f
commit 0794ed12ed

109
src/msh.c
View File

@@ -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);
}