diff --git a/src/tsm/libtsm-int.h b/src/tsm/libtsm-int.h index dbc7924..7ae9bf4 100644 --- a/src/tsm/libtsm-int.h +++ b/src/tsm/libtsm-int.h @@ -152,6 +152,8 @@ struct tsm_screen { }; void screen_cell_init(struct tsm_screen *con, struct cell *cell); +void screen_fill(struct tsm_screen *con, tsm_symbol_t ch, + const struct tsm_screen_attr *attr); void tsm_screen_set_opts(struct tsm_screen *scr, unsigned int opts); void tsm_screen_reset_opts(struct tsm_screen *scr, unsigned int opts); diff --git a/src/tsm/tsm-screen.c b/src/tsm/tsm-screen.c index 2004d9f..6521c11 100644 --- a/src/tsm/tsm-screen.c +++ b/src/tsm/tsm-screen.c @@ -1604,3 +1604,32 @@ void tsm_screen_erase_screen(struct tsm_screen *con, bool protect) screen_erase_region(con, 0, 0, con->size_x - 1, con->size_y - 1, protect); } + +void screen_fill(struct tsm_screen *con, tsm_symbol_t ch, + const struct tsm_screen_attr *attr) +{ + unsigned int len, x, y; + struct line *line; + struct cell cell; + + if (!con) + return; + + len = tsm_symbol_get_width(con->sym_table, ch); + if (len != 1) + return; + + screen_inc_age(con); + + cell.ch = ch; + cell.width = len; + memcpy(&cell.attr, attr, sizeof(cell.attr)); + cell.age = con->age_cnt; + + for (y = 0; y < con->size_y; ++y) { + line = con->lines[y]; + for (x = 0; x < con->size_x; ++x) { + memcpy(&line->cells[x], &cell, sizeof(line->cells[x])); + } + } +} diff --git a/src/tsm/tsm-vte.c b/src/tsm/tsm-vte.c index 1cfe402..fcc7ee4 100644 --- a/src/tsm/tsm-vte.c +++ b/src/tsm/tsm-vte.c @@ -110,6 +110,7 @@ enum parser_action { #define CSI_PLUS 0x0100 /* CSI: + */ #define CSI_POPEN 0x0200 /* CSI: ( */ #define CSI_PCLOSE 0x0400 /* CSI: ) */ +#define CSI_HASH 0x0800 /* CSI: # */ /* max CSI arguments */ #define CSI_ARG_MAX 16 @@ -918,6 +919,9 @@ static void do_collect(struct tsm_vte *vte, uint32_t data) case ')': vte->csi_flags |= CSI_PCLOSE; break; + case '#': + vte->csi_flags |= CSI_HASH; + break; } } @@ -1053,6 +1057,18 @@ static void do_esc(struct tsm_vte *vte, uint32_t data) return; } break; + case '8': + if (vte->csi_flags & CSI_HASH) { + /* DECALN */ + /* DEC Screen Alignment Test */ + vte->flags &= ~FLAG_ORIGIN_MODE; + tsm_screen_reset_flags(vte->con, TSM_SCREEN_REL_ORIGIN); + screen_fill(vte->con, 'E', &vte->def_attr); + tsm_screen_move_to(vte->con, 0, 0); + tsm_screen_set_margins(vte->con, 1, vte->con->size_y); + return; + } + break; } /* everything below is only valid without CSI flags */ diff --git a/test/test_common.h b/test/test_common.h index ed30c1f..f018274 100644 --- a/test/test_common.h +++ b/test/test_common.h @@ -90,7 +90,7 @@ static inline int test_run_suite(Suite *s) SRunner *sr; sr = srunner_create(s); - srunner_run_all(sr, CK_NORMAL); + srunner_run_all(sr, CK_ENV); ret = srunner_ntests_failed(sr); srunner_free(sr); diff --git a/test/test_vte.c b/test/test_vte.c index 20bf370..c68ae6f 100644 --- a/test/test_vte.c +++ b/test/test_vte.c @@ -212,10 +212,91 @@ TEST_DEFINE_CASE(misc) TEST(test_vte_backspace_key) TEST_END_CASE +START_TEST(test_vte_DECALN) +{ + struct tsm_screen *screen; + struct tsm_vte *vte; + struct tsm_screen_attr attr; + const char *input; + unsigned int x, y, i; + tsm_age_t age; + int r; + + r = tsm_screen_new(&screen, log_cb, NULL); + ck_assert_int_eq(r, 0); + + tsm_screen_set_flags(screen, TSM_SCREEN_AUTO_WRAP); + + i = 0; + for (y = 0; y < screen->size_y; ++y) { + for (x = 0; x < screen->size_x; ++x, ++i) { + attr.fr = i * 1; + attr.fg = i * 2; + attr.fb = i * 3; + attr.br = i * 4; + attr.bg = i * 5; + attr.bb = i * 6; + attr.bold = !!(i & 0x01); + attr.italic = !!(i & 0x02); + attr.underline = !!(i & 0x04); + attr.inverse = !!(i & 0x08); + attr.protect = !!(i & 0x10); + attr.blink = !!(i & 0x20); + tsm_screen_write(screen, '!' + (i % ('~' - '!')), &attr); + } + } + + r = tsm_screen_set_margins(screen, 3, screen->size_y - 5); + ck_assert_int_eq(r, 0); + + r = tsm_vte_new(&vte, screen, write_cb, NULL, log_cb, NULL); + ck_assert_int_eq(r, 0); + + tsm_vte_get_def_attr(vte, &attr); + age = screen->age; + + input = "\x1b[?6h" /* DECSET(DECOM) */ "\x1b#8" /* DECALN */; + tsm_vte_input(vte, input, strlen(input)); + + i = 0; + for (y = 0; y < screen->size_y; ++y) { + for (x = 0; x < screen->size_x; ++x, ++i) { + ck_assert_uint_eq(screen->lines[y]->cells[x].ch, 'E'); + ck_assert_uint_eq(screen->lines[y]->cells[x].width, 1); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.fr, attr.fr); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.fg, attr.fg); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.fb, attr.fb); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.br, attr.br); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.bg, attr.bg); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.bb, attr.bb); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.bold, 0); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.italic, 0); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.underline, 0); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.inverse, 0); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.protect, 0); + ck_assert_uint_eq(screen->lines[y]->cells[x].attr.blink, 0); + ck_assert_uint_gt(screen->lines[y]->cells[x].age, age); + } + } + + ck_assert_uint_ne(tsm_screen_get_flags(screen) & TSM_SCREEN_REL_ORIGIN, TSM_SCREEN_REL_ORIGIN); + ck_assert_uint_eq(tsm_screen_get_cursor_x(screen), 0); + ck_assert_uint_eq(tsm_screen_get_cursor_y(screen), 0); + ck_assert_uint_eq(screen->margin_top, 0); + ck_assert_uint_eq(screen->margin_bottom, screen->size_y - 1); + ck_assert_uint_lt(screen->cursor_x, screen->size_x); +} +END_TEST + +TEST_DEFINE_CASE(control_sequences) + TEST(test_vte_DECALN) +TEST_END_CASE + // clang-format off TEST_DEFINE( TEST_SUITE(vte, TEST_CASE(misc), + TEST_CASE(control_sequences), TEST_END ) )