Scrollback filling should happen after cursor position is finalized

This commit is contained in:
Kovid Goyal 2021-03-17 21:59:11 +05:30
parent a4d9d948ab
commit 0f3ff4e2d9
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 67 additions and 68 deletions

View File

@ -212,6 +212,33 @@ realloc_lb(LineBuf *old, unsigned int lines, unsigned int columns, index_type *n
return ans;
}
static inline bool
is_selection_empty(const Selection *s) {
int start_y = (int)s->start.y - (int)s->start_scrolled_by, end_y = (int)s->end.y - (int)s->end_scrolled_by;
return s->start.x == s->end.x && s->start.in_left_half_of_cell == s->end.in_left_half_of_cell && start_y == end_y;
}
static inline void
index_selection(const Screen *self, Selections *selections, bool up) {
for (size_t i = 0; i < selections->count; i++) {
Selection *s = selections->items + i;
if (!is_selection_empty(s)) {
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; \
@ -221,6 +248,16 @@ realloc_lb(LineBuf *old, unsigned int lines, unsigned int columns, index_type *n
grman_scroll_images(self->grman, &s, self->cell_size); \
}
#define INDEX_DOWN \
if (self->overlay_line.is_active) deactivate_overlay_line(self); \
linebuf_reverse_index(self->linebuf, top, bottom); \
linebuf_clear_line(self->linebuf, top); \
INDEX_GRAPHICS(1) \
self->is_dirty = true; \
index_selection(self, &self->selections, false);
static bool
screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
if (self->overlay_line.is_active) deactivate_overlay_line(self);
@ -247,19 +284,11 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
if (n == NULL) return false;
int lines_to_fill = -1;
if (is_main && OPT(scrollback_fill_enlarged_window)) {
int lines_to_fill = (lines - self->main_linebuf->ynum) + (
lines_to_fill = (lines - self->main_linebuf->ynum) + (
linebuf_continued_lines_count(self->main_linebuf, self->cursor->y) - linebuf_continued_lines_count(n, y));
const unsigned int top = 0, bottom = lines-1;
Line last_history_line = {.xnum=self->historybuf->xnum};
while (lines_to_fill-- > 0) {
if (!historybuf_pop_line(self->historybuf, &last_history_line)) break;
linebuf_reverse_index(n, top, bottom);
INDEX_GRAPHICS(1);
linebuf_add_line_to_top(n, &last_history_line);
}
}
Py_CLEAR(self->main_linebuf); self->main_linebuf = n;
if (is_main) setup_cursor();
grman_resize(self->main_grman, self->lines, lines, self->columns, columns);
@ -295,6 +324,14 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
self->cursor->y = num_content_lines;
if (self->cursor->y >= self->lines) { self->cursor->y = self->lines - 1; screen_index(self); }
}
if (lines_to_fill > 0) {
const unsigned int top = 0, bottom = self->lines-1;
while (lines_to_fill-- > 0) {
if (!historybuf_pop_line(self->historybuf, self->alt_linebuf->line)) break;
INDEX_DOWN;
linebuf_add_line_to_top(self->main_linebuf, self->alt_linebuf->line);
}
}
return true;
}
@ -394,12 +431,6 @@ move_widened_char(Screen *self, CPUCell* cpu_cell, GPUCell *gpu_cell, index_type
*dest_gpu = src_gpu;
}
static inline bool
is_selection_empty(const Selection *s) {
int start_y = (int)s->start.y - (int)s->start_scrolled_by, end_y = (int)s->end.y - (int)s->end_scrolled_by;
return s->start.x == s->end.x && s->start.in_left_half_of_cell == s->end.in_left_half_of_cell && start_y == end_y;
}
static inline bool
selection_has_screen_line(const Selections *selections, const int y) {
for (size_t i = 0; i < selections->count; i++) {
@ -1058,26 +1089,6 @@ screen_cursor_to_column(Screen *self, unsigned int column) {
}
}
static inline void
index_selection(const Screen *self, Selections *selections, bool up) {
for (size_t i = 0; i < selections->count; i++) {
Selection *s = selections->items + i;
if (!is_selection_empty(s)) {
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_UP \
if (self->overlay_line.is_active) deactivate_overlay_line(self); \
linebuf_index(self->linebuf, top, bottom); \
@ -1111,14 +1122,6 @@ screen_scroll(Screen *self, unsigned int count) {
}
}
#define INDEX_DOWN \
if (self->overlay_line.is_active) deactivate_overlay_line(self); \
linebuf_reverse_index(self->linebuf, top, bottom); \
linebuf_clear_line(self->linebuf, top); \
INDEX_GRAPHICS(1) \
self->is_dirty = true; \
index_selection(self, &self->selections, false);
void
screen_reverse_index(Screen *self) {
// Move cursor up one line, scrolling screen if needed

View File

@ -91,14 +91,10 @@ class BaseTest(TestCase):
options = Options(merge_configs(defaults._asdict(), final_options))
set_options(options)
def create_screen(self, cols=5, lines=5, scrollback=5, cell_width=10, cell_height=20, options=None, content=()):
def create_screen(self, cols=5, lines=5, scrollback=5, cell_width=10, cell_height=20, options=None):
self.set_options(options)
c = Callbacks()
s = Screen(c, lines, cols, scrollback, cell_width, cell_height, 0, c)
for content_line in content:
s.draw(content_line)
s.linefeed()
s.carriage_return()
return s
def assertEqualAttributes(self, c1, c2):

View File

@ -305,45 +305,45 @@ class TestScreen(BaseTest):
def test_scrollback_fill_after_resize(self):
def prepare_screen(content=()):
return self.create_screen(
lines=5,
cols=5,
options={'scrollback_fill_enlarged_window': True},
content=content,
)
ans = self.create_screen(options={'scrollback_fill_enlarged_window': True})
for line in content:
ans.draw(line)
ans.linefeed()
ans.carriage_return()
return ans
def assert_lines(lines, s):
return self.ae(lines, str(s.linebuf).split("\n"))
def assert_lines(*lines):
return self.ae(lines, tuple(str(s.line(i)) for i in range(s.lines)))
# Height increased, width unchanged → pull down lines to fill new space at the top
s = prepare_screen([str(i) for i in range(0, 6)])
assert_lines(['2', '3', '4', '5', ''], s)
s = prepare_screen(map(str, range(6)))
assert_lines('2', '3', '4', '5', '')
s.resize(7, s.columns)
assert_lines(['0', '1', '2', '3', '4', '5', ''], s)
assert_lines('0', '1', '2', '3', '4', '5', '')
# Height increased, width increased → rewrap, pull down
s = prepare_screen(['0', '1', '2', '3' * 15])
assert_lines(['2', '33333', '33333', '33333', ''], s)
assert_lines('2', '33333', '33333', '33333', '')
s.resize(7, 12)
assert_lines(['0', '1', '2', '333333333333', '333', '', ''], s)
assert_lines('0', '1', '2', '333333333333', '333', '', '')
# Height increased, width decreased → rewrap, pull down if possible
s = prepare_screen(['0', '1', '2', '3' * 5])
assert_lines(['0', '1', '2', '33333', ''], s)
assert_lines('0', '1', '2', '33333', '')
s.resize(6, 4)
assert_lines(['0', '1', '2', '3333', '3', ''], s)
assert_lines('0', '1', '2', '3333', '3', '')
# Height unchanged, width increased → rewrap, pull down if possible
s = prepare_screen(['0', '1', '2', '3' * 15])
assert_lines(['2', '33333', '33333', '33333', ''], s)
assert_lines('2', '33333', '33333', '33333', '')
s.resize(s.lines, 12)
assert_lines(['1', '2', '333333333333', '333', ''], s)
assert_lines('1', '2', '333333333333', '333', '')
# Height decreased, width increased → rewrap, pull down if possible
s = prepare_screen(['0', '1', '2', '3' * 15])
assert_lines(['2', '33333', '33333', '33333', ''], s)
assert_lines('2', '33333', '33333', '33333', '')
s.resize(4, 12)
assert_lines(['2', '333333333333', '333', ''], s)
assert_lines('2', '333333333333', '333', '')
def test_tab_stops(self):
# Taken from vttest/main.c