From 89559d5466502176995720a33316714012a638d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 16 Apr 2020 18:51:14 +0200 Subject: [PATCH 1/9] grid: move 'cursor' state from terminal to grid This way, the 'normal' and 'alt' grids have their own cursor state, and we don't need to switch between them. --- csi.c | 128 ++++++++++++++++++++++++++++------------------------- render.c | 22 ++++----- sixel.c | 6 +-- terminal.c | 87 ++++++++++++++++++------------------ terminal.h | 6 +-- vt.c | 16 +++---- 6 files changed, 136 insertions(+), 129 deletions(-) diff --git a/csi.c b/csi.c index 335ac037..40526518 100644 --- a/csi.c +++ b/csi.c @@ -382,7 +382,7 @@ csi_dispatch(struct terminal *term, uint8_t final) /* VPA - vertical line position absolute */ int rel_row = vt_param_get(term, 0, 1) - 1; int row = term_row_rel_to_abs(term, rel_row); - term_cursor_to(term, row, term->cursor.point.col); + term_cursor_to(term, row, term->grid->cursor.point.col); break; } @@ -411,13 +411,13 @@ csi_dispatch(struct terminal *term, uint8_t final) case 'E': /* CNL - Cursor Next Line */ term_cursor_down(term, vt_param_get(term, 0, 1)); - term_cursor_left(term, term->cursor.point.col); + term_cursor_left(term, term->grid->cursor.point.col); break; case 'F': /* CPL - Cursor Previous Line */ term_cursor_up(term, vt_param_get(term, 0, 1)); - term_cursor_left(term, term->cursor.point.col); + term_cursor_left(term, term->grid->cursor.point.col); break; case 'g': { @@ -426,9 +426,9 @@ csi_dispatch(struct terminal *term, uint8_t final) case 0: /* Clear tab stop at *current* column */ tll_foreach(term->tab_stops, it) { - if (it->item == term->cursor.point.col) + if (it->item == term->grid->cursor.point.col) tll_remove(term->tab_stops, it); - else if (it->item > term->cursor.point.col) + else if (it->item > term->grid->cursor.point.col) break; } @@ -450,7 +450,7 @@ csi_dispatch(struct terminal *term, uint8_t final) case 'G': { /* Cursor horizontal absolute */ int col = min(vt_param_get(term, 0, 1), term->cols) - 1; - term_cursor_to(term, term->cursor.point.row, col); + term_cursor_to(term, term->grid->cursor.point.row, col); break; } @@ -473,15 +473,15 @@ csi_dispatch(struct terminal *term, uint8_t final) /* From cursor to end of screen */ term_erase( term, - &term->cursor.point, + &term->grid->cursor.point, &(struct coord){term->cols - 1, term->rows - 1}); - term->cursor.lcf = false; + term->grid->cursor.lcf = false; break; case 1: /* From start of screen to cursor */ - term_erase(term, &(struct coord){0, 0}, &term->cursor.point); - term->cursor.lcf = false; + term_erase(term, &(struct coord){0, 0}, &term->grid->cursor.point); + term->grid->cursor.lcf = false; break; case 2: @@ -490,7 +490,7 @@ csi_dispatch(struct terminal *term, uint8_t final) term, &(struct coord){0, 0}, &(struct coord){term->cols - 1, term->rows - 1}); - term->cursor.lcf = false; + term->grid->cursor.lcf = false; break; case 3: { @@ -531,25 +531,25 @@ csi_dispatch(struct terminal *term, uint8_t final) /* From cursor to end of line */ term_erase( term, - &term->cursor.point, - &(struct coord){term->cols - 1, term->cursor.point.row}); - term->cursor.lcf = false; + &term->grid->cursor.point, + &(struct coord){term->cols - 1, term->grid->cursor.point.row}); + term->grid->cursor.lcf = false; break; case 1: /* From start of line to cursor */ term_erase( - term, &(struct coord){0, term->cursor.point.row}, &term->cursor.point); - term->cursor.lcf = false; + term, &(struct coord){0, term->grid->cursor.point.row}, &term->grid->cursor.point); + term->grid->cursor.lcf = false; break; case 2: /* Entire line */ term_erase( term, - &(struct coord){0, term->cursor.point.row}, - &(struct coord){term->cols - 1, term->cursor.point.row}); - term->cursor.lcf = false; + &(struct coord){0, term->grid->cursor.point.row}, + &(struct coord){term->cols - 1, term->grid->cursor.point.row}); + term->grid->cursor.lcf = false; break; default: @@ -561,36 +561,36 @@ csi_dispatch(struct terminal *term, uint8_t final) } case 'L': { - if (term->cursor.point.row < term->scroll_region.start || - term->cursor.point.row >= term->scroll_region.end) + if (term->grid->cursor.point.row < term->scroll_region.start || + term->grid->cursor.point.row >= term->scroll_region.end) break; int count = min( vt_param_get(term, 0, 1), - term->scroll_region.end - term->cursor.point.row); + term->scroll_region.end - term->grid->cursor.point.row); term_scroll_reverse_partial( term, (struct scroll_region){ - .start = term->cursor.point.row, + .start = term->grid->cursor.point.row, .end = term->scroll_region.end}, count); break; } case 'M': { - if (term->cursor.point.row < term->scroll_region.start || - term->cursor.point.row >= term->scroll_region.end) + if (term->grid->cursor.point.row < term->scroll_region.start || + term->grid->cursor.point.row >= term->scroll_region.end) break; int count = min( vt_param_get(term, 0, 1), - term->scroll_region.end - term->cursor.point.row); + term->scroll_region.end - term->grid->cursor.point.row); term_scroll_partial( term, (struct scroll_region){ - .start = term->cursor.point.row, + .start = term->grid->cursor.point.row, .end = term->scroll_region.end}, count); break; @@ -601,26 +601,26 @@ csi_dispatch(struct terminal *term, uint8_t final) /* Number of characters to delete */ int count = min( - vt_param_get(term, 0, 1), term->cols - term->cursor.point.col); + vt_param_get(term, 0, 1), term->cols - term->grid->cursor.point.col); /* Number of characters left after deletion (on current line) */ - int remaining = term->cols - (term->cursor.point.col + count); + int remaining = term->cols - (term->grid->cursor.point.col + count); /* 'Delete' characters by moving the remaining ones */ - memmove(&term->grid->cur_row->cells[term->cursor.point.col], - &term->grid->cur_row->cells[term->cursor.point.col + count], + memmove(&term->grid->cur_row->cells[term->grid->cursor.point.col], + &term->grid->cur_row->cells[term->grid->cursor.point.col + count], remaining * sizeof(term->grid->cur_row->cells[0])); for (size_t c = 0; c < remaining; c++) - term->grid->cur_row->cells[term->cursor.point.col + c].attrs.clean = 0; + term->grid->cur_row->cells[term->grid->cursor.point.col + c].attrs.clean = 0; term->grid->cur_row->dirty = true; /* Erase the remainder of the line */ term_erase( term, - &(struct coord){term->cursor.point.col + remaining, term->cursor.point.row}, - &(struct coord){term->cols - 1, term->cursor.point.row}); - term->cursor.lcf = false; + &(struct coord){term->grid->cursor.point.col + remaining, term->grid->cursor.point.row}, + &(struct coord){term->cols - 1, term->grid->cursor.point.row}); + term->grid->cursor.lcf = false; break; } @@ -629,25 +629,25 @@ csi_dispatch(struct terminal *term, uint8_t final) /* Number of characters to insert */ int count = min( - vt_param_get(term, 0, 1), term->cols - term->cursor.point.col); + vt_param_get(term, 0, 1), term->cols - term->grid->cursor.point.col); /* Characters to move */ - int remaining = term->cols - (term->cursor.point.col + count); + int remaining = term->cols - (term->grid->cursor.point.col + count); /* Push existing characters */ - memmove(&term->grid->cur_row->cells[term->cursor.point.col + count], - &term->grid->cur_row->cells[term->cursor.point.col], + memmove(&term->grid->cur_row->cells[term->grid->cursor.point.col + count], + &term->grid->cur_row->cells[term->grid->cursor.point.col], remaining * sizeof(term->grid->cur_row->cells[0])); for (size_t c = 0; c < remaining; c++) - term->grid->cur_row->cells[term->cursor.point.col + count + c].attrs.clean = 0; + term->grid->cur_row->cells[term->grid->cursor.point.col + count + c].attrs.clean = 0; term->grid->cur_row->dirty = true; /* Erase (insert space characters) */ term_erase( term, - &term->cursor.point, - &(struct coord){term->cursor.point.col + count - 1, term->cursor.point.row}); - term->cursor.lcf = false; + &term->grid->cursor.point, + &(struct coord){term->grid->cursor.point.col + count - 1, term->grid->cursor.point.row}); + term->grid->cursor.lcf = false; break; } @@ -662,13 +662,13 @@ csi_dispatch(struct terminal *term, uint8_t final) case 'X': { /* Erase chars */ int count = min( - vt_param_get(term, 0, 1), term->cols - term->cursor.point.col); + vt_param_get(term, 0, 1), term->cols - term->grid->cursor.point.col); term_erase( term, - &term->cursor.point, - &(struct coord){term->cursor.point.col + count - 1, term->cursor.point.row}); - term->cursor.lcf = false; + &term->grid->cursor.point, + &(struct coord){term->grid->cursor.point.col + count - 1, term->grid->cursor.point.row}); + term->grid->cursor.lcf = false; break; } @@ -677,13 +677,13 @@ csi_dispatch(struct terminal *term, uint8_t final) for (int i = 0; i < vt_param_get(term, 0, 1); i++) { int new_col = term->cols - 1; tll_foreach(term->tab_stops, it) { - if (it->item > term->cursor.point.col) { + if (it->item > term->grid->cursor.point.col) { new_col = it->item; break; } } - assert(new_col >= term->cursor.point.col); - term_cursor_right(term, new_col - term->cursor.point.col); + assert(new_col >= term->grid->cursor.point.col); + term_cursor_right(term, new_col - term->grid->cursor.point.col); } break; } @@ -693,13 +693,13 @@ csi_dispatch(struct terminal *term, uint8_t final) for (int i = 0; i < vt_param_get(term, 0, 1); i++) { int new_col = 0; tll_rforeach(term->tab_stops, it) { - if (it->item < term->cursor.point.col) { + if (it->item < term->grid->cursor.point.col) { new_col = it->item; break; } } - assert(term->cursor.point.col >= new_col); - term_cursor_left(term, term->cursor.point.col - new_col); + assert(term->grid->cursor.point.col >= new_col); + term_cursor_left(term, term->grid->cursor.point.col - new_col); } break; @@ -757,11 +757,11 @@ csi_dispatch(struct terminal *term, uint8_t final) } case 's': - term->saved_cursor = term->cursor; + term->grid->saved_cursor = term->grid->cursor; break; case 'u': - term_restore_cursor(term, &term->saved_cursor); + term_restore_cursor(term, &term->grid->saved_cursor); break; case 't': { @@ -861,15 +861,15 @@ csi_dispatch(struct terminal *term, uint8_t final) /* u7 - cursor position query */ int row = term->origin == ORIGIN_ABSOLUTE - ? term->cursor.point.row - : term->cursor.point.row - term->scroll_region.start; + ? term->grid->cursor.point.row + : term->grid->cursor.point.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", - row + 1, term->cursor.point.col + 1); + row + 1, term->grid->cursor.point.col + 1); term_to_slave(term, reply, strlen(reply)); break; } @@ -1014,9 +1014,11 @@ csi_dispatch(struct terminal *term, uint8_t final) selection_cancel(term); term->grid = &term->alt; - term->alt_saved_cursor = term->cursor; - term_cursor_to(term, term->cursor.point.row, term->cursor.point.col); + term_cursor_to( + term, + min(term->grid->cursor.point.row, term->rows - 1), + min(term->grid->cursor.point.col, term->cols - 1)); tll_free(term->alt.damage); tll_free(term->alt.scroll_damage); @@ -1137,7 +1139,11 @@ csi_dispatch(struct terminal *term, uint8_t final) selection_cancel(term); term->grid = &term->normal; - term_restore_cursor(term, &term->alt_saved_cursor); + + term_cursor_to( + term, + min(term->grid->cursor.point.row, term->rows - 1), + min(term->grid->cursor.point.col, term->cols - 1)); tll_free(term->alt.damage); tll_free(term->alt.scroll_damage); diff --git a/render.c b/render.c index df67d85b..f0decd93 100644 --- a/render.c +++ b/render.c @@ -1373,7 +1373,7 @@ grid_render(struct terminal *term) */ bool cursor_is_visible = false; int view_end = (term->grid->view + term->rows - 1) & (term->grid->num_rows - 1); - int cursor_row = (term->grid->offset + term->cursor.point.row) & (term->grid->num_rows - 1); + int cursor_row = (term->grid->offset + term->grid->cursor.point.row) & (term->grid->num_rows - 1); if (view_end >= term->grid->view) { /* Not wrapped */ if (cursor_row >= term->grid->view && cursor_row <= view_end) @@ -1401,21 +1401,21 @@ grid_render(struct terminal *term) int view_aligned_row = (cursor_row - term->grid->view + term->grid->num_rows) & (term->grid->num_rows - 1); - term->render.last_cursor.actual = term->cursor.point; + term->render.last_cursor.actual = term->grid->cursor.point; term->render.last_cursor.in_view = (struct coord) { - term->cursor.point.col, view_aligned_row}; + term->grid->cursor.point.col, view_aligned_row}; struct row *row = grid_row_in_view(term->grid, view_aligned_row); - struct cell *cell = &row->cells[term->cursor.point.col]; + struct cell *cell = &row->cells[term->grid->cursor.point.col]; cell->attrs.clean = 0; term->render.last_cursor.cell = cell; int cols_updated = render_cell( - term, buf->pix, cell, term->cursor.point.col, view_aligned_row, true); + term, buf->pix, cell, term->grid->cursor.point.col, view_aligned_row, true); wl_surface_damage_buffer( term->window->surface, - term->margins.left + term->cursor.point.col * term->cell_width, + term->margins.left + term->grid->cursor.point.col * term->cell_width, term->margins.top + view_aligned_row * term->cell_height, cols_updated * term->cell_width, term->cell_height); } @@ -1804,7 +1804,7 @@ maybe_resize(struct terminal *term, int width, int height, bool force) term_cursor_to( term, cursor_row, - min(term->cursor.point.col, term->cols - 1)); + min(term->grid->cursor.point.col, term->cols - 1)); /* If in alt screen, update the saved 'normal' cursor too */ if (term->grid == &term->alt) { @@ -1813,10 +1813,10 @@ maybe_resize(struct terminal *term, int width, int height, bool force) while (cursor_row < 0) cursor_row += term->grid->num_rows; - term->alt_saved_cursor.lcf = false; - term->alt_saved_cursor.point.row = cursor_row; - term->alt_saved_cursor.point.col = min( - term->alt_saved_cursor.point.col, term->cols - 1); + term->normal.cursor.lcf = false; + term->normal.cursor.point.row = cursor_row; + term->normal.cursor.point.col = min( + term->normal.cursor.point.col, term->cols - 1); } term->render.last_cursor.cell = NULL; diff --git a/sixel.c b/sixel.c index 98a82deb..f335fdff 100644 --- a/sixel.c +++ b/sixel.c @@ -125,7 +125,7 @@ sixel_delete_in_range(struct terminal *term, int _start, int _end) void sixel_delete_at_cursor(struct terminal *term) { - sixel_delete_at_row(term, term->cursor.point.row); + sixel_delete_at_row(term, term->grid->cursor.point.row); } void @@ -142,8 +142,8 @@ sixel_unhook(struct terminal *term) .height = term->sixel.image.height, .rows = (term->sixel.image.height + term->cell_height - 1) / term->cell_height, .pos = (struct coord){ - term->cursor.point.col, - (term->grid->offset + term->cursor.point.row) & (term->grid->num_rows - 1)}, + term->grid->cursor.point.col, + (term->grid->offset + term->grid->cursor.point.row) & (term->grid->num_rows - 1)}, }; LOG_DBG("generating %dx%d pixman image", image.width, image.height); diff --git a/terminal.c b/terminal.c index b2017afc..b5156ca3 100644 --- a/terminal.c +++ b/terminal.c @@ -354,7 +354,7 @@ term_arm_blink_timer(struct terminal *term) static void cursor_refresh(struct terminal *term) { - term->grid->cur_row->cells[term->cursor.point.col].attrs.clean = 0; + term->grid->cur_row->cells[term->grid->cursor.point.col].attrs.clean = 0; term->grid->cur_row->dirty = true; render_refresh(term); } @@ -1163,7 +1163,6 @@ term_reset(struct terminal *term, bool hard) if (term->grid == &term->alt) { term->grid = &term->normal; - term_restore_cursor(term, &term->alt_saved_cursor); selection_cancel(term); } @@ -1188,10 +1187,12 @@ term_reset(struct terminal *term, bool hard) for (size_t i = 0; i < 256; i++) term->colors.table[i] = term->colors.default_table[i]; term->origin = ORIGIN_ABSOLUTE; - term->cursor.lcf = false; - term->cursor = (struct cursor){.point = {0, 0}}; - term->saved_cursor = (struct cursor){.point = {0, 0}}; - term->alt_saved_cursor = (struct cursor){.point = {0, 0}}; + term->normal.cursor.lcf = false; + term->alt.cursor.lcf = false; + term->normal.cursor = (struct cursor){.point = {0, 0}}; + term->normal.saved_cursor = (struct cursor){.point = {0, 0}}; + term->alt.cursor = (struct cursor){.point = {0, 0}}; + term->alt.saved_cursor = (struct cursor){.point = {0, 0}}; term->cursor_style = term->default_cursor_style; term_cursor_blink_disable(term); term->cursor_color.text = term->default_cursor_color.text; @@ -1431,10 +1432,10 @@ term_cursor_to(struct terminal *term, int row, int col) assert(row < term->rows); assert(col < term->cols); - term->cursor.lcf = false; + term->grid->cursor.lcf = false; - term->cursor.point.col = col; - term->cursor.point.row = row; + term->grid->cursor.point.col = col; + term->grid->cursor.point.row = row; term->grid->cur_row = grid_row(term->grid, row); } @@ -1448,39 +1449,39 @@ term_cursor_home(struct terminal *term) void term_cursor_left(struct terminal *term, int count) { - int move_amount = min(term->cursor.point.col, count); - term->cursor.point.col -= move_amount; - assert(term->cursor.point.col >= 0); - term->cursor.lcf = false; + int move_amount = min(term->grid->cursor.point.col, count); + term->grid->cursor.point.col -= move_amount; + assert(term->grid->cursor.point.col >= 0); + term->grid->cursor.lcf = false; } void term_cursor_right(struct terminal *term, int count) { - int move_amount = min(term->cols - term->cursor.point.col - 1, count); - term->cursor.point.col += move_amount; - assert(term->cursor.point.col < term->cols); - term->cursor.lcf = false; + int move_amount = min(term->cols - term->grid->cursor.point.col - 1, count); + term->grid->cursor.point.col += move_amount; + assert(term->grid->cursor.point.col < term->cols); + term->grid->cursor.lcf = false; } void term_cursor_up(struct terminal *term, int count) { int top = term->origin == ORIGIN_ABSOLUTE ? 0 : term->scroll_region.start; - assert(term->cursor.point.row >= top); + assert(term->grid->cursor.point.row >= top); - int move_amount = min(term->cursor.point.row - top, count); - term_cursor_to(term, term->cursor.point.row - move_amount, term->cursor.point.col); + int move_amount = min(term->grid->cursor.point.row - top, count); + term_cursor_to(term, term->grid->cursor.point.row - move_amount, term->grid->cursor.point.col); } void term_cursor_down(struct terminal *term, int count) { int bottom = term->origin == ORIGIN_ABSOLUTE ? term->rows : term->scroll_region.end; - assert(bottom >= term->cursor.point.row); + assert(bottom >= term->grid->cursor.point.row); - int move_amount = min(bottom - term->cursor.point.row - 1, count); - term_cursor_to(term, term->cursor.point.row + move_amount, term->cursor.point.col); + int move_amount = min(bottom - term->grid->cursor.point.row - 1, count); + term_cursor_to(term, term->grid->cursor.point.row + move_amount, term->grid->cursor.point.col); } static bool @@ -1569,7 +1570,7 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows sixel_delete_in_range(term, max(region.end - rows, region.start), region.end - 1); term_damage_scroll(term, DAMAGE_SCROLL, region, rows); - term->grid->cur_row = grid_row(term->grid, term->cursor.point.row); + term->grid->cur_row = grid_row(term->grid, term->grid->cursor.point.row); } void @@ -1622,7 +1623,7 @@ term_scroll_reverse_partial(struct terminal *term, sixel_delete_in_range(term, region.start, min(region.start + rows, region.end) - 1); term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows); - term->grid->cur_row = grid_row(term->grid, term->cursor.point.row); + term->grid->cur_row = grid_row(term->grid, term->grid->cursor.point.row); } void @@ -1634,14 +1635,14 @@ term_scroll_reverse(struct terminal *term, int rows) void term_formfeed(struct terminal *term) { - term_cursor_left(term, term->cursor.point.col); + term_cursor_left(term, term->grid->cursor.point.col); } void term_linefeed(struct terminal *term) { term->grid->cur_row->linebreak = true; - if (term->cursor.point.row == term->scroll_region.end - 1) + if (term->grid->cursor.point.row == term->scroll_region.end - 1) term_scroll(term, 1); else term_cursor_down(term, 1); @@ -1650,7 +1651,7 @@ term_linefeed(struct terminal *term) void term_reverse_index(struct terminal *term) { - if (term->cursor.point.row == term->scroll_region.start) + if (term->grid->cursor.point.row == term->scroll_region.start) term_scroll_reverse(term, 1); else term_cursor_up(term, 1); @@ -1672,7 +1673,7 @@ term_restore_cursor(struct terminal *term, const struct cursor *cursor) int row = min(cursor->point.row, term->rows - 1); int col = min(cursor->point.col, term->cols - 1); term_cursor_to(term, row, col); - term->cursor.lcf = cursor->lcf; + term->grid->cursor.lcf = cursor->lcf; } void @@ -2095,7 +2096,7 @@ term_disable_app_sync_updates(struct terminal *term) static inline void print_linewrap(struct terminal *term) { - if (likely(!term->cursor.lcf)) { + if (likely(!term->grid->cursor.lcf)) { /* Not and end of line */ return; } @@ -2105,11 +2106,11 @@ print_linewrap(struct terminal *term) return; } - if (term->cursor.point.row == term->scroll_region.end - 1) { + if (term->grid->cursor.point.row == term->scroll_region.end - 1) { term_scroll(term, 1); - term_cursor_to(term, term->cursor.point.row, 0); + term_cursor_to(term, term->grid->cursor.point.row, 0); } else - term_cursor_to(term, min(term->cursor.point.row + 1, term->rows - 1), 0); + term_cursor_to(term, min(term->grid->cursor.point.row + 1, term->rows - 1), 0); } static inline void @@ -2119,15 +2120,15 @@ print_insert(struct terminal *term, int width) if (unlikely(term->insert_mode)) { struct row *row = term->grid->cur_row; - const size_t move_count = max(0, term->cols - term->cursor.point.col - width); + const size_t move_count = max(0, term->cols - term->grid->cursor.point.col - width); memmove( - &row->cells[term->cursor.point.col + width], - &row->cells[term->cursor.point.col], + &row->cells[term->grid->cursor.point.col + width], + &row->cells[term->grid->cursor.point.col], move_count * sizeof(struct cell)); /* Mark moved cells as dirty */ - for (size_t i = term->cursor.point.col + width; i < term->cols; i++) + for (size_t i = term->grid->cursor.point.col + width; i < term->cols; i++) row->cells[i].attrs.clean = 0; } } @@ -2145,7 +2146,7 @@ term_print(struct terminal *term, wchar_t wc, int width) /* *Must* get current cell *after* linewrap+insert */ struct row *row = term->grid->cur_row; - struct cell *cell = &row->cells[term->cursor.point.col]; + struct cell *cell = &row->cells[term->grid->cursor.point.col]; cell->wc = term->vt.last_printed = wc; cell->attrs = term->vt.attrs; @@ -2154,20 +2155,20 @@ term_print(struct terminal *term, wchar_t wc, int width) cell->attrs.clean = 0; /* Advance cursor the 'additional' columns while dirty:ing the cells */ - for (int i = 1; i < width && term->cursor.point.col < term->cols - 1; i++) { + for (int i = 1; i < width && term->grid->cursor.point.col < term->cols - 1; i++) { term_cursor_right(term, 1); - assert(term->cursor.point.col < term->cols); - struct cell *cell = &row->cells[term->cursor.point.col]; + assert(term->grid->cursor.point.col < term->cols); + struct cell *cell = &row->cells[term->grid->cursor.point.col]; cell->wc = 0; cell->attrs.clean = 0; } /* Advance cursor */ - if (term->cursor.point.col < term->cols - 1) + if (term->grid->cursor.point.col < term->cols - 1) term_cursor_right(term, 1); else - term->cursor.lcf = true; + term->grid->cursor.lcf = true; } enum term_surface diff --git a/terminal.h b/terminal.h index 40088b04..7b7b0182 100644 --- a/terminal.h +++ b/terminal.h @@ -101,6 +101,9 @@ struct grid { int offset; int view; + struct cursor cursor; + struct cursor saved_cursor; + struct row **rows; struct row *cur_row; @@ -278,9 +281,6 @@ struct terminal { } colors; enum cursor_origin origin; - struct cursor cursor; - struct cursor saved_cursor; - struct cursor alt_saved_cursor; enum cursor_style default_cursor_style; enum cursor_style cursor_style; struct { diff --git a/vt.c b/vt.c index 409f9645..ab36ac6b 100644 --- a/vt.c +++ b/vt.c @@ -146,13 +146,13 @@ action_execute(struct terminal *term, uint8_t c) /* HT - horizontal tab */ int new_col = term->cols - 1; tll_foreach(term->tab_stops, it) { - if (it->item > term->cursor.point.col) { + if (it->item > term->grid->cursor.point.col) { new_col = it->item; break; } } - assert(new_col >= term->cursor.point.col); - term_cursor_right(term, new_col - term->cursor.point.col); + assert(new_col >= term->grid->cursor.point.col); + term_cursor_right(term, new_col - term->grid->cursor.point.col); break; } @@ -341,13 +341,13 @@ action_esc_dispatch(struct terminal *term, uint8_t final) case 0: switch (final) { case '7': - term->saved_cursor = term->cursor; + term->grid->saved_cursor = term->grid->cursor; term->vt.saved_attrs = term->vt.attrs; term->saved_charsets = term->charsets; break; case '8': - term_restore_cursor(term, &term->saved_cursor); + term_restore_cursor(term, &term->grid->saved_cursor); term->vt.attrs = term->vt.saved_attrs; term->charsets = term->saved_charsets; break; @@ -367,13 +367,13 @@ action_esc_dispatch(struct terminal *term, uint8_t final) case 'H': tll_foreach(term->tab_stops, it) { - if (it->item >= term->cursor.point.col) { - tll_insert_before(term->tab_stops, it, term->cursor.point.col); + if (it->item >= term->grid->cursor.point.col) { + tll_insert_before(term->tab_stops, it, term->grid->cursor.point.col); break; } } - tll_push_back(term->tab_stops, term->cursor.point.col); + tll_push_back(term->tab_stops, term->grid->cursor.point.col); break; case 'M': From 5546b40369b7bc20201a8f3a327be0ff84af7f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 16 Apr 2020 19:38:30 +0200 Subject: [PATCH 2/9] grid: grid_reflow() now translates cursor coordinates --- grid.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++------- grid.h | 2 +- render.c | 36 ++--------------------------------- 3 files changed, 54 insertions(+), 42 deletions(-) diff --git a/grid.c b/grid.c index 056dd791..b8659b55 100644 --- a/grid.c +++ b/grid.c @@ -53,7 +53,7 @@ grid_row_free(struct row *row) free(row); } -int +void grid_reflow(struct grid *grid, int new_rows, int new_cols, int old_screen_rows, int new_screen_rows) { @@ -79,13 +79,26 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, tll(struct sixel) new_sixels = tll_init(); + /* Turn cursor coordinates into grid absolute coordinates */ + struct coord cursor = grid->cursor.point; + struct coord new_cursor = {}; + cursor.row += grid->offset; + cursor.row &= old_rows - 1; + + struct coord saved_cursor = grid->saved_cursor.point; + struct coord new_saved_cursor = {}; + saved_cursor.row += grid->offset; + saved_cursor.row &= old_rows - 1; + /* * Walk the old grid */ for (int r = 0; r < old_rows; r++) { + const size_t old_row_idx = (offset + r) & (old_rows - 1); + /* Unallocated (empty) rows we can simply skip */ - const struct row *old_row = old_grid[(offset + r) & (old_rows - 1)]; + const struct row *old_row = old_grid[old_row_idx]; if (old_row == NULL) continue; @@ -102,7 +115,7 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, * the "real" sixel list. */ tll_foreach(grid->sixel_images, it) { - if (it->item.pos.row == ((offset + r) & (old_rows - 1))) { + if (it->item.pos.row == old_row_idx) { struct sixel six = it->item; six.pos.row = new_row_idx; @@ -122,7 +135,13 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, /* Walk current line of the old grid */ for (int c = 0; c < old_cols; c++) { - if (old_row->cells[c].wc == 0) { + bool has_cursor = cursor.row == old_row_idx && cursor.col == c; + bool has_saved_cursor + = saved_cursor.row == old_row_idx && saved_cursor.col == c; + + if (old_row->cells[c].wc == 0 && !has_cursor && !has_saved_cursor) { + assert(!has_cursor); + assert(!has_saved_cursor); empty_count++; continue; } @@ -168,6 +187,12 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, new_row->cells[new_col_idx] = *old_cell; new_row->cells[new_col_idx].attrs.clean = 1; + + if (has_cursor) + new_cursor = (struct coord){new_col_idx, new_row_idx}; + if (has_saved_cursor) + new_saved_cursor = (struct coord){new_col_idx, new_row_idx}; + new_col_idx++; } @@ -211,11 +236,32 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, grid_row_free(old_grid[r]); free(grid->rows); - grid->cur_row = new_grid[new_row_idx]; + grid->cur_row = new_grid[new_cursor.row]; grid->rows = new_grid; grid->num_rows = new_rows; grid->num_cols = new_cols; + /* Convert absolute coordinates to screen relative */ + new_cursor.row -= grid->offset; + while (new_cursor.row < 0) + new_cursor.row += grid->num_rows; + + assert(new_cursor.row >= 0); + assert(new_cursor.row < grid->num_rows); + + new_saved_cursor.row -= grid->offset; + while (new_saved_cursor.row < 0) + new_saved_cursor.row += grid->num_rows; + + assert(new_saved_cursor.row >= 0); + assert(new_saved_cursor.row < grid->num_rows); + + grid->cursor.point = new_cursor; + grid->saved_cursor.point = new_saved_cursor; + + grid->cursor.lcf = false; + grid->saved_cursor.lcf = false; + /* Destroy any non-moved sixels */ tll_foreach(grid->sixel_images, it) sixel_destroy(&it->item); @@ -225,6 +271,4 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, tll_foreach(new_sixels, it) tll_push_back(grid->sixel_images, it->item); tll_free(new_sixels); - - return new_row_idx; } diff --git a/grid.h b/grid.h index 50e2c2b7..d4045189 100644 --- a/grid.h +++ b/grid.h @@ -6,7 +6,7 @@ void grid_swap_row(struct grid *grid, int row_a, int row_b, bool initialize); struct row *grid_row_alloc(int cols, bool initialize); void grid_row_free(struct row *row); -int grid_reflow( +void grid_reflow( struct grid *grid, int new_rows, int new_cols, int old_screen_rows, int new_screen_rows); diff --git a/render.c b/render.c index f0decd93..ef0f0608 100644 --- a/render.c +++ b/render.c @@ -1754,10 +1754,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force) } /* Reflow grids */ - int last_normal_row = grid_reflow( - &term->normal, new_normal_grid_rows, new_cols, old_rows, new_rows); - int last_alt_row = grid_reflow( - &term->alt, new_alt_grid_rows, new_cols, old_rows, new_rows); + grid_reflow(&term->normal, new_normal_grid_rows, new_cols, old_rows, new_rows); + grid_reflow(&term->alt, new_alt_grid_rows, new_cols, old_rows, new_rows); /* Reset tab stops */ tll_free(term->tab_stops); @@ -1789,36 +1787,6 @@ maybe_resize(struct terminal *term, int width, int height, bool force) if (term->scroll_region.end >= old_rows) term->scroll_region.end = term->rows; - /* Position cursor at the last copied row */ - /* TODO: can we do better? */ - int cursor_row = term->grid == &term->normal - ? last_normal_row - term->normal.offset - : last_alt_row - term->alt.offset; - - while (cursor_row < 0) - cursor_row += term->grid->num_rows; - - assert(cursor_row >= 0); - assert(cursor_row < term->rows); - - term_cursor_to( - term, - cursor_row, - min(term->grid->cursor.point.col, term->cols - 1)); - - /* If in alt screen, update the saved 'normal' cursor too */ - if (term->grid == &term->alt) { - int cursor_row = last_normal_row - term->normal.offset; - - while (cursor_row < 0) - cursor_row += term->grid->num_rows; - - term->normal.cursor.lcf = false; - term->normal.cursor.point.row = cursor_row; - term->normal.cursor.point.col = min( - term->normal.cursor.point.col, term->cols - 1); - } - term->render.last_cursor.cell = NULL; damage_view: From e37aa3b369b67456f490102c455b6c16367f8e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 17 Apr 2020 20:33:08 +0200 Subject: [PATCH 3/9] grid: reflow: don't randomly insert hard linebreaks Not sure why I added this code; maybe to workaround issues caused by the fact that the cursor position wasn't properly translated. --- grid.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/grid.c b/grid.c index b8659b55..9276eb04 100644 --- a/grid.c +++ b/grid.c @@ -157,6 +157,7 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, /* Out of columns on current row in new grid? */ if (new_col_idx >= new_cols) { +#if 0 /* * If last cell on last row and first cell on new * row are non-empty, wrap the line, otherwise @@ -167,6 +168,7 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, { new_row->linebreak = true; } +#endif new_col_idx = 0; new_row_idx = (new_row_idx + 1) & (new_rows - 1); From aede474a52460fda2773e703b886172f9db74412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 17 Apr 2020 20:46:08 +0200 Subject: [PATCH 4/9] grid: reflow: turn line-wrapping code into a macro --- grid.c | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/grid.c b/grid.c index 9276eb04..eb7f0c25 100644 --- a/grid.c +++ b/grid.c @@ -124,6 +124,21 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, } } +#define line_wrap() \ + do { \ + new_col_idx = 0; \ + new_row_idx = (new_row_idx + 1) & (new_rows - 1); \ + \ + new_row = new_grid[new_row_idx]; \ + if (new_row == NULL) { \ + new_row = grid_row_alloc(new_cols, true); \ + new_grid[new_row_idx] = new_row; \ + } else { \ + memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0])); \ + new_row->linebreak = false; \ + } \ + } while(0) + /* * Keep track of empty cells. If the old line ends with a * string of empty cells, we don't need to, nor do we want to, @@ -169,18 +184,7 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, new_row->linebreak = true; } #endif - - new_col_idx = 0; - new_row_idx = (new_row_idx + 1) & (new_rows - 1); - - new_row = new_grid[new_row_idx]; - if (new_row == NULL) { - new_row = grid_row_alloc(new_cols, true); - new_grid[new_row_idx] = new_row; - } else { - memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0])); - new_row->linebreak = false; - } + line_wrap(); } assert(new_row != NULL); @@ -203,19 +207,10 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, if (old_row->linebreak) { new_row->linebreak = true; - - new_col_idx = 0; - new_row_idx = (new_row_idx + 1) & (new_rows - 1); - - new_row = new_grid[new_row_idx]; - if (new_row == NULL) { - new_row = grid_row_alloc(new_cols, true); - new_grid[new_row_idx] = new_row; - } else { - memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0])); - new_row->linebreak = false; - } + line_wrap(); } + +#undef line_wrap } /* Set offset such that the last reflowed row is at the bottom */ From 91a71b4147102e031aeb9952dfab920928998198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 17 Apr 2020 20:48:22 +0200 Subject: [PATCH 5/9] grid: reflow: remove commented out code --- grid.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/grid.c b/grid.c index eb7f0c25..0c6f9659 100644 --- a/grid.c +++ b/grid.c @@ -61,8 +61,6 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, const int old_rows = grid->num_rows; const int old_cols = grid->num_cols; - //assert(old_rows != new_rows || old_cols != new_cols); - int new_col_idx = 0; int new_row_idx = 0; From 87fc0cfb8571df3401ac8a1d30685be7276d14bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 17 Apr 2020 20:49:09 +0200 Subject: [PATCH 6/9] changelog: cursor coordinates are now translated on resize --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59fa0535..03e6137f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ * Alt+Return to emit "ESC \r". * Trackpad sloooow scrolling to eventually scroll a line. * Memory leak in terminal reset. +* Translation of cursor coordinates on resize ### Security From e5521ff79af196cc44d61604bc52c69b997be091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 17 Apr 2020 21:00:37 +0200 Subject: [PATCH 7/9] grid: reflow: generalize cursor coordinate translation Define a list of "tracking points" - coordinates that should be translated while reflowing. Add the cursor coordinates to this list. When a coordinate have been translated, it is removed from the list. This means we don't have to create a copy of the 'cursor' coordinate struct. --- grid.c | 67 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/grid.c b/grid.c index 0c6f9659..3e34c891 100644 --- a/grid.c +++ b/grid.c @@ -79,15 +79,17 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, /* Turn cursor coordinates into grid absolute coordinates */ struct coord cursor = grid->cursor.point; - struct coord new_cursor = {}; cursor.row += grid->offset; cursor.row &= old_rows - 1; struct coord saved_cursor = grid->saved_cursor.point; - struct coord new_saved_cursor = {}; saved_cursor.row += grid->offset; saved_cursor.row &= old_rows - 1; + tll(struct coord *) tracking_points = tll_init(); + tll_push_back(tracking_points, &cursor); + tll_push_back(tracking_points, &saved_cursor); + /* * Walk the old grid */ @@ -148,17 +150,23 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, /* Walk current line of the old grid */ for (int c = 0; c < old_cols; c++) { - bool has_cursor = cursor.row == old_row_idx && cursor.col == c; - bool has_saved_cursor - = saved_cursor.row == old_row_idx && saved_cursor.col == c; - if (old_row->cells[c].wc == 0 && !has_cursor && !has_saved_cursor) { - assert(!has_cursor); - assert(!has_saved_cursor); + /* Check if this cell is one of the tracked cells */ + bool is_tracking_point = false; + tll_foreach(tracking_points, it) { + if (it->item->row == old_row_idx && it->item->col == c) { + is_tracking_point = true; + break; + } + } + + if (old_row->cells[c].wc == 0 && !is_tracking_point) { empty_count++; continue; } + /* Allow left-adjusted and right-adjusted text, with empty + * cells in between, to be "pushed together" */ int old_cols_left = old_cols - c; int cols_needed = empty_count + old_cols_left; int new_cols_left = new_cols - new_col_idx; @@ -192,11 +200,16 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, new_row->cells[new_col_idx] = *old_cell; new_row->cells[new_col_idx].attrs.clean = 1; - if (has_cursor) - new_cursor = (struct coord){new_col_idx, new_row_idx}; - if (has_saved_cursor) - new_saved_cursor = (struct coord){new_col_idx, new_row_idx}; - + /* Translate tracking point(s) */ + if (is_tracking_point && i >= empty_count) { + tll_foreach(tracking_points, it) { + if (it->item->row == old_row_idx && it->item->col == c) { + it->item->row = new_row_idx; + it->item->col = new_col_idx; + tll_remove(tracking_points, it); + } + } + } new_col_idx++; } @@ -231,28 +244,28 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, grid_row_free(old_grid[r]); free(grid->rows); - grid->cur_row = new_grid[new_cursor.row]; + grid->cur_row = new_grid[cursor.row]; grid->rows = new_grid; grid->num_rows = new_rows; grid->num_cols = new_cols; /* Convert absolute coordinates to screen relative */ - new_cursor.row -= grid->offset; - while (new_cursor.row < 0) - new_cursor.row += grid->num_rows; + cursor.row -= grid->offset; + while (cursor.row < 0) + cursor.row += grid->num_rows; - assert(new_cursor.row >= 0); - assert(new_cursor.row < grid->num_rows); + assert(cursor.row >= 0); + assert(cursor.row < grid->num_rows); - new_saved_cursor.row -= grid->offset; - while (new_saved_cursor.row < 0) - new_saved_cursor.row += grid->num_rows; + saved_cursor.row -= grid->offset; + while (saved_cursor.row < 0) + saved_cursor.row += grid->num_rows; - assert(new_saved_cursor.row >= 0); - assert(new_saved_cursor.row < grid->num_rows); + assert(saved_cursor.row >= 0); + assert(saved_cursor.row < grid->num_rows); - grid->cursor.point = new_cursor; - grid->saved_cursor.point = new_saved_cursor; + grid->cursor.point = cursor; + grid->saved_cursor.point = saved_cursor; grid->cursor.lcf = false; grid->saved_cursor.lcf = false; @@ -266,4 +279,6 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, tll_foreach(new_sixels, it) tll_push_back(grid->sixel_images, it->item); tll_free(new_sixels); + + tll_free(tracking_points); } From ef52ed8a109af7512bd9e9ed62d74e36ae2deb41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 17 Apr 2020 21:04:32 +0200 Subject: [PATCH 8/9] grid: reflow: caller may now pass a list of coordinates that should be translated --- grid.c | 7 ++++++- grid.h | 4 +++- render.c | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/grid.c b/grid.c index 3e34c891..b50a095d 100644 --- a/grid.c +++ b/grid.c @@ -55,7 +55,9 @@ grid_row_free(struct row *row) void grid_reflow(struct grid *grid, int new_rows, int new_cols, - int old_screen_rows, int new_screen_rows) + int old_screen_rows, int new_screen_rows, + size_t tracking_points_count, + struct coord *_tracking_points[static tracking_points_count]) { struct row *const *old_grid = grid->rows; const int old_rows = grid->num_rows; @@ -90,6 +92,9 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, tll_push_back(tracking_points, &cursor); tll_push_back(tracking_points, &saved_cursor); + for (size_t i = 0; i < tracking_points_count; i++) + tll_push_back(tracking_points, _tracking_points[i]); + /* * Walk the old grid */ diff --git a/grid.h b/grid.h index d4045189..a2ff4b99 100644 --- a/grid.h +++ b/grid.h @@ -8,7 +8,9 @@ struct row *grid_row_alloc(int cols, bool initialize); void grid_row_free(struct row *row); void grid_reflow( struct grid *grid, int new_rows, int new_cols, - int old_screen_rows, int new_screen_rows); + int old_screen_rows, int new_screen_rows, + size_t tracking_points_count, + struct coord *tracking_points[static tracking_points_count]); static inline int grid_row_absolute(const struct grid *grid, int row_no) diff --git a/render.c b/render.c index ef0f0608..ca0342f2 100644 --- a/render.c +++ b/render.c @@ -1754,8 +1754,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force) } /* Reflow grids */ - grid_reflow(&term->normal, new_normal_grid_rows, new_cols, old_rows, new_rows); - grid_reflow(&term->alt, new_alt_grid_rows, new_cols, old_rows, new_rows); + grid_reflow(&term->normal, new_normal_grid_rows, new_cols, old_rows, new_rows, 0, NULL); + grid_reflow(&term->alt, new_alt_grid_rows, new_cols, old_rows, new_rows, 0, NULL); /* Reset tab stops */ tll_free(term->tab_stops); From 5509fe514afa64c972758ace3b81b462aba9694f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 17 Apr 2020 21:11:30 +0200 Subject: [PATCH 9/9] render: resize: no need to clear the selection - just truncate if necessary --- render.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/render.c b/render.c index ca0342f2..7b5391b6 100644 --- a/render.c +++ b/render.c @@ -1711,8 +1711,6 @@ maybe_resize(struct terminal *term, int width, int height, bool force) if (!force && width == term->width && height == term->height && scale == term->scale) return false; - selection_cancel(term); - /* Cancel an application initiated "Synchronized Update" */ term_disable_app_sync_updates(term); @@ -1814,6 +1812,12 @@ damage_view: term->height / term->scale + title_height); } + /* Make sure selection is within bounds */ + term->selection.start.row = min(term->selection.start.row, term->rows - 1); + term->selection.start.col = min(term->selection.start.col, term->cols - 1); + term->selection.end.row = min(term->selection.end.row, term->rows - 1); + term->selection.end.col = min(term->selection.end.col, term->cols - 1); + tll_free(term->normal.scroll_damage); tll_free(term->alt.scroll_damage);