Preserve the mouse selection even when the contents of the screen are scrolled or overwritten provided the new text does not intersect the selected lines.

Requires a small CPU usage overhead when scrolling/drawing characters
even in the absence of a selection. I couldn't isolate the overhead from
statistical noise in my testing.
This commit is contained in:
Kovid Goyal 2018-07-25 16:16:57 +05:30
parent 57871e1983
commit d72098bdf8
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 44 additions and 3 deletions

View File

@ -6,6 +6,10 @@ Changelog
0.12.0 [future]
------------------------------
- Preserve the mouse selection even when the contents of the screen are
scrolled or overwritten provided the new text does not intersect the
selected lines.
- Linux: Implement support for Input Method Extensions (multilingual input
using standard keyboards) via `IBus
<https://github.com/ibus/ibus/wiki/ReadMe>`_ (:iss:`469`)

View File

@ -146,6 +146,7 @@ screen_reset(Screen *self) {
init_tabstops(self->alt_tabstops, self->columns);
cursor_reset(self->cursor);
self->is_dirty = true;
self->selection = EMPTY_SELECTION;
screen_cursor_position(self, 1, 1);
set_dynamic_color(self, 110, NULL);
set_dynamic_color(self, 111, NULL);
@ -332,6 +333,14 @@ move_widened_char(Screen *self, CPUCell* cpu_cell, GPUCell *gpu_cell, index_type
*dest_gpu = src_gpu;
}
static inline bool
selection_has_screen_line(Selection *s, int y) {
if (s->start_scrolled_by == s->end_scrolled_by && s->start_x == s->end_x && s->start_y == s->end_y) return false;
int top = (int)s->start_y - s->start_scrolled_by;
int bottom = (int)s->end_y - s->end_scrolled_by;
return top <= y && y <= bottom;
}
static inline void
draw_combining_char(Screen *self, char_type ch) {
bool has_prev_char = false;
@ -350,6 +359,7 @@ draw_combining_char(Screen *self, char_type ch) {
if (has_prev_char) {
line_add_combining_char(self->linebuf->line, ch, xpos);
self->is_dirty = true;
if (selection_has_screen_line(&self->selection, ypos)) self->selection = EMPTY_SELECTION;
linebuf_mark_line_dirty(self->linebuf, ypos);
if (ch == 0xfe0f) { // emoji presentation variation marker makes default text presentation emoji (narrow emoji) into wide emoji
CPUCell *cpu_cell = self->linebuf->line->cpu_cells + xpos;
@ -398,6 +408,7 @@ screen_draw(Screen *self, uint32_t och) {
self->cursor->x++;
}
self->is_dirty = true;
if (selection_has_screen_line(&self->selection, self->cursor->y)) self->selection = EMPTY_SELECTION;
linebuf_mark_line_dirty(self->linebuf, self->cursor->y);
}
@ -563,6 +574,7 @@ screen_toggle_screen_buffer(Screen *self) {
}
screen_history_scroll(self, SCROLL_FULL, false);
self->is_dirty = true;
self->selection = EMPTY_SELECTION;
}
void screen_normal_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI
@ -782,6 +794,22 @@ screen_cursor_to_column(Screen *self, unsigned int column) {
}
}
static inline void
index_selection(Screen *self, Selection *s, bool up) {
if (s->start_scrolled_by == s->end_scrolled_by && s->start_x == s->end_x && s->start_y == s->end_y) return;
if (up) {
if (s->start_y == 0) s->start_scrolled_by += 1;
else s->start_y--;
if (s->end_y == 0) s->end_scrolled_by += 1;
else s->end_y--;
} else {
if (s->start_y >= self->lines - 1) s->start_scrolled_by -= 1;
else s->start_y++;
if (s->end_y >= self->lines - 1) s->end_scrolled_by -= 1;
else s->end_y++;
}
}
#define INDEX_GRAPHICS(amtv) { \
bool is_main = self->linebuf == self->main_linebuf; \
static ScrollData s; \
@ -802,7 +830,8 @@ screen_cursor_to_column(Screen *self, unsigned int column) {
self->history_line_added_count++; \
} \
linebuf_clear_line(self->linebuf, bottom); \
self->is_dirty = true;
self->is_dirty = true; \
index_selection(self, &self->selection, true);
void
screen_index(Screen *self) {
@ -828,7 +857,8 @@ screen_scroll(Screen *self, unsigned int count) {
linebuf_reverse_index(self->linebuf, top, bottom); \
linebuf_clear_line(self->linebuf, top); \
INDEX_GRAPHICS(1) \
self->is_dirty = true;
self->is_dirty = true; \
index_selection(self, &self->selection, false);
void
screen_reverse_index(Screen *self) {
@ -1012,6 +1042,7 @@ screen_erase_in_line(Screen *self, unsigned int how, bool private) {
line_apply_cursor(self->linebuf->line, self->cursor, s, n, true);
}
self->is_dirty = true;
if (selection_has_screen_line(&self->selection, self->cursor->y)) self->selection = EMPTY_SELECTION;
linebuf_mark_line_dirty(self->linebuf, self->cursor->y);
}
}
@ -1055,6 +1086,7 @@ screen_erase_in_display(Screen *self, unsigned int how, bool private) {
linebuf_mark_line_dirty(self->linebuf, i);
}
self->is_dirty = true;
self->selection = EMPTY_SELECTION;
}
if (how != 2) {
screen_erase_in_line(self, how, private);
@ -1075,6 +1107,7 @@ screen_insert_lines(Screen *self, unsigned int count) {
if (top <= self->cursor->y && self->cursor->y <= bottom) {
linebuf_insert_lines(self->linebuf, count, self->cursor->y, bottom);
self->is_dirty = true;
self->selection = EMPTY_SELECTION;
screen_carriage_return(self);
}
}
@ -1086,6 +1119,7 @@ screen_delete_lines(Screen *self, unsigned int count) {
if (top <= self->cursor->y && self->cursor->y <= bottom) {
linebuf_delete_lines(self->linebuf, count, self->cursor->y, bottom);
self->is_dirty = true;
self->selection = EMPTY_SELECTION;
screen_carriage_return(self);
}
}
@ -1102,6 +1136,7 @@ screen_insert_characters(Screen *self, unsigned int count) {
line_apply_cursor(self->linebuf->line, self->cursor, x, num, true);
linebuf_mark_line_dirty(self->linebuf, self->cursor->y);
self->is_dirty = true;
if (selection_has_screen_line(&self->selection, self->cursor->y)) self->selection = EMPTY_SELECTION;
}
}
@ -1118,6 +1153,7 @@ screen_delete_characters(Screen *self, unsigned int count) {
line_apply_cursor(self->linebuf->line, self->cursor, self->columns - num, num, true);
linebuf_mark_line_dirty(self->linebuf, self->cursor->y);
self->is_dirty = true;
if (selection_has_screen_line(&self->selection, self->cursor->y)) self->selection = EMPTY_SELECTION;
}
}
@ -1131,6 +1167,7 @@ screen_erase_characters(Screen *self, unsigned int count) {
line_apply_cursor(self->linebuf->line, self->cursor, x, num, true);
linebuf_mark_line_dirty(self->linebuf, self->cursor->y);
self->is_dirty = true;
if (selection_has_screen_line(&self->selection, self->cursor->y)) self->selection = EMPTY_SELECTION;
}
// }}}
@ -1423,7 +1460,7 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat
update_line_data(self->linebuf->line, y, address);
}
if (was_dirty) {
self->selection = EMPTY_SELECTION; self->url_range = EMPTY_SELECTION;
self->url_range = EMPTY_SELECTION;
}
}