From c4562e8778c10bef861aef88daa54a827447cc02 Mon Sep 17 00:00:00 2001 From: Lluciocc <114759545+Lluciocc@users.noreply.github.com> Date: Fri, 17 Apr 2026 11:40:11 +0200 Subject: [PATCH] Implement command history and input color updates --- src/userland/gui/terminal.c | 169 +++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 4 deletions(-) diff --git a/src/userland/gui/terminal.c b/src/userland/gui/terminal.c index 0b0f6cb..7d3dbdf 100644 --- a/src/userland/gui/terminal.c +++ b/src/userland/gui/terminal.c @@ -4,6 +4,7 @@ #include #include #include "libc/libui.h" +#include "libc/input.h" #include #include @@ -19,6 +20,8 @@ #define TAB_CLOSE_PAD 6 #define MAX_TABS 4 #define TTY_READ_CHUNK 512 +#define HISTORY_MAX 64 +#define HISTORY_LINE_MAX 256 typedef struct { char c; @@ -38,12 +41,21 @@ typedef struct { int cursor_col; uint32_t fg_color; uint32_t bg_color; + uint32_t input_color; int ansi_state; int ansi_params[8]; int ansi_param_count; int saved_row; int saved_col; + + + char history[HISTORY_MAX][HISTORY_LINE_MAX]; + int history_count; + int history_index; + + char current_input[HISTORY_LINE_MAX]; + int input_len; } TerminalSession; static ui_window_t g_win; @@ -663,6 +675,16 @@ static void draw_session(TerminalSession *s) { if (ch == 0) ch = ' '; color = line[col].color; } + if (s->scroll_offset == 0 && row == s->cursor_row) { + int cmd_len = 0; + while (cmd_len < s->input_len && + s->current_input[cmd_len] != ' ') { + cmd_len++; + } + if (col < cmd_len) { + color = s->input_color; + } + } char str[2] = { ch, 0 }; int x = col * CHAR_W; int y = base_y + row * g_line_h; @@ -691,6 +713,10 @@ static void tab_init(TerminalSession *s, int tty_id, int bsh_pid) { s->ansi_param_count = 0; s->saved_row = 0; s->saved_col = 0; + s->history_count = 0; + s->history_index = 0; + s->input_len = 0; + s->current_input[0] = 0; session_reset_colors(s); scrollback_init(s); session_clear(s); @@ -778,27 +804,77 @@ static int create_tab(void) { return g_tab_count - 1; } +// checks if a command exist in /bin +static bool command_exists(const char *cmd) { + char path[256]; + + // test /bin/cmd + path[0] = 0; + str_append(path, "/bin/", sizeof(path)); + str_append(path, cmd, sizeof(path)); + + if (sys_exists(path)) return true; + + // test /bin/cmd.elf + path[0] = 0; + str_append(path, "/bin/", sizeof(path)); + str_append(path, cmd, sizeof(path)); + str_append(path, ".elf", sizeof(path)); + + if (sys_exists(path)) return true; + + return false; +} + +static void update_input_color(TerminalSession *s) { + if (s->input_len == 0) { + s->input_color = 0xFFFFFFFF; + return; + } + + char cmd[64]; + int i = 0; + + while (i < s->input_len && + s->current_input[i] != ' ' && + i < 63) { + cmd[i] = s->current_input[i]; + i++; + } + cmd[i] = 0; + + if (command_exists(cmd)) { + s->input_color = 0xFF55FF55; // green + } else { + s->input_color = 0xFFFF5555; // red + } +} + static void handle_key(gui_event_t *ev) { TerminalSession *s = &g_tabs[g_active_tab]; char c = (char)ev->arg1; bool ctrl = ev->arg3 != 0; + // create new tab with ctrl + t if (ctrl && c == 't') { int idx = create_tab(); if (idx >= 0) g_active_tab = idx; return; } - if (ctrl && c == 20) { + // switch to tab right, with ctrl + arrow right + if (ctrl && c == KEY_RIGHT) { if (g_tab_count > 0) g_active_tab = (g_active_tab + 1) % g_tab_count; return; } - if (ctrl && c == 19) { + // switch to tab left, with ctrl + arrow left + if (ctrl && c == KEY_LEFT) { if (g_tab_count > 0) g_active_tab = (g_active_tab + g_tab_count - 1) % g_tab_count; return; } + // kill the processus with ctrl + c if (ctrl && (c == 'c' || c == 'C')) { int fg = sys_tty_get_fg(s->tty_id); if (fg > 0) { @@ -811,6 +887,92 @@ static void handle_key(gui_event_t *ev) { return; } + // enter = save command + if (c == KEY_ENTER) { + if (s->input_len > 0) { + strcpy(s->history[s->history_count % HISTORY_MAX], s->current_input); + s->history_count++; + } + + s->input_color = 0xFFFFFFFF; + s->history_index = s->history_count; + s->input_len = 0; + s->current_input[0] = 0; + } + + // Storing command logic + // Backspace + else if (c == KEY_BACKSPACE) { + if (s->input_len > 0) { + s->input_len--; + s->current_input[s->input_len] = 0; + } + update_input_color(s); + } + + // Normal char + else if (c >= 32 && c < 127) { + if (s->input_len < HISTORY_LINE_MAX - 1) { + s->current_input[s->input_len++] = c; + s->current_input[s->input_len] = 0; + } + update_input_color(s); + } + + // Restoring command logic + if (c == KEY_UP) { + if (s->history_count > 0 && s->history_index > 0) { + s->history_index--; + + char *cmd = s->history[s->history_index % HISTORY_MAX]; + + // remove actual line + for (int i = 0; i < s->input_len; i++) { + char bs = 8; + sys_tty_write_in(s->tty_id, &bs, 1); + } + + strcpy(s->current_input, cmd); + s->input_len = strlen(cmd); + update_input_color(s); + + sys_tty_write_in(s->tty_id, cmd, s->input_len); + } + return; + } + + if (c == KEY_DOWN) { + if (s->history_index < s->history_count - 1) { + s->history_index++; + + char *cmd = s->history[s->history_index % HISTORY_MAX]; + + for (int i = 0; i < s->input_len; i++) { + char bs = 8; + sys_tty_write_in(s->tty_id, &bs, 1); + } + + strcpy(s->current_input, cmd); + s->input_len = strlen(cmd); + update_input_color(s); + + sys_tty_write_in(s->tty_id, cmd, s->input_len); + } + else { + // we want an empty line if we go back and nothing in history + for (int i = 0; i < s->input_len; i++) { + char bs = 8; + sys_tty_write_in(s->tty_id, &bs, 1); + } + + s->history_index = s->history_count; + s->input_len = 0; + s->current_input[0] = 0; + s->input_color = 0xFFFFFFFF; + } + return; + } + sys_tty_write_in(s->tty_id, &c, 1); } @@ -885,8 +1047,7 @@ int main(void) { draw_tabs(); draw_session(&g_tabs[g_active_tab]); } else { - // Avoid a tight poll loop when idle; sleep yields to the scheduler. - sleep(1); + sys_yield(); } }