diff --git a/csi.c b/csi.c index 80ee75cd..dc5a018a 100644 --- a/csi.c +++ b/csi.c @@ -917,26 +917,7 @@ csi_dispatch(struct terminal *term, uint8_t final) case 3: { /* Erase scrollback */ - int end = (term->grid->offset + term->rows - 1) % term->grid->num_rows; - for (size_t i = 0; i < term->grid->num_rows; i++) { - if (end >= term->grid->offset) { - /* Not wrapped */ - if (i >= term->grid->offset && i <= end) - continue; - } else { - /* Wrapped */ - if (i >= term->grid->offset || i <= end) - continue; - } - - if (term->render.last_cursor.row == term->grid->rows[i]) - term->render.last_cursor.row = NULL; - - grid_row_free(term->grid->rows[i]); - term->grid->rows[i] = NULL; - } - term->grid->view = term->grid->offset; - term_damage_view(term); + term_erase_scrollback(term); break; } diff --git a/selection.c b/selection.c index 57ab8bf6..537614f6 100644 --- a/selection.c +++ b/selection.c @@ -69,10 +69,8 @@ selection_on_rows(const struct terminal *term, int row_start, int row_end) end = tmp; } - if (row_start >= start->row && row_end <= end->row) { - LOG_INFO("ON ROWS"); + if (row_start >= start->row && row_end <= end->row) return true; - } return false; } diff --git a/terminal.c b/terminal.c index 72ab1f2b..df6ddbed 100644 --- a/terminal.c +++ b/terminal.c @@ -2011,6 +2011,69 @@ term_erase(struct terminal *term, const struct coord *start, const struct coord sixel_overwrite_by_row(term, end->row, 0, end->col + 1); } +void +term_erase_scrollback(struct terminal *term) +{ + const int mask = term->grid->num_rows - 1; + const int start = (term->grid->offset + term->rows) & mask; + const int end = (term->grid->offset - 1) & mask; + const int sel_start = term->selection.start.row; + const int sel_end = term->selection.end.row; + + if (sel_end >= 0) { + /* + * Cancel selection if it touches any of the rows in the + * scrollback, since we can’t have the selection reference + * soon-to-be deleted rows. + * + * This is done by range checking the selection range against + * the scrollback range. + * + * To make this comparison simpler, the start/end absolute row + * numbers are “rebased” against the scrollback start, where + * row 0 is the *first* row in the scrollback. A high number + * thus means the row is further *down* in the scrollback, + * closer to the screen bottom. + */ + int scrollback_start = term->grid->offset + term->rows; + + int rel_sel_start = sel_start - scrollback_start + term->grid->num_rows; + int rel_sel_end = sel_end - scrollback_start + term->grid->num_rows; + + int rel_start = start - scrollback_start + term->grid->num_rows; + int rel_end = end - scrollback_start + term->grid->num_rows; + + rel_sel_start &= mask; + rel_sel_end &= mask; + rel_start &= mask; + rel_end &= mask; + + if ((rel_sel_start <= rel_start && rel_sel_end >= rel_start) || + (rel_sel_start <= rel_end && rel_sel_end >= rel_end) || + (rel_sel_start >= rel_start && rel_sel_end <= rel_end)) + { + selection_cancel(term); + } + } + + for (int i = start;; i = (i + 1) & mask) { + struct row *row = term->grid->rows[i]; + if (row != NULL) { + if (term->render.last_cursor.row == row) + term->render.last_cursor.row = NULL; + + grid_row_free(row); + term->grid->rows[i] = NULL; + } + + if (i == end) + break; + } + + term->grid->view = term->grid->offset; + term_damage_view(term); +} + int term_row_rel_to_abs(const struct terminal *term, int row) { diff --git a/terminal.h b/terminal.h index b02036a2..d699d644 100644 --- a/terminal.h +++ b/terminal.h @@ -662,6 +662,7 @@ void term_damage_scroll( void term_erase( struct terminal *term, const struct coord *start, const struct coord *end); +void term_erase_scrollback(struct terminal *term); int term_row_rel_to_abs(const struct terminal *term, int row); void term_cursor_home(struct terminal *term);