diff --git a/csi.c b/csi.c index af591325..8f407f0f 100644 --- a/csi.c +++ b/csi.c @@ -330,8 +330,9 @@ csi_dispatch(struct terminal *term, uint8_t final) case 'd': { /* VPA - vertical line position absolute */ - int row = min(vt_param_get(term, 0, 1), term->rows); - term_cursor_to(term, row - 1, term->cursor.col); + struct coord new_cursor = term_cursor_rel_to_abs( + term, vt_param_get(term, 0, 1) - 1, term->cursor.col); + term_cursor_to(term, new_cursor.row, new_cursor.col); break; } @@ -358,17 +359,20 @@ csi_dispatch(struct terminal *term, uint8_t final) case 'G': { /* Cursor horizontal absolute */ - int col = min(vt_param_get(term, 0, 1), term->cols); - term_cursor_to(term, term->cursor.row, col - 1); + struct coord new_cursor = term_cursor_rel_to_abs( + term, term->cursor.row, vt_param_get(term, 0, 1) - 1); + term_cursor_to(term, new_cursor.row, new_cursor.col); break; } case 'f': case 'H': { /* Move cursor */ - int row = min(vt_param_get(term, 0, 1), term->rows); - int col = min(vt_param_get(term, 1, 1), term->cols); - term_cursor_to(term, row - 1, col - 1); + struct coord new_cursor = term_cursor_rel_to_abs( + term, + vt_param_get(term, 0, 1) - 1, + vt_param_get(term, 1, 1) - 1); + term_cursor_to(term, new_cursor.row, new_cursor.col); break; } @@ -623,8 +627,7 @@ csi_dispatch(struct terminal *term, uint8_t final) /* 1-based */ term->scroll_region.start = start - 1; term->scroll_region.end = end; - - term_cursor_to(term, start - 1, 0); + term_cursor_home(term); LOG_DBG("scroll region: %d-%d", term->scroll_region.start, @@ -684,13 +687,17 @@ csi_dispatch(struct terminal *term, uint8_t final) switch (param) { case 6: { /* u7 - cursor position query */ + + int row = term->origin == ORIGIN_ABSOLUTE + ? term->cursor.row + : term->cursor.row - term->scroll_region.start; + /* TODO: we use 0-based position, while the xterm * terminfo says the receiver of the reply should * decrement, hence we must add 1 */ char reply[64]; snprintf(reply, sizeof(reply), "\x1b[%d;%dR", - term->cursor.row + 1, - term->cursor.col + 1); + row + 1, term->cursor.col + 1); term_to_slave(term, reply, strlen(reply)); break; } @@ -729,6 +736,7 @@ csi_dispatch(struct terminal *term, uint8_t final) term, &(struct coord){0, 0}, &(struct coord){term->cols - 1, term->rows - 1}); + term_cursor_home(term); break; case 5: @@ -736,6 +744,12 @@ csi_dispatch(struct terminal *term, uint8_t final) term_damage_all(term); break; + case 6: { /* DECOM */ + term->origin = ORIGIN_RELATIVE; + term_cursor_home(term); + break; + } + case 7: term->auto_margin = true; break; @@ -839,6 +853,7 @@ csi_dispatch(struct terminal *term, uint8_t final) term, &(struct coord){0, 0}, &(struct coord){term->cols - 1, term->rows - 1}); + term_cursor_home(term); break; case 4: @@ -853,8 +868,7 @@ csi_dispatch(struct terminal *term, uint8_t final) case 6: { /* DECOM */ term->origin = ORIGIN_ABSOLUTE; - struct coord new_home = term_cursor_rel_to_abs(term, 0, 0); - term_cursor_to(term, new_home.row, new_home.col); + term_cursor_home(term); break; } diff --git a/terminal.c b/terminal.c index b7523d1b..2be46130 100644 --- a/terminal.c +++ b/terminal.c @@ -486,6 +486,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, }, .alpha = conf->colors.alpha, }, + .origin = ORIGIN_ABSOLUTE, .default_cursor_style = conf->cursor.style, .cursor_style = conf->cursor.style, .default_cursor_color = { @@ -991,6 +992,30 @@ term_erase(struct terminal *term, const struct coord *start, const struct coord erase_cell_range(term, grid_row(term->grid, end->row), 0, end->col); } +struct coord +term_cursor_rel_to_abs(const struct terminal *term, int row, int col) +{ + switch (term->origin) { + case ORIGIN_ABSOLUTE: + return (struct coord) { + .col = min(col, term->cols - 1), + .row = min(row, term->rows - 1), + }; + break; + + case ORIGIN_RELATIVE: { + return (struct coord) { + .col = min(col, term->cols - 1), + .row = min(row + term->scroll_region.start, term->rows - 1), + }; + break; + } + } + + assert(false); + return (struct coord){-1, -1}; +} + void term_cursor_to(struct terminal *term, int row, int col) { @@ -1005,6 +1030,13 @@ term_cursor_to(struct terminal *term, int row, int col) term->grid->cur_row = grid_row(term->grid, row); } +void +term_cursor_home(struct terminal *term) +{ + struct coord new_cursor = term_cursor_rel_to_abs(term, 0, 0); + term_cursor_to(term, new_cursor.row, new_cursor.col); +} + void term_cursor_left(struct terminal *term, int count) { diff --git a/terminal.h b/terminal.h index 0ed83877..5339d367 100644 --- a/terminal.h +++ b/terminal.h @@ -122,7 +122,8 @@ struct vt { struct attributes saved_attrs; }; -enum cursor_keys { CURSOR_KEYS_DONTCARE, CURSOR_KEYS_NORMAL, CURSOR_KEYS_APPLICATION}; +enum cursor_origin { ORIGIN_ABSOLUTE, ORIGIN_RELATIVE }; +enum cursor_keys { CURSOR_KEYS_DONTCARE, CURSOR_KEYS_NORMAL, CURSOR_KEYS_APPLICATION }; enum keypad_keys { KEYPAD_DONTCARE, KEYPAD_NUMERICAL, KEYPAD_APPLICATION }; enum charset { CHARSET_ASCII, CHARSET_GRAPHIC }; @@ -214,6 +215,7 @@ struct terminal { uint32_t default_table[256]; } colors; + enum cursor_origin origin; struct coord cursor; struct coord saved_cursor; struct coord alt_saved_cursor; @@ -328,6 +330,8 @@ void term_damage_scroll( void term_erase( struct terminal *term, const struct coord *start, const struct coord *end); +struct coord term_cursor_rel_to_abs(const struct terminal *term, int row, int col); +void term_cursor_home(struct terminal *term); void term_cursor_to(struct terminal *term, int row, int col); void term_cursor_left(struct terminal *term, int count); void term_cursor_right(struct terminal *term, int count);