diff --git a/terminal.c b/terminal.c index c1a12c04..a0596b8d 100644 --- a/terminal.c +++ b/terminal.c @@ -1600,6 +1600,24 @@ void term_reconfig(Terminal *term, Conf *conf) term_copy_stuff_from_conf(term); } +/* + * Ensure the position variables describing the ends of the terminal + * selection are in bounds with respect to the actual extent of the + * screen and scrollback. + */ +static void term_selection_bounds_check(Terminal *term) +{ + pos lo, hi; + lo.y = -count234(term->scrollback); + lo.x = 0; + hi.y = count234(term->screen); + hi.x = term->cols - 1; + + term->selstart = bound_pos(term->selstart, lo, hi); + term->selend = bound_pos(term->selend, lo, hi); + term->selanchor = bound_pos(term->selanchor, lo, hi); +} + /* * Clear the scrollback. */ @@ -1621,6 +1639,11 @@ void term_clrsb(Terminal *term) sfree(line); /* this is compressed data, not a termline */ } + /* + * Make sure we didn't invalidate selstart and selend in the process. + */ + term_selection_bounds_check(term); + /* * When clearing the scrollback, we also truncate any termlines on * the current screen which have remembered data from a previous diff --git a/terminal.h b/terminal.h index 1ed0b17d..8da3b9b4 100644 --- a/terminal.h +++ b/terminal.h @@ -475,4 +475,9 @@ static inline bool decpos_fn(pos *p, int cols) #define incpos(p) incpos_fn(&(p), GET_TERM_COLS) #define decpos(p) decpos_fn(&(p), GET_TERM_COLS) +static inline pos bound_pos(pos p, pos lo, pos hi) +{ + return poslt(p, lo) ? lo : poslt(p, hi) ? p : hi; +} + #endif