mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-06-09 17:41:36 +00:00
fix(screen): preserve tab stops across window resizes
Previously, every window resize reinitialised the tab stops to the default of every 8 columns, discarding any stops set via HTS or cleared via TBC. ECMA-48 only treats RIS, DECSTR, and DECCOLM as events that reset tab stops, and other terminal emulators all preserve user-set stops across an interactive resize. Copy the surviving prefix of the previous tab stops into the freshly allocated array on both main and alt screens. Newly added columns when growing the window keep the default every 8 columns pattern. Also point the active tabstops pointer at the alt screen's array when a resize happens while the alt screen is active, instead of unconditionally resetting it to the main screen's array. Signed-off-by: Ayman Bagabas <aymanbagabas@gmail.com>
This commit is contained in:
parent
e257e5695f
commit
3138ae4aad
3 changed files with 47 additions and 7 deletions
|
|
@ -176,6 +176,8 @@ Detailed list of changes
|
|||
0.47.1 [future]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Preserve user-set tab stops across window resizes (previously they were reset to every 8 columns on every resize)
|
||||
|
||||
- Fix a regression in the previous release that caused :ac:`copy_or_noop` to stop working correctly (:pull:`10041`)
|
||||
|
||||
- macOS: Fix a regression in the previous release that caused URLs to be quoted when dropping into shells (:iss:`10054`)
|
||||
|
|
|
|||
|
|
@ -575,16 +575,26 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
|
|||
grman_resize(self->alt_grman, self->lines, lines, self->columns, columns, num_content_lines_before, num_content_lines_after);
|
||||
#undef setup_cursor
|
||||
/* printf("\nold_size: (%u, %u) new_size: (%u, %u)\n", self->columns, self->lines, columns, lines); */
|
||||
index_type old_columns_for_tabs = self->columns;
|
||||
self->lines = lines; self->columns = columns;
|
||||
self->margin_top = 0; self->margin_bottom = self->lines - 1;
|
||||
|
||||
PyMem_Free(self->main_tabstops);
|
||||
self->main_tabstops = PyMem_Calloc(2*self->columns, sizeof(bool));
|
||||
if (self->main_tabstops == NULL) { PyErr_NoMemory(); return false; }
|
||||
self->alt_tabstops = self->main_tabstops + self->columns;
|
||||
self->tabstops = self->main_tabstops;
|
||||
init_tabstops(self->main_tabstops, self->columns);
|
||||
init_tabstops(self->alt_tabstops, self->columns);
|
||||
bool *old_tabstops = self->main_tabstops;
|
||||
bool *new_tabstops = PyMem_Calloc(2 * self->columns, sizeof(bool));
|
||||
if (new_tabstops == NULL) { PyErr_NoMemory(); return false; }
|
||||
bool *new_main = new_tabstops;
|
||||
bool *new_alt = new_tabstops + self->columns;
|
||||
init_tabstops(new_main, self->columns);
|
||||
init_tabstops(new_alt, self->columns);
|
||||
if (old_tabstops && old_columns_for_tabs) {
|
||||
index_type to_copy = MIN(old_columns_for_tabs, self->columns);
|
||||
memcpy(new_main, old_tabstops, to_copy * sizeof(bool));
|
||||
memcpy(new_alt, old_tabstops + old_columns_for_tabs, to_copy * sizeof(bool));
|
||||
}
|
||||
PyMem_Free(old_tabstops);
|
||||
self->main_tabstops = new_main;
|
||||
self->alt_tabstops = new_alt;
|
||||
self->tabstops = is_main ? self->main_tabstops : self->alt_tabstops;
|
||||
self->is_dirty = true;
|
||||
clear_all_selections(self);
|
||||
self->last_visited_prompt.is_set = false;
|
||||
|
|
|
|||
|
|
@ -531,6 +531,34 @@ class TestScreen(BaseTest):
|
|||
s.draw('aaaX\tbbbb')
|
||||
self.ae(str(s.line(0)) + str(s.line(1)), 'aaaXbbbb')
|
||||
|
||||
# Custom tab stops survive a window resize
|
||||
s = self.create_screen(cols=20, lines=2)
|
||||
s.clear_tab_stop(3) # clear all
|
||||
s.cursor_position(1, 5)
|
||||
s.set_tab_stop() # stop at column index 4
|
||||
s.cursor_position(1, 13)
|
||||
s.set_tab_stop() # stop at column index 12
|
||||
# Grow: existing stops preserved, new columns get default every-8 stops
|
||||
s.resize(s.lines, 30)
|
||||
s.cursor_position(1, 1)
|
||||
s.tab(); self.ae(s.cursor.x, 4)
|
||||
s.tab(); self.ae(s.cursor.x, 12)
|
||||
s.tab(); self.ae(s.cursor.x, 24) # default stop in newly added columns
|
||||
# Shrink: stops within new width are preserved
|
||||
s.resize(s.lines, 15)
|
||||
s.cursor_position(1, 1)
|
||||
s.tab(); self.ae(s.cursor.x, 4)
|
||||
s.tab(); self.ae(s.cursor.x, 12)
|
||||
# Resize on alt screen also preserves alt-screen tab stops
|
||||
s = self.create_screen(cols=20, lines=2)
|
||||
parse_bytes(s, b'\x1b[?1049h') # switch to alt screen
|
||||
s.clear_tab_stop(3)
|
||||
s.cursor_position(1, 5)
|
||||
s.set_tab_stop()
|
||||
s.resize(s.lines, 30)
|
||||
s.cursor_position(1, 1)
|
||||
s.tab(); self.ae(s.cursor.x, 4)
|
||||
|
||||
def test_backspace(self):
|
||||
s = self.create_screen()
|
||||
q = 'a'*s.columns
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue