Skip to content

Commit

Permalink
Add rudimentary command-line history (up/down arrow)
Browse files Browse the repository at this point in the history
This commit adds very rudimentary command-line history support. Use the
up/down arrow to navigate the history.

This commit also adds an additional command, "history" to view the
history.
  • Loading branch information
cculianu committed Jul 12, 2021
1 parent 6ffa228 commit 4c4a63f
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 2 deletions.
89 changes: 89 additions & 0 deletions refterm_example_terminal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,18 @@ static void ExecuteCommandLine(example_terminal *Terminal)
{
AppendOutput(Terminal, "%s\n", B);
}
else if (StringsAreEqual(Terminal->CommandLine, "history"))
{
const int ovr = Terminal->CommandLineHistoryCount > CommandLineHistorySize;
AppendOutput(Terminal, "History size: %u (max: %u)\n",
ovr ? CommandLineHistorySize : Terminal->CommandLineHistoryCount,
CommandLineHistorySize);
for (uint32_t n = 0, i = ovr ? Terminal->CommandLineHistoryCount - CommandLineHistorySize : 0;
i < Terminal->CommandLineHistoryCount;
++i, ++n) {
AppendOutput(Terminal, "%3u %s\n", n, Terminal->CommandLineHistory[i % CommandLineHistorySize].CommandLine);
}
}
else if(StringsAreEqual(Terminal->CommandLine, ""))
{
}
Expand All @@ -1060,6 +1072,72 @@ static void ExecuteCommandLine(example_terminal *Terminal)
}
}

static void PushCommandHistory(example_terminal *Terminal)
{
if (!Terminal->CommandLineCount) {
Terminal->CommandLineHistoryCursor = 0; // indicate we are not going back/forth through history
return; // don't push empty lines to history
}
if (Terminal->CommandLineHistoryCount) {
// check that top and command line don't match (don't push dupes)
const uint32_t top = (Terminal->CommandLineHistoryCount - 1) % CommandLineHistorySize;
char cmdTmp[CommandLineSize + 1];
memcpy(cmdTmp, Terminal->CommandLine, Terminal->CommandLineCount);
cmdTmp[Terminal->CommandLineCount] = 0;
if (StringsAreEqual(Terminal->CommandLineHistory[top].CommandLine, cmdTmp)) {
Terminal->CommandLineHistoryCursor = 0; // indicate we are not going back/forth through history
return; // don't push dupes to history
}
}
const uint32_t index = Terminal->CommandLineHistoryCount++ % CommandLineHistorySize;
Terminal->CommandLineHistory[index].CommandLineCount = Terminal->CommandLineCount;
memcpy(Terminal->CommandLineHistory[index].CommandLine, Terminal->CommandLine, CommandLineSize);
Terminal->CommandLineHistory[index].CommandLine[Terminal->CommandLineCount] = 0; // ensure NUL termination
Terminal->CommandLineHistoryCursor = 0; // indicate we are not going back/forth through history
}

static void CopyCommandHistoryCursorToCommandLine(example_terminal *Terminal)
{
if (Terminal->CommandLineHistoryCount && Terminal->CommandLineHistoryCursor) {
const uint32_t index = (Terminal->CommandLineHistoryCursor - 1) % CommandLineHistorySize;
memcpy(Terminal->CommandLine, Terminal->CommandLineHistory[index].CommandLine, CommandLineSize);
Terminal->CommandLineCount = Terminal->CommandLineHistory[index].CommandLineCount;
}
}

static void CommandHistoryPrev(example_terminal *Terminal)
{
if (!Terminal->CommandLineHistoryCount) {
// no history
Terminal->CommandLineHistoryCursor = 0;
return;
}
if (!Terminal->CommandLineHistoryCursor) {
// no cursor set, initialize to 1 past end of history
Terminal->CommandLineHistoryCursor = 1 + Terminal->CommandLineHistoryCount;
}
else if (Terminal->CommandLineHistoryCount - (Terminal->CommandLineHistoryCursor-1) >= CommandLineHistorySize) {
// at beginning of history
return;
}
Terminal->CommandLineHistoryCursor--;
CopyCommandHistoryCursorToCommandLine(Terminal);
}

static void CommandHistoryNext(example_terminal *Terminal)
{
if (!Terminal->CommandLineHistoryCursor
|| Terminal->CommandLineHistoryCursor >= Terminal->CommandLineHistoryCount) {
// not iterating back through history, or at top of history/no history
// clear line, clear cursor
Terminal->CommandLineCount = 0;
Terminal->CommandLineHistoryCursor = 0;
return;
}
Terminal->CommandLineHistoryCursor++;
CopyCommandHistoryCursorToCommandLine(Terminal);
}

static int IsUTF8Extension(char A)
{
int Result = ((A & 0xc0) == 0x80);
Expand Down Expand Up @@ -1091,6 +1169,16 @@ static void ProcessMessages(example_terminal *Terminal)
{
Terminal->ViewingLineOffset += Terminal->ScreenBuffer.DimY/2;
} break;

case VK_UP:
{
CommandHistoryPrev(Terminal);
} break;

case VK_DOWN:
{
CommandHistoryNext(Terminal);
} break;
}

if(Terminal->ViewingLineOffset > 0)
Expand Down Expand Up @@ -1124,6 +1212,7 @@ static void ProcessMessages(example_terminal *Terminal)

case VK_RETURN:
{
PushCommandHistory(Terminal);
ExecuteCommandLine(Terminal);
Terminal->CommandLineCount = 0;
Terminal->ViewingLineOffset = 0;
Expand Down
13 changes: 11 additions & 2 deletions refterm_example_terminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,17 @@ typedef struct

wchar_t LastChar;
uint32_t CommandLineCount;
char CommandLine[256];
#define CommandLineSize 256
char CommandLine[CommandLineSize];

#define CommandLineHistorySize 96
// TODO(Calin): This should really be a linked-list
struct {
uint32_t CommandLineCount;
char CommandLine[CommandLineSize];
} CommandLineHistory[CommandLineHistorySize];
uint32_t CommandLineHistoryCount;
uint32_t CommandLineHistoryCursor;

int NoThrottle;
int DebugHighlighting;
Expand Down Expand Up @@ -120,4 +130,3 @@ typedef struct
#define MaxDirectCodepoint 126
gpu_glyph_index ReservedTileTable[MaxDirectCodepoint - MinDirectCodepoint + 1];
} example_terminal;

0 comments on commit 4c4a63f

Please sign in to comment.