|
@@ -6,7 +6,18 @@
|
|
|
|
|
|
#define MAX_PARAMS 2
|
|
|
|
|
|
-void term_init(struct term *t, int num_rows, int num_cols)
|
|
|
+static char *colors[8] = {
|
|
|
+ "000000",
|
|
|
+ "ff0000",
|
|
|
+ "00ff00",
|
|
|
+ "ffff00",
|
|
|
+ "0000ff",
|
|
|
+ "ff00ff",
|
|
|
+ "00ffff",
|
|
|
+ "ffffff",
|
|
|
+};
|
|
|
+
|
|
|
+void term_init(struct term *t, int num_rows, int num_cols, int pango)
|
|
|
{
|
|
|
t->state = TERM_STATE_GROUND;
|
|
|
t->cursor.x = 0;
|
|
@@ -17,6 +28,9 @@ void term_init(struct term *t, int num_rows, int num_cols)
|
|
|
t->param_idx = 0;
|
|
|
t->params[0] = 0;
|
|
|
t->params[1] = 0;
|
|
|
+ t->pango = pango;
|
|
|
+ t->sgra.fg = 7;
|
|
|
+ t->sgra.bg = 0;
|
|
|
for (int i = 0; i < t->num_rows; i++) {
|
|
|
t->rows[i].cells = calloc(t->num_cols, sizeof(struct cell));
|
|
|
for (int j = 0; j < t->num_cols; j++) {
|
|
@@ -71,13 +85,14 @@ static void term_line_feed(struct term *t)
|
|
|
|
|
|
static void term_print(struct term *t, char c) {
|
|
|
struct row *cur_row = &t->rows[t->cursor.y];
|
|
|
+ struct cell *cur_cell = &cur_row->cells[t->cursor.x];
|
|
|
|
|
|
- cur_row->cells[t->cursor.x].c = c;
|
|
|
+ cur_cell->c = c;
|
|
|
+ cur_cell->sgra = t->sgra;
|
|
|
|
|
|
- if (t->cursor.x == t->num_cols - 1) {
|
|
|
+ if (t->cursor.x >= t->num_cols - 1) {
|
|
|
term_cursor_move_down(t, 1);
|
|
|
t->cursor.x = 0;
|
|
|
- cur_row->wrapped = true;
|
|
|
} else {
|
|
|
t->cursor.x++;
|
|
|
}
|
|
@@ -85,10 +100,13 @@ static void term_print(struct term *t, char c) {
|
|
|
|
|
|
static void term_clear(struct term *t) {
|
|
|
t->param_idx = 0;
|
|
|
- // TODO: also clear
|
|
|
- // private flag
|
|
|
- // intermediate characters
|
|
|
- // final character
|
|
|
+ t->params[0] = 0;
|
|
|
+ t->params[1] = 0;
|
|
|
+
|
|
|
+ // TODO: also clear:
|
|
|
+ // private flag?
|
|
|
+ // intermediate characters?
|
|
|
+ // final character?
|
|
|
}
|
|
|
|
|
|
static void term_add_param_digit(struct term *t, char c) {
|
|
@@ -123,9 +141,91 @@ static void term_collect(struct term *t, char c) {
|
|
|
|
|
|
}
|
|
|
|
|
|
+static void term_csi_erase_in_display(struct term *t) {
|
|
|
+ // inclusive
|
|
|
+ int start_x;
|
|
|
+ int start_y;
|
|
|
+ //exclusive
|
|
|
+ int end_x;
|
|
|
+ int end_y;
|
|
|
+
|
|
|
+ switch (t->params[0]) {
|
|
|
+ case 0:
|
|
|
+ start_x = t->cursor.x;
|
|
|
+ start_y = t->cursor.y;
|
|
|
+ end_x = t->num_rows;
|
|
|
+ end_y = t->num_cols;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1:
|
|
|
+ start_x = 0;
|
|
|
+ start_y = 0;
|
|
|
+ end_x = t->cursor.x + 1;
|
|
|
+ end_y = t->cursor.y + 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ // We don't have a scrollback buffer, so 2 and 3 are equivalent
|
|
|
+ case 2:
|
|
|
+ case 3:
|
|
|
+ start_x = 0;
|
|
|
+ start_y = 0;
|
|
|
+ end_x = t->num_rows;
|
|
|
+ end_y = t->num_cols;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = start_y; i < end_y; i++) {
|
|
|
+ for (int j = start_x; j < end_x; j++) {
|
|
|
+ // TODO: clear sgr
|
|
|
+ t->rows[i].cells[j].c = ' ';
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void term_csi_erase_in_line(struct term *t) {
|
|
|
+ int start_x; // inclusive
|
|
|
+ int end_x; // exclusive
|
|
|
+
|
|
|
+ switch (t->params[0]) {
|
|
|
+ case 0:
|
|
|
+ start_x = t->cursor.x;
|
|
|
+ end_x = t->num_cols;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1:
|
|
|
+ start_x = 0;
|
|
|
+ end_x = t->cursor.x + 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2:
|
|
|
+ start_x = 0;
|
|
|
+ end_x = t->num_cols;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int j = start_x; j < end_x; j++) {
|
|
|
+ // TODO: clear sgr
|
|
|
+ t->rows[t->cursor.y].cells[j].c = ' ';
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void term_csi_sgr(struct term *t) {
|
|
|
+ int p0 = t->params[0];
|
|
|
+
|
|
|
+ switch (p0) {
|
|
|
+ case 0:
|
|
|
+ t->sgra.fg = 7;
|
|
|
+ t->sgra.bg = 0;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 30 ... 37: t->sgra.fg = p0 - 30; break;
|
|
|
+ case 40 ... 47: t->sgra.bg = p0 - 40; break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void term_csi_dispatch(struct term *t, char c) {
|
|
|
int p0 = t->params[0];
|
|
|
- //int p1 = t->params[1];
|
|
|
+ int p1 = t->params[1];
|
|
|
|
|
|
switch (c) {
|
|
|
case 'A': term_cursor_move_up(t, p0); break;
|
|
@@ -141,6 +241,14 @@ static void term_csi_dispatch(struct term *t, char c) {
|
|
|
case 'F': t->cursor.x = 0; term_cursor_move_up(t, p0 == 0 ? 1 : p0); break;
|
|
|
|
|
|
case 'G': t->cursor.x = p0; break;
|
|
|
+
|
|
|
+ case 'H': t->cursor.y = p0 == 0 ? 0 : p0 - 1; t->cursor.x = p1 == 0 ? 0 : p1 - 1; break;
|
|
|
+
|
|
|
+ case 'J': term_csi_erase_in_display(t); break;
|
|
|
+
|
|
|
+ case 'K': term_csi_erase_in_line(t); break;
|
|
|
+
|
|
|
+ case 'm': term_csi_sgr(t); break;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -158,7 +266,7 @@ void term_putc(struct term *t, char c)
|
|
|
|
|
|
case 0x1b: t->state = TERM_STATE_ESC; break;
|
|
|
|
|
|
- case 0x20 ... 0x7f: term_print(t, c);
|
|
|
+ case 0x20 ... 0x7f: term_print(t, c); break;
|
|
|
} break;
|
|
|
|
|
|
case TERM_STATE_ESC:
|
|
@@ -177,12 +285,19 @@ void term_putc(struct term *t, char c)
|
|
|
} break;
|
|
|
|
|
|
case TERM_STATE_CSI_ENTRY:
|
|
|
+ // entry
|
|
|
+ term_clear(t);
|
|
|
+
|
|
|
// events
|
|
|
switch (c) {
|
|
|
case 0x00 ... 0x17:
|
|
|
case 0x19:
|
|
|
case 0x1c ... 0x1f: term_execute(t, c); 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 0x30 ... 0x39:
|
|
@@ -207,6 +322,8 @@ void term_putc(struct term *t, char c)
|
|
|
|
|
|
case 0x3a:
|
|
|
case 0x3c ... 0x3f: t->state = TERM_STATE_CSI_IGNORE; break;
|
|
|
+
|
|
|
+ case 0x40 ... 0x7e: term_csi_dispatch(t, c); t->state = TERM_STATE_GROUND; break;
|
|
|
} break;
|
|
|
|
|
|
case TERM_STATE_CSI_INTERMEDIATE:
|
|
@@ -216,7 +333,7 @@ void term_putc(struct term *t, char c)
|
|
|
|
|
|
case 0x30 ... 0x3f: t->state = TERM_STATE_CSI_IGNORE; break;
|
|
|
|
|
|
- case 0x40 ... 0x7e: term_csi_dispatch(t, c); t->state = TERM_STATE_GROUND;
|
|
|
+ case 0x40 ... 0x7e: term_csi_dispatch(t, c); t->state = TERM_STATE_GROUND; break;
|
|
|
} break;
|
|
|
|
|
|
case TERM_STATE_CSI_IGNORE:
|
|
@@ -241,22 +358,32 @@ void term_put_string(struct term *t, char *str) {
|
|
|
|
|
|
char *term_to_string(struct term *t)
|
|
|
{
|
|
|
- int str_size = t->num_rows * t->num_cols + t->num_rows;
|
|
|
- char *str = calloc(str_size, sizeof(char));
|
|
|
- int str_idx = 0;
|
|
|
+ // TODO: don't allocate too much if pango is not used.
|
|
|
+ int str_size = t->num_rows * t->num_cols * 64 + t->num_rows;
|
|
|
+ char *ret = calloc(str_size, sizeof(char));
|
|
|
+ char *s = ret;
|
|
|
|
|
|
for (int i = 0; i < t->num_rows; i++) {
|
|
|
- for (int j = 0; j < t->num_cols && str_idx < str_size; j++) {
|
|
|
- str[str_idx++] = t->rows[i].cells[j].c;
|
|
|
+ for (int j = 0; j < t->num_cols; j++) {
|
|
|
+ struct cell cur_cell = t->rows[i].cells[j];
|
|
|
+ if (t->pango) {
|
|
|
+ // TODO: use snprintf...
|
|
|
+ s += sprintf(s, "<span fgcolor='#%s' bgcolor='#%s'>%c</span>",
|
|
|
+ colors[cur_cell.sgra.fg],
|
|
|
+ colors[cur_cell.sgra.bg],
|
|
|
+ cur_cell.c);
|
|
|
+ } else {
|
|
|
+ *s++ = cur_cell.c;
|
|
|
+ }
|
|
|
}
|
|
|
if (i == t->num_rows - 1) {
|
|
|
- str[str_idx++] = '\0';
|
|
|
+ *s++ = '\0';
|
|
|
} else {
|
|
|
- str[str_idx++] = '\n';
|
|
|
+ *s++ = '\n';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return str;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
void term_free(struct term *t)
|