From 9740861ec50da16ea07dc848e6e38494ddbad610 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 2 Oct 2025 10:43:36 +0530 Subject: [PATCH] Splits layout: Fix corrupted layout in some circs Basically one function was adding a window id instead of a group id to the pairs. Fixes #9059 --- docs/changelog.rst | 6 ++++++ kitty/layout/splits.py | 29 ++++++++++++++--------------- kitty/window_list.py | 3 +++ 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 1f31fddae..a5ff2fc5a 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -134,6 +134,12 @@ consumption to do the same tasks. Detailed list of changes ------------------------------------- +0.43.2 [future] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Splits layout: Fix a bug that could cause a corrupted layout in some + circumstances (:iss:`9059`) + 0.43.1 [2025-10-01] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/layout/splits.py b/kitty/layout/splits.py index b0ef321bb..bb83e3ded 100644 --- a/kitty/layout/splits.py +++ b/kitty/layout/splits.py @@ -511,24 +511,21 @@ def remove_windows(self, *windows_to_remove: int) -> None: def do_layout(self, all_windows: WindowList) -> None: groups = tuple(all_windows.iter_all_layoutable_groups()) - window_count = len(groups) root = self.pairs_root - all_present_window_ids = frozenset(w.id for w in groups) - already_placed_window_ids = frozenset(root.all_window_ids()) - windows_to_remove = already_placed_window_ids - all_present_window_ids - if windows_to_remove: - self.remove_windows(*windows_to_remove) - id_window_map = {w.id: w for w in groups} - id_idx_map = {w.id: i for i, w in enumerate(groups)} - windows_to_add = all_present_window_ids - already_placed_window_ids - if windows_to_add: - for wid in sorted(windows_to_add, key=id_idx_map.__getitem__): - root.balanced_add(wid) + all_present_group_ids = {g.id for g in groups} + already_placed_group_ids = frozenset(root.all_window_ids()) + if groups_to_remove := already_placed_group_ids - all_present_group_ids: + self.remove_windows(*groups_to_remove) + if groups_to_add := all_present_group_ids - already_placed_group_ids: + id_idx_map = {g.id: i for i, g in enumerate(groups)} + for gid in sorted(groups_to_add, key=id_idx_map.__getitem__): + root.balanced_add(gid) - if window_count == 1: + if len(groups) == 1: self.layout_single_window_group(groups[0]) else: - root.layout_pair(lgd.central.left, lgd.central.top, lgd.central.width, lgd.central.height, id_window_map, self) + id_group_map = {g.id: g for g in groups} + root.layout_pair(lgd.central.left, lgd.central.top, lgd.central.width, lgd.central.height, id_group_map, self) def add_non_overlay_window( self, @@ -563,7 +560,9 @@ def add_non_overlay_window( parent_pair.bias = bias if parent_pair.one == target_group.id else (1 - bias) return all_windows.add_window(window) - p = self.pairs_root.balanced_add(window.id) + g = all_windows.group_for_window(window) + assert g is not None + p = self.pairs_root.balanced_add(g.id) if bias is not None: p.bias = bias diff --git a/kitty/window_list.py b/kitty/window_list.py index 0fba377c1..48dde41c4 100644 --- a/kitty/window_list.py +++ b/kitty/window_list.py @@ -33,6 +33,9 @@ def __init__(self) -> None: self.windows: list[WindowType] = [] self.id = next(group_id_counter) + def __repr__(self) -> str: + return f'WindowGroup(id={self.id}, windows={", ".join(str(w.id) for w in self.windows)})' + def __len__(self) -> int: return len(self.windows)