mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-08-27 03:42:49 +00:00
Fix flickering of prompt during window resize
Works by keeping the old prompt unreflowed rather than clearing it. There may still be some flicker for people using long or right side prompts, but that cant be avoided, since we cannot know how the shell will redraw after the resize. But in the common case of a left side smallish prompt that fits in the resized window, the flicker is eliminated. It means we have to do some more copying work on resize, but the nicer visuals is worth it, IMO.
This commit is contained in:
parent
a5b0db3219
commit
684d28d328
2 changed files with 38 additions and 10 deletions
|
|
@ -96,6 +96,8 @@ Detailed list of changes
|
|||
|
||||
- When asking for quit confirmation because of a running program, mention the program name (:iss:`7331`)
|
||||
|
||||
- Fix flickering of prompt during window resize (:iss:`7324`)
|
||||
|
||||
0.33.1 [2024-03-21]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -299,9 +299,10 @@ index_selection(const Screen *self, Selections *selections, bool up) {
|
|||
index_selection(self, &self->selections, false);
|
||||
|
||||
|
||||
static void
|
||||
prevent_current_prompt_from_rewrapping(Screen *self) {
|
||||
if (!self->prompt_settings.redraws_prompts_at_all) return;
|
||||
static index_type
|
||||
prevent_current_prompt_from_rewrapping(Screen *self, LineBuf *prompt_copy, index_type *num_of_prompt_lines_above_cursor) {
|
||||
index_type num_of_prompt_lines = 0; *num_of_prompt_lines_above_cursor = 0;
|
||||
if (!self->prompt_settings.redraws_prompts_at_all) return num_of_prompt_lines;
|
||||
int y = self->cursor->y;
|
||||
while (y >= 0) {
|
||||
linebuf_init_line(self->main_linebuf, y);
|
||||
|
|
@ -314,12 +315,12 @@ prevent_current_prompt_from_rewrapping(Screen *self) {
|
|||
goto found;
|
||||
break;
|
||||
case OUTPUT_START:
|
||||
return;
|
||||
return num_of_prompt_lines;
|
||||
}
|
||||
y--;
|
||||
}
|
||||
found:
|
||||
if (y < 0) return;
|
||||
if (y < 0) return num_of_prompt_lines;
|
||||
// we have identified a prompt at which the cursor is present, the shell
|
||||
// will redraw this prompt. However when doing so it gets confused if the
|
||||
// cursor vertical position relative to the first prompt line changes. This
|
||||
|
|
@ -327,16 +328,18 @@ found:
|
|||
// so when resizing, simply blank all lines after the current
|
||||
// prompt and trust the shell to redraw them.
|
||||
for (; y < (int)self->main_linebuf->ynum; y++) {
|
||||
linebuf_clear_line(self->main_linebuf, y, false);
|
||||
linebuf_init_line(self->main_linebuf, y);
|
||||
linebuf_copy_line_to(prompt_copy, self->main_linebuf->line, num_of_prompt_lines++);
|
||||
linebuf_clear_line(self->main_linebuf, y, false);
|
||||
if (y <= (int)self->cursor->y) {
|
||||
linebuf_init_line(self->main_linebuf, y);
|
||||
// this is needed because screen_resize() checks to see if the cursor is beyond the content,
|
||||
// so insert some fake content
|
||||
Line *line = self->linebuf->line;
|
||||
// we use a space as readline does not erase to bottom of screen so we fake it with spaces
|
||||
line->cpu_cells[0].ch = ' ';
|
||||
self->main_linebuf->line->cpu_cells[0].ch = ' ';
|
||||
if (y < (int)self->cursor->y) (*num_of_prompt_lines_above_cursor)++;
|
||||
}
|
||||
}
|
||||
return num_of_prompt_lines;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -372,7 +375,12 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
|
|||
HistoryBuf *nh = realloc_hb(self->historybuf, self->historybuf->ynum, columns, &self->as_ansi_buf);
|
||||
if (nh == NULL) return false;
|
||||
Py_CLEAR(self->historybuf); self->historybuf = nh;
|
||||
if (is_main) prevent_current_prompt_from_rewrapping(self);
|
||||
RAII_PyObject(prompt_copy, NULL);
|
||||
index_type num_of_prompt_lines = 0, num_of_prompt_lines_above_cursor = 0;
|
||||
if (is_main) {
|
||||
prompt_copy = (PyObject*)alloc_linebuf(self->lines, self->columns);
|
||||
num_of_prompt_lines = prevent_current_prompt_from_rewrapping(self, (LineBuf*)prompt_copy, &num_of_prompt_lines_above_cursor);
|
||||
}
|
||||
LineBuf *n = realloc_lb(self->main_linebuf, lines, columns, &num_content_lines_before, &num_content_lines_after, self->historybuf, &cursor, &main_saved_cursor, &self->as_ansi_buf);
|
||||
if (n == NULL) return false;
|
||||
Py_CLEAR(self->main_linebuf); self->main_linebuf = n;
|
||||
|
|
@ -433,6 +441,24 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
|
|||
self->linebuf->line->cpu_cells[0].ch = 0;
|
||||
self->cursor->x = 0;
|
||||
}
|
||||
if (num_of_prompt_lines) {
|
||||
// Copy the old prompt lines without any reflow this prevents
|
||||
// flickering of prompt during resize. THe flicker is caused by the
|
||||
// prompt being first cleared by kitty then sometime later redrawn by
|
||||
// the shell.
|
||||
LineBuf *src = (LineBuf*)prompt_copy;
|
||||
for (index_type
|
||||
src_line = 0,
|
||||
y = num_of_prompt_lines_above_cursor <= self->cursor->y ? self->cursor->y - num_of_prompt_lines_above_cursor : 0;
|
||||
|
||||
src_line < num_of_prompt_lines && y < self->lines;
|
||||
|
||||
y++, src_line++
|
||||
) {
|
||||
linebuf_init_line(src, src_line);
|
||||
linebuf_copy_line_to(self->main_linebuf, src->line, y);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue