vtgl

terminal emulator implemented in OpenGL
git clone anongit@rnpnr.xyz:vtgl.git
Log | Files | Refs | Feed | LICENSE

Commit: 5396fbf72d4e7ed0384f542a8e4a34b61514b015
Parent: b9f18b0baef0e92d2f6cc1e96fbc2b7782559ca2
Author: Randy Palamar
Date:   Sat,  6 Jul 2024 15:29:58 -0600

handle escapes through a different path when splitting raw input

The raw input path shouldn't be able to draw to the fb (via
clear_fb_region or otherwise).

Diffstat:
Mterminal.c | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
1 file changed, 71 insertions(+), 25 deletions(-)

diff --git a/terminal.c b/terminal.c @@ -103,8 +103,9 @@ static void fb_scroll_down(Term *t, u32 top, u32 n) { // TODO: CLAMP? - fb_clear_region(t, t->size.h - 1 - (n - 1), t->size.h - 1, 0, t->size.w); - for (u32 i = t->size.h - 1; i >= top + n; i--) { + u32 bottom = t->size.h - 1; + fb_clear_region(t, bottom - n + 1, bottom, 0, t->size.w); + for (u32 i = bottom; i >= top + n; i--) { Row tmp = t->fb.rows[i]; t->fb.rows[i] = t->fb.rows[i - n]; t->fb.rows[i - n] = tmp; @@ -115,8 +116,9 @@ static void fb_scroll_up(Term *t, u32 top, u32 n) { // TODO: CLAMP? + u32 bottom = t->size.h - 1; fb_clear_region(t, top, top + n - 1, 0, t->size.w); - for (u32 i = top; i < t->size.h - n; i++) { + for (u32 i = top; i <= bottom - n; i++) { Row tmp = t->fb.rows[i]; t->fb.rows[i] = t->fb.rows[i + n]; t->fb.rows[i + n] = tmp; @@ -330,8 +332,9 @@ parse_csi(s8 *r) return csi; } } - /* TODO: error case: needs more chars! */ - ASSERT(0); + + /* NOTE: Needs more characters! */ + csi.argc = -1; return csi; } @@ -339,30 +342,25 @@ static void handle_csi(Term *t, s8 *raw) { CSI csi = parse_csi(raw); + ASSERT(csi.argc != -1); switch (csi.mode) { - case 'H': cursor_move_to(t, csi.argv[0], csi.argv[1]); break; - case 'J': erase_in_display(t, &csi); break; - case 'K': erase_in_line(t, &csi); break; - case 'h': set_mode(t, &csi, 1); break; - case 'l': set_mode(t, &csi, 0); break; - case 'm': set_colours(t, &csi); break; - case 't': window_manipulation(t, &csi); break; + case 'H': cursor_move_to(t, csi.argv[0] - 1, csi.argv[1] - 1); break; + case 'J': erase_in_display(t, &csi); break; + case 'K': erase_in_line(t, &csi); break; + case 'h': set_mode(t, &csi, 1); break; + case 'l': set_mode(t, &csi, 0); break; + case 'm': set_colours(t, &csi); break; + case 't': window_manipulation(t, &csi); break; default: fputs("unknown csi: ", stderr); dump_csi(&csi); } } -enum handle_escape_return { - HESC_NORMAL_RETURN, - HESC_NEEDS_MORE_BYTES, - HESC_CURSOR_MOVED, -}; -static enum handle_escape_return +static void handle_escape(Term *t, s8 *raw) { - enum handle_escape_return result = HESC_NORMAL_RETURN; u32 cp = get_ascii(raw); switch(cp) { case '[': handle_csi(t, raw); break; @@ -382,13 +380,61 @@ handle_escape(Term *t, s8 *raw) fb_scroll_down(t, 0, 1); } else { cursor_move_to(t, t->cursor.row - 1, t->cursor.col); - result = HESC_CURSOR_MOVED; } break; default: fprintf(stderr, "unknown escape sequence: ESC %c (0x%02x)\n", cp, cp); break; } +} + +enum escape_moves_cursor_result { + EMC_NORMAL_RETURN, + EMC_NEEDS_MORE_BYTES, + EMC_CURSOR_MOVED, +}; + +static enum escape_moves_cursor_result +check_if_csi_moves_cursor(Term *t, s8 *raw) +{ + enum escape_moves_cursor_result result = EMC_NORMAL_RETURN; + CSI csi = parse_csi(raw); + + if (csi.argc == -1) + return EMC_NEEDS_MORE_BYTES; + + switch (csi.mode) { + case 'H': result = EMC_CURSOR_MOVED; break; + case 'h': set_mode(t, &csi, 1); break; + case 'l': set_mode(t, &csi, 0); break; + default: break; + } + + return result; +} + +static enum escape_moves_cursor_result +check_if_escape_moves_cursor(Term *t, s8 *raw) +{ + enum escape_moves_cursor_result result = EMC_NORMAL_RETURN; + u32 cp = get_ascii(raw); + switch(cp) { + case '[': + result = check_if_csi_moves_cursor(t, raw); + break; + case '(': /* GZD4 -- set primary charset G0 */ + case ')': /* G1D4 -- set secondary charset G1 */ + case '*': /* G2D4 -- set tertiary charset G2 */ + case '+': /* G3D4 -- set quaternary charset G3 */ + case '%': /* utf-8 mode */ + get_ascii(raw); + break; + case 'M': /* RI -- Reverse Index */ + if (t->cursor.row != 0) + result = EMC_CURSOR_MOVED; + break; + default: break; + } return result; } @@ -434,11 +480,11 @@ split_raw_input_to_lines(Term *t, s8 raw) if (peek(raw, 0) == 0x1B) { s8 old = raw; raw = consume(raw, 1); - switch (handle_escape(t, &raw)) { - case HESC_NEEDS_MORE_BYTES: + switch (check_if_escape_moves_cursor(t, &raw)) { + case EMC_NEEDS_MORE_BYTES: t->unprocessed_bytes = old.len; return parsed_lines; - case HESC_CURSOR_MOVED: + case EMC_CURSOR_MOVED: parsed_lines++; feed_line(lb, old.data, t->cursor.state); break; @@ -478,7 +524,7 @@ static void push_newline(Term *t) { t->cursor.row++; - if (t->cursor.row >= t->size.h) { + if (t->cursor.row == t->size.h) { t->cursor.row = t->size.h - 1; fb_scroll_up(t, 0, 1); } @@ -488,7 +534,7 @@ static void push_tab(Term *t) { u32 col = t->cursor.col; - u32 advance = g_tabstop - col % g_tabstop; + u32 advance = g_tabstop - (col % g_tabstop); fb_clear_region(t, t->cursor.row, t->cursor.row, t->cursor.col, t->cursor.col + advance); cursor_step_column(t, advance); }