diff --git a/kitty/layout/base.py b/kitty/layout/base.py index 6deb610d2..cb957a1f0 100644 --- a/kitty/layout/base.py +++ b/kitty/layout/base.py @@ -117,14 +117,14 @@ def layout_dimension( bias: None | Sequence[float] | dict[int, float] = None ) -> LayoutDimension: number_of_windows = len(decoration_pairs) - number_of_cells = length // cell_length + number_of_cells = max(0, length // cell_length) dec_vals: Iterable[int] = map(sum, decoration_pairs) space_needed_for_decorations = sum(dec_vals) extra = length - number_of_cells * cell_length - while extra < space_needed_for_decorations: + while extra < space_needed_for_decorations and number_of_cells > 0: number_of_cells -= 1 extra = length - number_of_cells * cell_length - cells_map = calculate_cells_map(bias, number_of_windows, number_of_cells) + cells_map = calculate_cells_map(bias, number_of_windows, number_of_cells) if number_of_cells > 0 else [0] * number_of_windows assert sum(cells_map) == number_of_cells extra = length - number_of_cells * cell_length - space_needed_for_decorations diff --git a/kitty_tests/layout.py b/kitty_tests/layout.py index cbcad2a0c..517ad5fd7 100644 --- a/kitty_tests/layout.py +++ b/kitty_tests/layout.py @@ -3,7 +3,7 @@ from kitty.config import defaults from kitty.fast_data_types import BOTTOM_EDGE, LEFT_EDGE, RIGHT_EDGE, TOP_EDGE, Region -from kitty.layout.base import lgd +from kitty.layout.base import layout_dimension, lgd from kitty.layout.interface import Grid, Horizontal, Splits, Stack, Tall from kitty.layout.splits import Pair from kitty.types import WindowGeometry @@ -325,6 +325,22 @@ def test_splits_maximize(self): self.assertTrue(result) self.ae(root.bias, root_bias_before) + def test_layout_dimension_no_negative_cells(self): + # Regression test for issue #9946: when window padding exceeds the + # available space (e.g. after maximize sets a window to minimum width), + # layout_dimension must not produce a negative cells_per_window value + # which would cause right < left in the resulting window geometry. + for length, cell_length, decs in ( + (8, 8, [(5, 5)]), # padding (10) > length (8) > cell_length (8) + (6, 8, [(4, 4)]), # length < cell_length + (0, 8, [(4, 4)]), # zero length + (4, 8, [(3, 3)]), # space_needed == length, no room for cells + ): + result = next(layout_dimension(0, length, cell_length, decs)) + self.assertGreaterEqual(result.cells_per_window, 0, + f'cells_per_window={result.cells_per_window} < 0 for length={length}, ' + f'cell_length={cell_length}, decs={decs}') + def test_drag_resize_target_windows(self): # Helper: call drag_resize_target_windows with given window and edge flags. def drtw(q, all_windows, window, edges):