|
@@ -76,9 +76,12 @@ static void term_line_feed(struct term *t)
|
|
|
{
|
|
|
if (t->cursor.y == t->num_rows - 1) {
|
|
|
for (int i = 1; i < t->num_rows; i++) {
|
|
|
- memcpy(t->rows[i-1].cells, t->rows[i].cells, t->num_cols);
|
|
|
+ memcpy(t->rows[i-1].cells, t->rows[i].cells, t->num_cols * sizeof(struct cell));
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < t->num_cols; i++) {
|
|
|
+ t->rows[t->cursor.y].cells[i].c = ' ';
|
|
|
}
|
|
|
- memset(t->rows[t->cursor.y].cells, ' ', t->num_cols);
|
|
|
} else {
|
|
|
t->cursor.y++;
|
|
|
}
|
|
@@ -92,7 +95,7 @@ static void term_print(struct term *t, char c) {
|
|
|
cur_cell->sgra = t->sgra;
|
|
|
|
|
|
if (t->cursor.x >= t->num_cols - 1) {
|
|
|
- term_cursor_move_down(t, 1);
|
|
|
+ term_line_feed(t);
|
|
|
t->cursor.x = 0;
|
|
|
} else {
|
|
|
t->cursor.x++;
|
|
@@ -139,7 +142,6 @@ static void term_execute(struct term *t, char c) {
|
|
|
|
|
|
case '\r': t->cursor.x = 0; break;
|
|
|
|
|
|
-
|
|
|
case '\t':
|
|
|
term_print(t, ' ');
|
|
|
term_print(t, ' ');
|
|
@@ -234,7 +236,6 @@ static void term_csi_sgr(struct term *t) {
|
|
|
t->sgra.normal = 0;
|
|
|
switch (p) {
|
|
|
case 1: t->sgra.bold = 1; break;
|
|
|
-
|
|
|
case 30 ... 37: t->sgra.fg = p - 30; break;
|
|
|
case 40 ... 47: t->sgra.bg = p - 40; break;
|
|
|
}
|
|
@@ -247,13 +248,13 @@ static void term_csi_dispatch(struct term *t, char c) {
|
|
|
int p1 = t->params[1];
|
|
|
|
|
|
switch (c) {
|
|
|
- case 'A': term_cursor_move_up(t, p0); break;
|
|
|
+ case 'A': term_cursor_move_up(t, p0 == 0 ? 1 : p0); break;
|
|
|
|
|
|
- case 'B': term_cursor_move_down(t, p0); break;
|
|
|
+ case 'B': term_cursor_move_down(t, p0 == 0 ? 1 : p0); break;
|
|
|
|
|
|
- case 'C': term_cursor_move_right(t, p0); break;
|
|
|
+ case 'C': term_cursor_move_right(t, p0 == 0 ? 1 : p0); break;
|
|
|
|
|
|
- case 'D': term_cursor_move_left(t, p0); break;
|
|
|
+ case 'D': term_cursor_move_left(t, p0 == 0 ? 1 : p0); break;
|
|
|
|
|
|
case 'E': t->cursor.x = 0; term_cursor_move_down(t, p0 == 0 ? 1 : p0); break;
|
|
|
|
|
@@ -271,6 +272,14 @@ static void term_csi_dispatch(struct term *t, char c) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void term_esc_dispatch(struct term *t, char c) {
|
|
|
+ switch (c) {
|
|
|
+ case 'D': term_line_feed(t); break;
|
|
|
+
|
|
|
+ case 'E': t->cursor.x = 0; term_line_feed(t); break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void term_putc(struct term *t, char c)
|
|
|
{
|
|
|
// Loosely based on a very (very) limited subset of the state machine at https://vt100.net/emu/dec_ansi_parser
|
|
@@ -298,9 +307,29 @@ void term_putc(struct term *t, char c)
|
|
|
case 0x19:
|
|
|
case 0x1c ... 0x1f: term_execute(t, c); break;
|
|
|
|
|
|
+ case 0x20 ... 0x2f: term_collect(t, c); t->state = TERM_STATE_ESC_INTERMEDIATE; break;
|
|
|
+
|
|
|
+ case 0x30 ... 0x4f:
|
|
|
+ case 0x51 ... 0x57:
|
|
|
+ case 0x59:
|
|
|
+ case 0x5a:
|
|
|
+ case 0x5c:
|
|
|
+ case 0x60 ... 0x7e: term_esc_dispatch(t, c); t->state = TERM_STATE_GROUND; break;
|
|
|
+
|
|
|
case 0x5b: t->state = TERM_STATE_CSI_ENTRY; break;
|
|
|
+ } break;
|
|
|
+
|
|
|
+ case TERM_STATE_ESC_INTERMEDIATE:
|
|
|
+ switch (c) {
|
|
|
+ case 0x00 ... 0x17:
|
|
|
+ case 0x19:
|
|
|
+ case 0x1c ... 0x1f: term_execute(t, c); break;
|
|
|
|
|
|
- default: t->state = TERM_STATE_GROUND; break;
|
|
|
+ case 0x1b: t->state = TERM_STATE_ESC; break;
|
|
|
+
|
|
|
+ case 0x20 ... 0x2f: term_collect(t, c); break;
|
|
|
+
|
|
|
+ case 0x30 ... 0x7e: term_esc_dispatch(t, c); t->state = TERM_STATE_GROUND; break;
|
|
|
} break;
|
|
|
|
|
|
case TERM_STATE_CSI_ENTRY:
|
|
@@ -313,11 +342,13 @@ void term_putc(struct term *t, char c)
|
|
|
case 0x19:
|
|
|
case 0x1c ... 0x1f: term_execute(t, c); break;
|
|
|
|
|
|
+ case 0x1b: t->state = TERM_STATE_ESC; break;
|
|
|
+
|
|
|
case 0x20 ... 0x2f: term_collect(t, c); t->state = TERM_STATE_CSI_INTERMEDIATE; break;
|
|
|
|
|
|
case 0x3a: t->state = TERM_STATE_CSI_IGNORE; break;
|
|
|
|
|
|
- case 0x3c ... 0x3f: /* Ignore privates??? */ break;
|
|
|
+ case 0x3c ... 0x3f: term_collect(t, c); break;
|
|
|
|
|
|
case 0x30 ... 0x39:
|
|
|
case 0x3b:
|
|
@@ -333,6 +364,8 @@ void term_putc(struct term *t, char c)
|
|
|
case 0x19:
|
|
|
case 0x1c ... 0x1f: term_execute(t, c); break;
|
|
|
|
|
|
+ case 0x1b: t->state = TERM_STATE_ESC; break;
|
|
|
+
|
|
|
case 0x20 ... 0x2f: term_collect(t, c); t->state = TERM_STATE_CSI_INTERMEDIATE; break;
|
|
|
|
|
|
case 0x30 ... 0x39:
|
|
@@ -348,6 +381,12 @@ void term_putc(struct term *t, char c)
|
|
|
case TERM_STATE_CSI_INTERMEDIATE:
|
|
|
// events
|
|
|
switch (c) {
|
|
|
+ case 0x00 ... 0x17:
|
|
|
+ case 0x19:
|
|
|
+ case 0x1c ... 0x1f: term_execute(t, c); break;
|
|
|
+
|
|
|
+ case 0x1b: t->state = TERM_STATE_ESC; break;
|
|
|
+
|
|
|
case 0x20 ... 0x2f: term_collect(t, c); break;
|
|
|
|
|
|
case 0x30 ... 0x3f: t->state = TERM_STATE_CSI_IGNORE; break;
|
|
@@ -362,6 +401,8 @@ void term_putc(struct term *t, char c)
|
|
|
case 0x19:
|
|
|
case 0x1c ... 0x1f: term_execute(t, c); break;
|
|
|
|
|
|
+ case 0x1b: t->state = TERM_STATE_ESC; break;
|
|
|
+
|
|
|
case 0x40 ... 0x7e: t->state = TERM_STATE_GROUND; break;
|
|
|
} break;
|
|
|
|
|
@@ -397,6 +438,7 @@ static char *xml_entity(char *str, char c) {
|
|
|
|
|
|
char *term_to_string(struct term *t)
|
|
|
{
|
|
|
+ // TODO: Allocate once
|
|
|
// TODO: don't allocate too much if pango is not used.
|
|
|
int str_size = t->num_rows * t->num_cols * 128 + t->num_rows;
|
|
|
char *ret = calloc(str_size, sizeof(char));
|