From 0f3ff4e2d907dc7045cfeb1754b8637effa3eac8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 17 Mar 2021 21:59:11 +0530 Subject: [PATCH] Scrollback filling should happen after cursor position is finalized --- kitty/screen.c | 91 +++++++++++++++++++++-------------------- kitty_tests/__init__.py | 6 +-- kitty_tests/screen.py | 38 ++++++++--------- 3 files changed, 67 insertions(+), 68 deletions(-) diff --git a/kitty/screen.c b/kitty/screen.c index f109d17e3..b5bf807e4 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -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 diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py index 19568636a..5c0c2f465 100644 --- a/kitty_tests/__init__.py +++ b/kitty_tests/__init__.py @@ -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): diff --git a/kitty_tests/screen.py b/kitty_tests/screen.py index bdb493794..594da05cb 100644 --- a/kitty_tests/screen.py +++ b/kitty_tests/screen.py @@ -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