diff --git a/src/userland/cli/bsh.c b/src/userland/cli/bsh.c index be06ff6..659e1da 100644 --- a/src/userland/cli/bsh.c +++ b/src/userland/cli/bsh.c @@ -866,11 +866,25 @@ static void prompt_write_with_right(const char *left_tmpl, const char *right_tmp } } -static void redraw_input(const char *prompt_tmpl, const char *line, int len) { +static void redraw_input(const char *prompt_tmpl, const char *line, int len, int cursor) { sys_write(1, "\r", 1); prompt_write_with_right(prompt_tmpl, g_cfg.prompt_right); sys_write(1, line, len); sys_write(1, "\x1b[K", 3); + + int diff = len - cursor; + if (diff > 0) { + int char_diff = text_strlen_utf8(line + cursor); + if (char_diff > 0) { + char num[16]; + char seq[32]; + itoa(char_diff, num); + str_copy(seq, "\x1b[", sizeof(seq)); + str_append(seq, num, sizeof(seq)); + str_append(seq, "D", sizeof(seq)); + sys_write(1, seq, (int)strlen(seq)); + } + } } static void show_matches(const char *prompt_tmpl, const char *line, int len, char matches[][MAX_MATCH_LEN], int count) { @@ -880,7 +894,7 @@ static void show_matches(const char *prompt_tmpl, const char *line, int len, cha sys_write(1, " ", 2); } sys_write(1, "\n", 1); - redraw_input(prompt_tmpl, line, len); + redraw_input(prompt_tmpl, line, len, len); } static int pid_exists(int pid) { @@ -1424,6 +1438,7 @@ static bool run_script(const char *path) { static int read_line(char *out, int max_len, const char *prompt_tmpl) { int len = 0; + int cursor = 0; int hist_index = g_history_count; bool search_mode = false; char saved_line[MAX_LINE]; @@ -1463,15 +1478,15 @@ static int read_line(char *out, int max_len, const char *prompt_tmpl) { } if (ch == '\b' || ch == 127) { - if (len > 0) { - // Find previous UTF-8 character boundary - const char *prev = text_prev_utf8(out, out + len); - len = (int)(prev - out); - out[len] = 0; - - // Send only ONE backspace sequence to the terminal - // because the terminal is now codepoint-based. - sys_write(1, "\b \b", 3); + if (cursor > 0) { + const char *prev = text_prev_utf8(out, out + cursor); + int shift = (int)(out + cursor - prev); + for (int i = cursor; i <= len; i++) { + out[i - shift] = out[i]; + } + cursor -= shift; + len -= shift; + redraw_input(prompt_tmpl, out, len, cursor); } search_mode = false; hist_index = g_history_count; @@ -1524,7 +1539,8 @@ static int read_line(char *out, int max_len, const char *prompt_tmpl) { out[token_start] = 0; str_append(out, matches[0], max_len); len = (int)strlen(out); - redraw_input(prompt_tmpl, out, len); + cursor = len; + redraw_input(prompt_tmpl, out, len, cursor); } else { int common_len = common_prefix_len(matches, match_count); if (common_len > token_len) { @@ -1535,9 +1551,11 @@ static int read_line(char *out, int max_len, const char *prompt_tmpl) { out[token_start] = 0; str_append(out, prefix_buf, max_len); len = (int)strlen(out); - redraw_input(prompt_tmpl, out, len); + cursor = len; + redraw_input(prompt_tmpl, out, len, cursor); } else { show_matches(prompt_tmpl, out, len, matches, match_count); + cursor = len; } } search_mode = false; @@ -1545,6 +1563,23 @@ static int read_line(char *out, int max_len, const char *prompt_tmpl) { continue; } + if (ch == 27) { + char seq[2]; + int g1 = 0, g2 = 0; + int retries = 0; + while (g1 <= 0 && retries < 10) { g1 = sys_tty_read_in(&seq[0], 1); if (g1 <= 0) { sleep(1); retries++; } } + retries = 0; + while (g2 <= 0 && retries < 10) { g2 = sys_tty_read_in(&seq[1], 1); if (g2 <= 0) { sleep(1); retries++; } } + + if (g1 > 0 && g2 > 0 && seq[0] == '[') { + if (seq[1] == 'A') ch = 17; + else if (seq[1] == 'B') ch = 18; + else if (seq[1] == 'C') ch = 19; + else if (seq[1] == 'D') ch = 20; + } + if (ch == 27) continue; + } + if (ch == 17) { // Up if (g_history_count == 0) continue; if (!search_mode) { @@ -1565,7 +1600,8 @@ static int read_line(char *out, int max_len, const char *prompt_tmpl) { hist_index = found; str_copy(out, g_history[hist_index], max_len); len = (int)strlen(out); - redraw_input(prompt_tmpl, out, len); + cursor = len; + redraw_input(prompt_tmpl, out, len, cursor); } continue; } @@ -1583,20 +1619,44 @@ static int read_line(char *out, int max_len, const char *prompt_tmpl) { hist_index = found; str_copy(out, g_history[hist_index], max_len); len = (int)strlen(out); + cursor = len; } else { search_mode = false; hist_index = g_history_count; str_copy(out, saved_line, max_len); len = (int)strlen(out); + cursor = len; + } + redraw_input(prompt_tmpl, out, len, cursor); + continue; + } + + if (ch == 20) { // Left + if (cursor > 0) { + const char *prev = text_prev_utf8(out, out + cursor); + if (prev) cursor = (int)(prev - out); + redraw_input(prompt_tmpl, out, len, cursor); + } + continue; + } + + if (ch == 19) { // Right + if (cursor < len) { + const char *next = text_next_utf8(out + cursor); + if (next && *next) cursor = (int)(next - out); + else cursor = len; + redraw_input(prompt_tmpl, out, len, cursor); } - redraw_input(prompt_tmpl, out, len); continue; } if (((unsigned char)ch >= 32 || (signed char)ch < 0) && len < max_len - 1) { - out[len++] = ch; - out[len] = 0; - sys_write(1, &ch, 1); + for (int i = len; i >= cursor; i--) { + out[i + 1] = out[i]; + } + out[cursor++] = ch; + len++; + redraw_input(prompt_tmpl, out, len, cursor); search_mode = false; hist_index = g_history_count; } diff --git a/src/userland/gui/terminal.c b/src/userland/gui/terminal.c index 0af8504..5d7757c 100644 --- a/src/userland/gui/terminal.c +++ b/src/userland/gui/terminal.c @@ -62,6 +62,8 @@ typedef struct { // for color char current_input[LINE_MAX]; int input_len; + int input_start_col; + int input_start_row; } TerminalSession; static ui_window_t g_win; @@ -774,9 +776,10 @@ static void draw_session(TerminalSession *s) { } } - int input_start = s->cursor_col - visible_len; - if (input_start < 0) input_start = 0; - if (input_start >= g_cols) input_start = g_cols - 1; + int input_start = -1; + if (s->input_len > 0 && row == s->input_start_row) { + input_start = s->input_start_col; + } char cmd[64]; int i = 0; @@ -800,7 +803,7 @@ static void draw_session(TerminalSession *s) { color = line[col].color; } - if (s->scroll_offset == 0 && row == s->cursor_row) { + if (s->scroll_offset == 0 && row == s->input_start_row && input_start >= 0) { if (col >= input_start && col < input_end) { color = s->input_color; } @@ -839,6 +842,8 @@ static void tab_init(TerminalSession *s, int tty_id, int bsh_pid) { s->saved_col = 0; s->input_len = 0; + s->input_start_col = 0; + s->input_start_row = 0; s->current_input[0] = 0; s->utf8_codepoint = 0; s->utf8_expected = 0; @@ -1095,6 +1100,7 @@ static void handle_key(gui_event_t *ev) { sys_tty_set_fg(s->tty_id, 0); return; } + s->input_len = 0; char ch = 3; sys_tty_write_in(s->tty_id, &ch, 1); return; @@ -1149,6 +1155,10 @@ static void handle_key(gui_event_t *ev) { char utf8[4]; int len = text_encode_utf8(codepoint, utf8); if (len > 0 && s->input_len + len < LINE_MAX - 1) { + if (s->input_len == 0) { + s->input_start_col = s->cursor_col; + s->input_start_row = s->cursor_row; + } for (int i = 0; i < len; i++) { s->current_input[s->input_len + i] = utf8[i]; }