From 43913bb470d023a50dd3ce56e8fb8f5665053e38 Mon Sep 17 00:00:00 2001 From: Aravinda Rao Date: Mon, 15 Apr 2024 18:05:06 +0530 Subject: [PATCH] fix(core/tree): ensure push_in_with_neighbor() and merge_with_neighbor_to_subtab() don't fail when there are no neighbor nodes --- src/qtile_bonsai/core/tree.py | 15 ++++++--------- src/qtile_bonsai/layout.py | 20 ++++++++++++-------- tests/unit/core/test_tree.py | 19 ++++++++++++++++++- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/qtile_bonsai/core/tree.py b/src/qtile_bonsai/core/tree.py index 6649e17..52ca27b 100644 --- a/src/qtile_bonsai/core/tree.py +++ b/src/qtile_bonsai/core/tree.py @@ -771,23 +771,23 @@ def resolve_node_neighbor_selection( mode = NodeHierarchySelectionMode(selection_mode) border_direction = Direction(border_direction) + adjacent_panes = self.adjacent_panes(node, border_direction, wrap=wrap) + if not adjacent_panes: + raise InvalidNodeSelectionError("There is no neighbor node to select.") + if mode == NodeHierarchySelectionMode.mru_deepest: - adjacent_panes = self.adjacent_panes(node, border_direction, wrap=wrap) resolved_node = self.find_mru_pane(panes=adjacent_panes) elif mode == NodeHierarchySelectionMode.mru_largest: besp = self.find_border_encompassing_supernode( node, border_direction, stop_at_tc=False ) - if besp is None: - raise InvalidNodeSelectionError("There is no suitable node to select.") + assert besp is not None resolved_node = besp.sibling(border_direction.axis_unit, wrap=wrap) elif mode == NodeHierarchySelectionMode.mru_subtab_else_deepest: - adjacent_panes = self.adjacent_panes(node, border_direction, wrap=wrap) deepest = self.find_mru_pane(panes=adjacent_panes) tc = deepest.get_first_ancestor(TabContainer) resolved_node = tc if tc.tab_level > 1 else deepest elif mode == NodeHierarchySelectionMode.mru_subtab_else_largest: - adjacent_panes = self.adjacent_panes(node, border_direction, wrap=wrap) deepest = self.find_mru_pane(panes=adjacent_panes) tc = deepest.get_first_ancestor(TabContainer) if tc.tab_level > 1: @@ -796,10 +796,7 @@ def resolve_node_neighbor_selection( besp = self.find_border_encompassing_supernode( node, border_direction, stop_at_tc=False ) - if besp is None: - raise InvalidNodeSelectionError( - "There is no suitable node to select." - ) + assert besp is not None resolved_node = besp.sibling(border_direction.axis_unit, wrap=wrap) else: raise ValueError(f"Invalid `selection_mode`: {selection_mode}") diff --git a/src/qtile_bonsai/layout.py b/src/qtile_bonsai/layout.py index a91e046..7369437 100644 --- a/src/qtile_bonsai/layout.py +++ b/src/qtile_bonsai/layout.py @@ -734,13 +734,17 @@ def merge_to_subtab( if self._tree.is_empty: return - self._tree.merge_with_neighbor_to_subtab( - self.focused_pane, - direction, - src_selection_mode=src_selection_mode, - dest_selection_mode=dest_selection_mode, - normalize=normalize, - ) + try: + self._tree.merge_with_neighbor_to_subtab( + self.focused_pane, + direction, + src_selection_mode=src_selection_mode, + dest_selection_mode=dest_selection_mode, + normalize=normalize, + ) + except InvalidNodeSelectionError: + return + self._request_relayout() @expose_command @@ -749,7 +753,7 @@ def push_in( direction: DirectionParam, *, src_selection_mode: NodeHierarchySelectionMode = NodeHierarchySelectionMode.mru_deepest, - dest_selection_mode: NodeHierarchySelectionMode = NodeHierarchySelectionMode.mru_largest, + dest_selection_mode: NodeHierarchySelectionMode = NodeHierarchySelectionMode.mru_deepest, normalize: bool = True, wrap: bool = True, ): diff --git a/tests/unit/core/test_tree.py b/tests/unit/core/test_tree.py index 95fa863..4751b0d 100644 --- a/tests/unit/core/test_tree.py +++ b/tests/unit/core/test_tree.py @@ -7,8 +7,9 @@ import pytest import tests.data.tree_state -from qtile_bonsai.core.geometry import Rect +from qtile_bonsai.core.geometry import Direction, Rect from qtile_bonsai.core.tree import ( + InvalidNodeSelectionError, NodeHierarchySelectionMode, Pane, Tab, @@ -5351,6 +5352,22 @@ def test_given_deep_tree_when_src_is_sc_with_inv_axis_of_dest_push_axis( assert cb_remove.mock_calls == [mock.call([sc_y_to_prune])] +class TestResolveNodeNeighborSelection: + @pytest.mark.parametrize("selection_mode", list(NodeHierarchySelectionMode)) + def test_when_there_are_no_adjacent_nodes_then_error_is_raised( + self, tree: Tree, selection_mode: NodeHierarchySelectionMode + ): + p1 = tree.tab() + + err_msg = "There is no neighbor node to select" + with pytest.raises(InvalidNodeSelectionError, match=err_msg): + tree.resolve_node_neighbor_selection( + p1, + selection_mode, + Direction.right, + ) + + class TestConfig: def test_when_config_is_passed_on_init_then_it_overrides_default_config(self): # Default window.margin is 0