aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2023-02-17 12:05:50 +0100
committerGitHub <noreply@github.com>2023-02-17 12:05:50 +0100
commitf1ff272b0b65f6d328fef24531ada67ea585ce85 (patch)
tree0e33aa4a1af21c0785fa30118ee42a21972497cf
parentdocs(changelog): termwiz update (diff)
downloadsl0ppij-f1ff272b0b65f6d328fef24531ada67ea585ce85.tar.gz
sl0ppij-f1ff272b0b65f6d328fef24531ada67ea585ce85.tar.xz
sl0ppij-f1ff272b0b65f6d328fef24531ada67ea585ce85.zip
feat(ui): swap layouts and stacked panes (#2167)
* relayout working with hard coded layout * work * refactor(layout): PaneLayout => TiledPaneLayout * tests passing * tests passing * tests passing * stacked panes and passing tests * tests for stacked panes * refactor(panes): stacked panes * fix: focusing into stacked panes from the left/right * fix(layouts): handle stacked layouts in the middle of the screen * fix(pane-stack): focus correctly when coming to stack from above/below * fix(stacked-panes): resize stack * fix(stacked-panes): focus with mouse * fix(stacked-panes): focus next pane * fix(layout-applier): sane focus order * fix(stacked-panes): better titles for one-liners * fix(stacked-panes): handle moving pane location in stack * fix(relayout): properly calculate display area * fix(relayout): properly calculate rounding errors * fix(stacked-panes): properly handle closing a pane near a stack * fix(swap-layouts): adjust swap layout sort order * feat(swap-layouts): ui + ux * fix(swap-layouts): include base layout * refactor(layout): remove unused method * fix(swap-layouts): respect pane contents and focus * work * fix(swap-layouts): load swap layouts from external file * fix(swap-layouts): properly truncate layout children * fix(stacked-panes): allow stacked panes to become fullscreen * fix(swap-layouts): work with multiple tabs * fix(swap-layouts): embed/eject panes properly with auto-layout * fix(stacked-panes): close last pane in stack * fix(stacked-panes): move focus for all clients in stack * fix(floating-panes): set layout damaged when moving panes * fix(relayout): move out of unfitting layout when resizing whole tab * fix(ui): background color for swap layout indicator * fix(keybinds): add switch next layout in tmux * fix(ui): swap layout indication in compact layout * fix(compact): correct swap constraint * fix(tests): tmux swap config shortcut * fix(resizes): cache resizes so as not to confuse panes (eg. vim) with multiple resizes that it debounces weirdly * feat(cli): dump swap layouts * fix(ui): stacked panes without pane frames * fix(ux): move pane forward/backwards also with floating panes * refactor(lint): remove unused stuff * refactor(tab): move swap layouts to separate file * style(fmt): rustfmt * style(fmt): rustfmt * refactor(panes): various cleanups * chore(deps): upgrade termwiz to get alt left-bracket * fix(assets): merge conflicts of binary files * style(fmt): rustfmt * style(clippy): no thank you! * chore(repo): remove garbage file
-rw-r--r--default-plugins/compact-bar/src/line.rs94
-rw-r--r--default-plugins/compact-bar/src/main.rs6
-rw-r--r--default-plugins/status-bar/src/first_line.rs146
-rw-r--r--default-plugins/status-bar/src/main.rs103
-rw-r--r--default-plugins/status-bar/src/second_line.rs7
-rw-r--r--default-plugins/status-bar/src/tip/data/compact_layout.rs8
-rw-r--r--default-plugins/status-bar/src/tip/data/edit_scrollbuffer.rs8
-rw-r--r--default-plugins/status-bar/src/tip/data/floating_panes_mouse.rs3
-rw-r--r--default-plugins/status-bar/src/tip/data/move_focus_hjkl_tab_switch.rs4
-rw-r--r--default-plugins/status-bar/src/tip/data/quicknav.rs8
-rw-r--r--default-plugins/status-bar/src/tip/data/sync_tab.rs8
-rw-r--r--src/tests/e2e/remote_runner.rs7
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap2
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap4
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions-2.snap2
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions.snap2
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab-2.snap4
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab.snap4
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap4
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap4
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane.snap6
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap4
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap2
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap4
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap4
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__tmux_mode.snap4
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap4
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_pane_fullscreen.snap4
-rw-r--r--zellij-server/src/lib.rs20
-rw-r--r--zellij-server/src/os_input_output.rs29
-rw-r--r--zellij-server/src/panes/active_panes.rs1
-rw-r--r--zellij-server/src/panes/floating_panes/floating_pane_grid.rs55
-rw-r--r--zellij-server/src/panes/floating_panes/mod.rs126
-rw-r--r--zellij-server/src/panes/plugin_pane.rs24
-rw-r--r--zellij-server/src/panes/terminal_pane.rs32
-rw-r--r--zellij-server/src/panes/tiled_panes/mod.rs364
-rw-r--r--zellij-server/src/panes/tiled_panes/pane_resizer.rs137
-rw-r--r--zellij-server/src/panes/tiled_panes/stacked_panes.rs630
-rw-r--r--zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs445
-rw-r--r--zellij-server/src/panes/unit/search_in_pane_tests.rs1
-rw-r--r--zellij-server/src/panes/unit/terminal_pane_tests.rs12
-rw-r--r--zellij-server/src/plugins/mod.rs11
-rw-r--r--zellij-server/src/pty.rs10
-rw-r--r--zellij-server/src/route.rs34
-rw-r--r--zellij-server/src/screen.rs103
-rw-r--r--zellij-server/src/tab/layout_applier.rs367
-rw-r--r--zellij-server/src/tab/mod.rs322
-rw-r--r--zellij-server/src/tab/swap_layouts.rs284
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_floating_layout_is_included_in_swap_layouts.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_layout_is_included_in_swap_layouts.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_horizontally.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_non_directionally.snap46
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_vertically.snap46
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_horizontally.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_non_directionally.snap46
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_vertically.snap46
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_between_multiple_layouts.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_floating_layout_at_runtime.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_tiled_layout_at_runtime.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__cannot_decrease_stack_size_beyond_minimum_height.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_main_stacked_pane.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_main_stacked_pane_in_mid_stack.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_one_liner_stacked_pane_above_main_pane.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_one_liner_stacked_pane_below_main_pane.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_pane_near_stacked_panes.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_stacked_pane_with_previously_focused_other_pane.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__decreasing_size_of_whole_tab_treats_stacked_panes_properly.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_layout_with_plugins_and_commands_swaped_properly.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_next_pane_expands_stacked_panes.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_stacked_pane_over_flexible_pane_with_the_mouse.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_stacked_pane_under_flexible_pane_with_the_mouse.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_into_main_pane_in_stack_horizontally_does_not_break_stack.snap46
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_of_main_pane_in_stack_horizontally_does_not_break_stack.snap46
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_of_whole_tab_treats_stacked_panes_properly.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__layout_with_plugins_and_commands_swaped_properly.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_down_into_stacked_panes.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_down_with_stacked_panes.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_left_into_stacked_panes.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_right_into_stacked_panes.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_up_into_stacked_panes.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_up_with_stacked_panes.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_with_stacked_panes.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-2.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-3.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-2.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-3.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-4.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-5.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-6.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-7.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_tab_with_floating_panes.snap2
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap2
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically.snap2
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_back.snap2
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__stacked_panes_can_become_fullscreen.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_command_panes_absent_from_existing_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_plugin_panes_absent_from_existing_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_command_panes_present_in_existing_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_plugin_panes_present_in_existing_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_including_command_panes_absent_from_existing_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_including_plugin_panes_absent_from_existing_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_command_panes_present_in_existing_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_plugin_panes_present_in_existing_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_tiled_layout_with_stacked_children.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_tiled_layout_with_stacked_children_and_no_pane_frames.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swapping_layouts_after_resize_snaps_to_current_layout.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_floating_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_resizing_whole_tab_with_auto_layout_and_floating_panes_the_layout_is_maintained.snap36
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_an_undamaged_state_pane_focuses_on_focused_node.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_an_undamaged_state_with_no_focus_node_pane_focuses_on_deepest_node.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_an_undamaged_state_pane_focuses_on_focused_node.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_an_undamaged_state_with_no_focus_node_pane_focuses_on_deepest_node.snap26
-rw-r--r--zellij-server/src/tab/unit/tab_integration_tests.rs4067
-rw-r--r--zellij-server/src/tab/unit/tab_tests.rs55
-rw-r--r--zellij-server/src/thread_bus.rs6
-rw-r--r--zellij-server/src/ui/boundaries.rs14
-rw-r--r--zellij-server/src/ui/pane_boundaries_frame.rs133
-rw-r--r--zellij-server/src/ui/pane_contents_and_ui.rs15
-rw-r--r--zellij-server/src/unit/os_input_output_tests.rs1
-rw-r--r--zellij-server/src/unit/screen_tests.rs194
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_default_params.snap11
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap14
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_tab.snap48
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_tab.snap56
-rw-r--r--zellij-utils/assets/compact-bar.wasmbin0 -> 397489 bytes
-rw-r--r--zellij-utils/assets/config/default.kdl11
-rw-r--r--zellij-utils/assets/layouts/compact.swap.kdl91
-rw-r--r--zellij-utils/assets/layouts/default.swap.kdl94
-rw-r--r--zellij-utils/assets/layouts/strider.kdl23
-rw-r--r--zellij-utils/assets/layouts/strider.swap.kdl102
-rw-r--r--zellij-utils/assets/plugins/compact-bar.wasmbin397489 -> 427886 bytes
-rw-r--r--zellij-utils/assets/plugins/status-bar.wasmbin485616 -> 520407 bytes
-rw-r--r--zellij-utils/assets/plugins/strider.wasmbin413509 -> 441654 bytes
-rw-r--r--zellij-utils/assets/plugins/tab-bar.wasmbin373679 -> 400807 bytes
-rw-r--r--zellij-utils/assets/status-bar.wasmbin0 -> 485616 bytes
-rw-r--r--zellij-utils/assets/strider.wasmbin0 -> 413509 bytes
-rw-r--r--zellij-utils/assets/tab-bar.wasmbin0 -> 373679 bytes
-rw-r--r--zellij-utils/src/cli.rs42
-rw-r--r--zellij-utils/src/data.rs2
-rw-r--r--zellij-utils/src/errors.rs3
-rw-r--r--zellij-utils/src/input/actions.rs52
-rw-r--r--zellij-utils/src/input/layout.rs373
-rw-r--r--zellij-utils/src/input/options.rs10
-rw-r--r--zellij-utils/src/input/unit/layout_test.rs669
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_added_to_args_in_template.snap116
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_override_args_in_template.snap122
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__can_load_swap_layouts_from_a_different_file.snap536
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_pane_template.snap281
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_tab_template.snap63
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_added_to_close_on_exit_in_template.snap110
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_overrides_close_on_exit_in_template.snap110
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__combined_tab_and_pane_template_both_with_children.snap78
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_added_to_cwd_in_template.snap114
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_override_cwd_in_template.snap118
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd.snap39
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_pane_templates.snap48
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_tab_templates.snap45
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_given_to_panes_without_cwd.snap102
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor.snap102
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor_overrides_global_cwd_in_layout_file.snap102
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_prepended_to_panes_with_cwd.snap102
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_with_tab_cwd_given_to_panes_without_cwd.snap39
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_close_on_exit.snap71
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_start_suspended.snap71
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_default_tab_template.snap143
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_branched_pane_templates.snap248
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_pane_templates.snap183
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_pane_templates.snap487
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tab_and_pane_templates.snap48
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap48
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_is_overriden_by_its_consumers_bare_cwd.snap75
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_overriden_by_its_consumers_command_cwd.snap75
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_remains_when_its_consumer_command_does_not_have_a_cwd.snap75
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_is_overriden_by_its_consumers_cwd.snap75
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_receives_its_consumers_bare_cwd.snap75
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_cwd_overriden_by_its_consumers_bare_cwd.snap59
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_with_cwd.snap75
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_without_cwd.snap75
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_edit.snap61
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_command_propagated_to_its_consumer_edit.snap61
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_given_to_panes_without_cwd.snap39
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_prepended_to_panes_with_cwd.snap39
-rw-r--r--zellij-utils/src/kdl/kdl_layout_parser.rs577
-rw-r--r--zellij-utils/src/kdl/mod.rs134
-rw-r--r--zellij-utils/src/pane_size.rs44
-rw-r--r--zellij-utils/src/setup.rs39
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_config_options.snap3
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options-2.snap28
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options.snap3
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap1630
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-3.snap3
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap198
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap198
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_keybinds_override_config_keybinds.snap3
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options-2.snap28
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options.snap3
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap198
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap198
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap198
204 files changed, 16275 insertions, 2901 deletions
diff --git a/default-plugins/compact-bar/src/line.rs b/default-plugins/compact-bar/src/line.rs
index 16d64d07..6bcbab18 100644
--- a/default-plugins/compact-bar/src/line.rs
+++ b/default-plugins/compact-bar/src/line.rs
@@ -256,6 +256,8 @@ pub fn tab_line(
palette: Palette,
capabilities: PluginCapabilities,
mode: InputMode,
+ active_swap_layout_name: &Option<String>,
+ is_swap_layout_dirty: bool,
) -> Vec<LinePart> {
let mut tabs_after_active = all_tabs.split_off(active_tab_index);
let mut tabs_before_active = all_tabs;
@@ -283,5 +285,97 @@ pub fn tab_line(
capabilities,
);
prefix.append(&mut tabs_to_render);
+
+ let current_title_len = get_current_title_len(&prefix);
+ if current_title_len < cols {
+ let mut remaining_space = cols - current_title_len;
+ if let Some(swap_layout_status) = swap_layout_status(
+ remaining_space,
+ active_swap_layout_name,
+ is_swap_layout_dirty,
+ mode,
+ &palette,
+ tab_separator(capabilities),
+ ) {
+ remaining_space -= swap_layout_status.len;
+ let mut buffer = String::new();
+ for _ in 0..remaining_space {
+ buffer.push_str(&style!(palette.black, palette.black).paint(" ").to_string());
+ }
+ prefix.push(LinePart {
+ part: buffer,
+ len: remaining_space,
+ tab_index: None,
+ });
+ prefix.push(swap_layout_status);
+ }
+ }
+
prefix
}
+
+fn swap_layout_status(
+ max_len: usize,
+ swap_layout_name: &Option<String>,
+ is_swap_layout_damaged: bool,
+ input_mode: InputMode,
+ palette: &Palette,
+ separator: &str,
+) -> Option<LinePart> {
+ match swap_layout_name {
+ Some(swap_layout_name) => {
+ let mut swap_layout_name = format!(" {} ", swap_layout_name);
+ swap_layout_name.make_ascii_uppercase();
+ let swap_layout_name_len = swap_layout_name.len() + 3;
+
+ let (prefix_separator, swap_layout_name, suffix_separator) =
+ if input_mode == InputMode::Locked {
+ (
+ style!(palette.black, palette.fg).paint(separator),
+ style!(palette.black, palette.fg)
+ .italic()
+ .paint(&swap_layout_name),
+ style!(palette.fg, palette.black).paint(separator),
+ )
+ } else if is_swap_layout_damaged {
+ (
+ style!(palette.black, palette.fg).paint(separator),
+ style!(palette.black, palette.fg)
+ .bold()
+ .paint(&swap_layout_name),
+ style!(palette.fg, palette.black).paint(separator),
+ )
+ } else {
+ (
+ style!(palette.black, palette.green).paint(separator),
+ style!(palette.black, palette.green)
+ .bold()
+ .paint(&swap_layout_name),
+ style!(palette.green, palette.black).paint(separator),
+ )
+ };
+ let swap_layout_indicator = format!(
+ "{}{}{}",
+ prefix_separator, swap_layout_name, suffix_separator
+ );
+ let (part, full_len) = (format!("{}", swap_layout_indicator), swap_layout_name_len);
+ let short_len = swap_layout_name_len + 1; // 1 is the space between
+ if full_len <= max_len {
+ Some(LinePart {
+ part,
+ len: full_len,
+ tab_index: None,
+ })
+ } else if short_len <= max_len && input_mode != InputMode::Locked {
+ Some(LinePart {
+ part: swap_layout_indicator,
+ len: short_len,
+ tab_index: None,
+ })
+ } else {
+ None
+ }
+ },
+ None => None,
+ }
+}
diff --git a/default-plugins/compact-bar/src/main.rs b/default-plugins/compact-bar/src/main.rs
index c6ce9bbc..71652f0f 100644
--- a/default-plugins/compact-bar/src/main.rs
+++ b/default-plugins/compact-bar/src/main.rs
@@ -92,6 +92,8 @@ impl ZellijPlugin for State {
}
let mut all_tabs: Vec<LinePart> = vec![];
let mut active_tab_index = 0;
+ let mut active_swap_layout_name = None;
+ let mut is_swap_layout_dirty = false;
let mut is_alternate_tab = false;
for t in &mut self.tabs {
let mut tabname = t.name.clone();
@@ -102,6 +104,8 @@ impl ZellijPlugin for State {
active_tab_index = t.position;
} else if t.active {
active_tab_index = t.position;
+ is_swap_layout_dirty = t.is_swap_layout_dirty;
+ active_swap_layout_name = t.active_swap_layout_name.clone();
}
let tab = tab_style(
tabname,
@@ -121,6 +125,8 @@ impl ZellijPlugin for State {
self.mode_info.style.colors,
self.mode_info.capabilities,
self.mode_info.mode,
+ &active_swap_layout_name,
+ is_swap_layout_dirty,
);
let mut s = String::new();
let mut len_cnt = 0;
diff --git a/default-plugins/status-bar/src/first_line.rs b/default-plugins/status-bar/src/first_line.rs
index ae8fc70e..23a6d586 100644
--- a/default-plugins/status-bar/src/first_line.rs
+++ b/default-plugins/status-bar/src/first_line.rs
@@ -1,9 +1,11 @@
-use ansi_term::ANSIStrings;
+use ansi_term::{unstyled_len, ANSIStrings};
use zellij_tile::prelude::actions::Action;
use zellij_tile::prelude::*;
use crate::color_elements;
-use crate::{action_key, get_common_modifier, TO_NORMAL};
+use crate::{
+ action_key, action_key_group, get_common_modifier, style_key_with_modifier, TO_NORMAL,
+};
use crate::{ColoredElements, LinePart};
struct KeyShortcut {
@@ -232,6 +234,102 @@ fn key_indicators(
line_part
}
+fn swap_layout_keycode(mode_info: &ModeInfo, palette: &Palette) -> LinePart {
+ let mode_keybinds = mode_info.get_mode_keybinds();
+ let prev_next_keys = action_key_group(
+ &mode_keybinds,
+ &[&[Action::PreviousSwapLayout], &[Action::NextSwapLayout]],
+ );
+ let prev_next_keys_indicator =
+ style_key_with_modifier(&prev_next_keys, palette, Some(palette.black));
+ let keycode = ANSIStrings(&prev_next_keys_indicator);
+ let len = unstyled_len(&keycode);
+ let part = keycode.to_string();
+ LinePart { part, len }
+}
+
+fn swap_layout_status(
+ max_len: usize,
+ swap_layout_name: &Option<String>,
+ is_swap_layout_damaged: bool,
+ mode_info: &ModeInfo,
+ colored_elements: ColoredElements,
+ palette: &Palette,
+ separator: &str,
+) -> Option<LinePart> {
+ match swap_layout_name {
+ Some(swap_layout_name) => {
+ let mut swap_layout_name = format!(" {} ", swap_layout_name);
+ swap_layout_name.make_ascii_uppercase();
+ let keycode = swap_layout_keycode(mode_info, palette);
+ let swap_layout_name_len = swap_layout_name.len() + 3; // 2 for the arrow separators, one for the screen end buffer
+ //
+ macro_rules! style_swap_layout_indicator {
+ ($style_name:ident) => {{
+ (
+ colored_elements
+ .$style_name
+ .prefix_separator
+ .paint(separator),
+ colored_elements
+ .$style_name
+ .styled_text
+ .paint(&swap_layout_name),
+ colored_elements
+ .$style_name
+ .suffix_separator
+ .paint(separator),
+ )
+ }};
+ }
+ let (prefix_separator, swap_layout_name, suffix_separator) =
+ if mode_info.mode == InputMode::Locked {
+ style_swap_layout_indicator!(disabled)
+ } else if is_swap_layout_damaged {
+ style_swap_layout_indicator!(unselected)
+ } else {
+ style_swap_layout_indicator!(selected)
+ };
+ let swap_layout_indicator = format!(
+ "{}{}{}",
+ prefix_separator, swap_layout_name, suffix_separator
+ );
+ let (part, full_len) = if mode_info.mode == InputMode::Locked {
+ (
+ format!("{}", swap_layout_indicator),
+ swap_layout_name_len, // 1 is the space between
+ )
+ } else {
+ (
+ format!(
+ "{}{}{}{}",
+ keycode,
+ colored_elements.superkey_prefix.paint(" "),
+ swap_layout_indicator,
+ colored_elements.superkey_prefix.paint(" ")
+ ),
+ keycode.len + swap_layout_name_len + 1, // 1 is the space between
+ )
+ };
+ let short_len = swap_layout_name_len + 1; // 1 is the space between
+ if full_len <= max_len {
+ Some(LinePart {
+ part,
+ len: full_len,
+ })
+ } else if short_len <= max_len && mode_info.mode != InputMode::Locked {
+ Some(LinePart {
+ part: swap_layout_indicator,
+ len: short_len,
+ })
+ } else {
+ None
+ }
+ },
+ None => None,
+ }
+}
+
/// Get the keybindings for switching `InputMode`s and `Quit` visible in status bar.
///
/// Return a Vector of `Key`s where each `Key` is a shortcut to switch to some `InputMode` or Quit
@@ -351,7 +449,12 @@ fn get_key_shortcut_for_mode<'a>(
None
}
-pub fn first_line(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
+pub fn first_line(
+ help: &ModeInfo,
+ tab_info: Option<&TabInfo>,
+ max_len: usize,
+ separator: &str,
+) -> LinePart {
let supports_arrow_fonts = !help.capabilities.arrow_fonts;
let colored_elements = color_elements(help.style.colors, !supports_arrow_fonts);
let binds = &help.get_mode_keybinds();
@@ -432,7 +535,32 @@ pub fn first_line(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart
));
}
- key_indicators(max_len, &default_keys, colored_elements, separator, help)
+ let mut key_indicators =
+ key_indicators(max_len, &default_keys, colored_elements, separator, help);
+ if key_indicators.len < max_len {
+ if let Some(tab_info) = tab_info {
+ let mut remaining_space = max_len - key_indicators.len;
+ if let Some(swap_layout_status) = swap_layout_status(
+ remaining_space,
+ &tab_info.active_swap_layout_name,
+ tab_info.is_swap_layout_dirty,
+ help,
+ colored_elements,
+ &help.style.colors,
+ separator,
+ ) {
+ remaining_space -= swap_layout_status.len;
+ for _ in 0..remaining_space {
+ key_indicators.part.push_str(
+ &ANSIStrings(&[colored_elements.superkey_prefix.paint(" ")]).to_string(),
+ );
+ key_indicators.len += 1;
+ }
+ key_indicators.append(&swap_layout_status);
+ }
+ }
+ }
+ key_indicators
}
#[cfg(test)]
@@ -735,7 +863,7 @@ mod tests {
..ModeInfo::default()
};
- let ret = first_line(&mode_info, 500, ">");
+ let ret = first_line(&mode_info, None, 500, ">");
let ret = unstyle(ret);
assert_eq!(
@@ -759,7 +887,7 @@ mod tests {
..ModeInfo::default()
};
- let ret = first_line(&mode_info, 500, ">");
+ let ret = first_line(&mode_info, None, 500, ">");
let ret = unstyle(ret);
assert_eq!(
@@ -785,7 +913,7 @@ mod tests {
..ModeInfo::default()
};
- let ret = first_line(&mode_info, 500, ">");
+ let ret = first_line(&mode_info, None, 500, ">");
let ret = unstyle(ret);
assert_eq!(
@@ -812,7 +940,7 @@ mod tests {
..ModeInfo::default()
};
- let ret = first_line(&mode_info, 50, ">");
+ let ret = first_line(&mode_info, None, 50, ">");
let ret = unstyle(ret);
assert_eq!(ret, " Ctrl + >> a >> b >> c >> d >> e >".to_string());
@@ -833,7 +961,7 @@ mod tests {
..ModeInfo::default()
};
- let ret = first_line(&mode_info, 30, "");
+ let ret = first_line(&mode_info, None, 30, "");
let ret = unstyle(ret);
assert_eq!(ret, " Ctrl + a b c ".to_string());
diff --git a/default-plugins/status-bar/src/main.rs b/default-plugins/status-bar/src/main.rs
index 603cdf35..3e668559 100644
--- a/default-plugins/status-bar/src/main.rs
+++ b/default-plugins/status-bar/src/main.rs
@@ -44,6 +44,13 @@ pub struct LinePart {
len: usize,
}
+impl LinePart {
+ pub fn append(&mut self, to_append: &LinePart) {
+ self.part.push_str(&to_append.part);
+ self.len += to_append.len;
+ }
+}
+
impl Display for LinePart {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{}", self.part)
@@ -236,7 +243,8 @@ impl ZellijPlugin for State {
""
};
- let first_line = first_line(&self.mode_info, cols, separator);
+ let active_tab = self.tabs.iter().find(|t| t.active);
+ let first_line = first_line(&self.mode_info, active_tab, cols, separator);
let second_line = self.second_line(cols);
let background = match self.mode_info.style.colors.theme_hue {
@@ -396,7 +404,11 @@ pub fn action_key_group(keymap: &[(Key, Vec<Action>)], actions: &[&[Action]]) ->
///
/// The returned Vector of [`ANSIString`] is suitable for transformation into an [`ANSIStrings`]
/// type.
-pub fn style_key_with_modifier(keyvec: &[Key], palette: &Palette) -> Vec<ANSIString<'static>> {
+pub fn style_key_with_modifier(
+ keyvec: &[Key],
+ palette: &Palette,
+ background: Option<PaletteColor>,
+) -> Vec<ANSIString<'static>> {
// Nothing to do, quit...
if keyvec.is_empty() {
return vec![];
@@ -419,13 +431,32 @@ pub fn style_key_with_modifier(keyvec: &[Key], palette: &Palette) -> Vec<ANSIStr
let painted_modifier = if modifier_str.is_empty() {
Style::new().paint("")
} else {
- Style::new().fg(orange_color).bold().paint(modifier_str)
+ if let Some(background) = background {
+ let background = palette_match!(background);
+ Style::new()
+ .fg(orange_color)
+ .on(background)
+ .bold()
+ .paint(modifier_str)
+ } else {
+ Style::new().fg(orange_color).bold().paint(modifier_str)
+ }
};
ret.push(painted_modifier);
// Prints key group start
let group_start_str = if no_modifier { "<" } else { " + <" };
- ret.push(Style::new().fg(text_color).paint(group_start_str));
+ if let Some(background) = background {
+ let background = palette_match!(background);
+ ret.push(
+ Style::new()
+ .fg(text_color)
+ .on(background)
+ .paint(group_start_str),
+ );
+ } else {
+ ret.push(Style::new().fg(text_color).paint(group_start_str));
+ }
// Prints the keys
let key = keyvec
@@ -451,18 +482,50 @@ pub fn style_key_with_modifier(keyvec: &[Key], palette: &Palette) -> Vec<ANSIStr
"←↓↑→" => "",
"←→" => "",
"↓↑" => "",
+ "[]" => "",
_ => "|",
};
for (idx, key) in key.iter().enumerate() {
if idx > 0 && !key_separator.is_empty() {
- ret.push(Style::new().fg(text_color).paint(key_separator));
+ if let Some(background) = background {
+ let background = palette_match!(background);
+ ret.push(
+ Style::new()
+ .fg(text_color)
+ .on(background)
+ .paint(key_separator),
+ );
+ } else {
+ ret.push(Style::new().fg(text_color).paint(key_separator));
+ }
+ }
+ if let Some(background) = background {
+ let background = palette_match!(background);
+ ret.push(
+ Style::new()
+ .fg(green_color)
+ .on(background)
+ .bold()
+ .paint(key.clone()),
+ );
+ } else {
+ ret.push(Style::new().fg(green_color).bold().paint(key.clone()));
}
- ret.push(Style::new().fg(green_color).bold().paint(key.clone()));
}
let group_end_str = ">";
- ret.push(Style::new().fg(text_color).paint(group_end_str));
+ if let Some(background) = background {
+ let background = palette_match!(background);
+ ret.push(
+ Style::new()
+ .fg(text_color)
+ .on(background)
+ .paint(group_end_str),
+ );
+ } else {
+ ret.push(Style::new().fg(text_color).paint(group_end_str));
+ }
ret
}
@@ -623,7 +686,7 @@ pub mod tests {
let keyvec = vec![Key::Char('a'), Key::Char('b'), Key::Char('c')];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "<a|b|c>".to_string())
@@ -639,7 +702,7 @@ pub mod tests {
];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "<hjkl>".to_string())
@@ -656,7 +719,7 @@ pub mod tests {
];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "<h|k|j|l>".to_string())
@@ -672,7 +735,7 @@ pub mod tests {
];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "<←↓↑→>".to_string())
@@ -683,7 +746,7 @@ pub mod tests {
let keyvec = vec![Key::Char('←'), Key::Char('→')];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "<←→>".to_string())
@@ -694,7 +757,7 @@ pub mod tests {
let keyvec = vec![Key::Char('↓'), Key::Char('↑')];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "<↓↑>".to_string())
@@ -710,7 +773,7 @@ pub mod tests {
];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "Ctrl + <a|b|c|d>".to_string())
@@ -726,7 +789,7 @@ pub mod tests {
];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "Alt + <a|b|c|d>".to_string())
@@ -742,7 +805,7 @@ pub mod tests {
];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "Alt + <←↓↑→>".to_string())
@@ -757,7 +820,7 @@ pub mod tests {
];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "<Alt+a|Ctrl+b|c>".to_string())
@@ -780,7 +843,7 @@ pub mod tests {
];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(
@@ -794,7 +857,7 @@ pub mod tests {
let keyvec = vec![Key::Ctrl('\n'), Key::Ctrl(' '), Key::Ctrl('\t')];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "Ctrl + <ENTER|SPACE|TAB>".to_string())
@@ -809,7 +872,7 @@ pub mod tests {
];
let palette = get_palette();
- let ret = style_key_with_modifier(&keyvec, &palette);
+ let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret));
assert_eq!(ret, "Alt + <ENTER|SPACE|TAB>".to_string())
diff --git a/default-plugins/status-bar/src/second_line.rs b/default-plugins/status-bar/src/second_line.rs
index 9b2c23fb..b7c8a9ce 100644
--- a/default-plugins/status-bar/src/second_line.rs
+++ b/default-plugins/status-bar/src/second_line.rs
@@ -30,7 +30,7 @@ fn full_length_shortcut(
let separator = if is_first_shortcut { " " } else { " / " };
let mut bits: Vec<ANSIString> = vec![Style::new().fg(text_color).paint(separator)];
- bits.extend(style_key_with_modifier(&key, &palette));
+ bits.extend(style_key_with_modifier(&key, &palette, None));
bits.push(
Style::new()
.fg(text_color)
@@ -179,7 +179,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<Key>)> {
vec![
(s("Move focus"), s("Move"), focus_keys),
- (s("New"), s("New"), action_key(&km, &[A::NewTab(None, vec![], None), TO_NORMAL])),
+ (s("New"), s("New"), action_key(&km, &[A::NewTab(None, vec![], None, None, None), TO_NORMAL])),
(s("Close"), s("Close"), action_key(&km, &[A::CloseTab, TO_NORMAL])),
(s("Rename"), s("Rename"),
action_key(&km, &[A::SwitchToMode(IM::RenameTab), A::TabNameInput(vec![0])])),
@@ -210,6 +210,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<Key>)> {
&[Action::MovePane(Some(Dir::Left))], &[Action::MovePane(Some(Dir::Down))],
&[Action::MovePane(Some(Dir::Up))], &[Action::MovePane(Some(Dir::Right))]])),
(s("Next pane"), s("Next"), action_key(&km, &[Action::MovePane(None)])),
+ (s("Previous pane"), s("Previous"), action_key(&km, &[Action::MovePaneBackwards])),
]} else if mi.mode == IM::Scroll { vec![
(s("Scroll"), s("Scroll"),
action_key_group(&km, &[&[Action::ScrollDown], &[Action::ScrollUp]])),
@@ -253,7 +254,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<Key>)> {
(s("Split down"), s("Down"), action_key(&km, &[A::NewPane(Some(Dir::Down), None), TO_NORMAL])),
(s("Split right"), s("Right"), action_key(&km, &[A::NewPane(Some(Dir::Right), None), TO_NORMAL])),
(s("Fullscreen"), s("Fullscreen"), action_key(&km, &[A::ToggleFocusFullscreen, TO_NORMAL])),
- (s("New tab"), s("New"), action_key(&km, &[A::NewTab(None, vec![], None), TO_NORMAL])),
+ (s("New tab"), s("New"), action_key(&km, &[A::NewTab(None, vec![], None, None, None), TO_NORMAL])),
(s("Rename tab"), s("Rename"),
action_key(&km, &[A::SwitchToMode(IM::RenameTab), A::TabNameInput(vec![0])])),
(s("Previous Tab"), s("Previous"), action_key(&km, &[A::GoToPreviousTab, TO_NORMAL])),
diff --git a/default-plugins/status-bar/src/tip/data/compact_layout.rs b/default-plugins/status-bar/src/tip/data/compact_layout.rs
index dd67ab8f..77dec8a6 100644
--- a/default-plugins/status-bar/src/tip/data/compact_layout.rs
+++ b/default-plugins/status-bar/src/tip/data/compact_layout.rs
@@ -93,8 +93,12 @@ fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
}
let mut bits = vec![];
- bits.extend(style_key_with_modifier(&to_pane, &help.style.colors));
+ bits.extend(style_key_with_modifier(&to_pane, &help.style.colors, None));
bits.push(Style::new().paint(", "));
- bits.extend(style_key_with_modifier(&pane_frames, &help.style.colors));
+ bits.extend(style_key_with_modifier(
+ &pane_frames,
+ &help.style.colors,
+ None,
+ ));
bits
}
diff --git a/default-plugins/status-bar/src/tip/data/edit_scrollbuffer.rs b/default-plugins/status-bar/src/tip/data/edit_scrollbuffer.rs
index bef8acba..ebd944b7 100644
--- a/default-plugins/status-bar/src/tip/data/edit_scrollbuffer.rs
+++ b/default-plugins/status-bar/src/tip/data/edit_scrollbuffer.rs
@@ -83,8 +83,12 @@ fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
}
let mut bits = vec![];
- bits.extend(style_key_with_modifier(&to_pane, &help.style.colors));
+ bits.extend(style_key_with_modifier(&to_pane, &help.style.colors, None));
bits.push(Style::new().paint(", "));
- bits.extend(style_key_with_modifier(&edit_buffer, &help.style.colors));
+ bits.extend(style_key_with_modifier(
+ &edit_buffer,
+ &help.style.colors,
+ None,
+ ));
bits
}
diff --git a/default-plugins/status-bar/src/tip/data/floating_panes_mouse.rs b/default-plugins/status-bar/src/tip/data/floating_panes_mouse.rs
index d91c3ed8..4bf4a143 100644
--- a/default-plugins/status-bar/src/tip/data/floating_panes_mouse.rs
+++ b/default-plugins/status-bar/src/tip/data/floating_panes_mouse.rs
@@ -62,11 +62,12 @@ fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
}
let mut bits = vec![];
- bits.extend(style_key_with_modifier(&to_pane, &help.style.colors));
+ bits.extend(style_key_with_modifier(&to_pane, &help.style.colors, None));
bits.push(Style::new().paint(", "));
bits.extend(style_key_with_modifier(
&floating_toggle,
&help.style.colors,
+ None,
));
bits
}
diff --git a/default-plugins/status-bar/src/tip/data/move_focus_hjkl_tab_switch.rs b/default-plugins/status-bar/src/tip/data/move_focus_hjkl_tab_switch.rs
index 67940e49..c39ea302 100644
--- a/default-plugins/status-bar/src/tip/data/move_focus_hjkl_tab_switch.rs
+++ b/default-plugins/status-bar/src/tip/data/move_focus_hjkl_tab_switch.rs
@@ -70,8 +70,8 @@ fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
letters.push(key);
}
}
- let arrows = style_key_with_modifier(&arrows, &help.style.colors);
- let letters = style_key_with_modifier(&letters, &help.style.colors);
+ let arrows = style_key_with_modifier(&arrows, &help.style.colors, None);
+ let letters = style_key_with_modifier(&letters, &help.style.colors, None);
if arrows.is_empty() && letters.is_empty() {
vec![Style::new().bold().paint("UNBOUND")]
} else if arrows.is_empty() || letters.is_empty() {
diff --git a/default-plugins/status-bar/src/tip/data/quicknav.rs b/default-plugins/status-bar/src/tip/data/quicknav.rs
index b8077e45..318fe702 100644
--- a/default-plugins/status-bar/src/tip/data/quicknav.rs
+++ b/default-plugins/status-bar/src/tip/data/quicknav.rs
@@ -66,7 +66,7 @@ fn add_keybinds(help: &ModeInfo) -> Keygroups {
let new_pane = if new_pane_keys.is_empty() {
vec![Style::new().bold().paint("UNBOUND")]
} else {
- style_key_with_modifier(&new_pane_keys, &help.style.colors)
+ style_key_with_modifier(&new_pane_keys, &help.style.colors, None)
};
let mut resize_keys = action_key_group(
@@ -84,7 +84,7 @@ fn add_keybinds(help: &ModeInfo) -> Keygroups {
let resize = if resize_keys.is_empty() {
vec![Style::new().bold().paint("UNBOUND")]
} else {
- style_key_with_modifier(&resize_keys, &help.style.colors)
+ style_key_with_modifier(&resize_keys, &help.style.colors, None)
};
let move_focus_keys = action_key_group(
@@ -113,8 +113,8 @@ fn add_keybinds(help: &ModeInfo) -> Keygroups {
letters.push(key);
}
}
- let arrows = style_key_with_modifier(&arrows, &help.style.colors);
- let letters = style_key_with_modifier(&letters, &help.style.colors);
+ let arrows = style_key_with_modifier(&arrows, &help.style.colors, None);
+ let letters = style_key_with_modifier(&letters, &help.style.colors, None);
let move_focus = if arrows.is_empty() && letters.is_empty() {
vec![Style::new().bold().paint("UNBOUND")]
} else if arrows.is_empty() || letters.is_empty() {
diff --git a/default-plugins/status-bar/src/tip/data/sync_tab.rs b/default-plugins/status-bar/src/tip/data/sync_tab.rs
index 55331eb3..486e2aa2 100644
--- a/default-plugins/status-bar/src/tip/data/sync_tab.rs
+++ b/default-plugins/status-bar/src/tip/data/sync_tab.rs
@@ -61,8 +61,12 @@ fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
}
let mut bits = vec![];
- bits.extend(style_key_with_modifier(&to_tab, &help.style.colors));
+ bits.extend(style_key_with_modifier(&to_tab, &help.style.colors, None));
bits.push(Style::new().paint(", "));
- bits.extend(style_key_with_modifier(&sync_tabs, &help.style.colors));
+ bits.extend(style_key_with_modifier(
+ &sync_tabs,
+ &help.style.colors,
+ None,
+ ));
bits
}
diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs
index 9b007989..bafd9df7 100644
--- a/src/tests/e2e/remote_runner.rs
+++ b/src/tests/e2e/remote_runner.rs
@@ -201,6 +201,7 @@ fn read_from_channel(
Rc::new(RefCell::new(Palette::default())),
Rc::new(RefCell::new(HashMap::new())),
None,
+ None,
); // 0 is the pane index
loop {
if !should_keep_running.load(Ordering::SeqCst) {
@@ -397,6 +398,7 @@ impl RemoteRunner {
y: 0,
rows,
cols,
+ is_stacked: false,
};
setup_remote_environment(&mut channel, win_size);
start_zellij(&mut channel);
@@ -432,6 +434,7 @@ impl RemoteRunner {
y: 0,
rows,
cols,
+ is_stacked: false,
};
setup_remote_environment(&mut channel, win_size);
start_zellij_mirrored_session(&mut channel);
@@ -474,6 +477,7 @@ impl RemoteRunner {
y: 0,
rows,
cols,
+ is_stacked: false,
};
setup_remote_environment(&mut channel, win_size);
start_zellij_in_session(&mut channel, session_name, mirrored);
@@ -509,6 +513,7 @@ impl RemoteRunner {
y: 0,
rows,
cols,
+ is_stacked: false,
};
setup_remote_environment(&mut channel, win_size);
attach_to_existing_session(&mut channel, session_name);
@@ -544,6 +549,7 @@ impl RemoteRunner {
y: 0,
rows,
cols,
+ is_stacked: false,
};
setup_remote_environment(&mut channel, win_size);
start_zellij_without_frames(&mut channel);
@@ -580,6 +586,7 @@ impl RemoteRunner {
y: 0,
rows,
cols,
+ is_stacked: false,
};
setup_remote_environment(&mut channel, win_size);
start_zellij_with_config(&mut channel, &remote_path.to_string_lossy());
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap
index 2673f0fb..c42ad188 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap
@@ -25,5 +25,5 @@ expression: last_snapshot
│ ││ │
│ ││ │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap
index d373cbbb..8d06a664 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 1077
+assertion_line: 1046
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
@@ -25,5 +25,5 @@ expression: last_snapshot
│ ││ │
│ ││ │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions-2.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions-2.snap
index 54908a5c..4e5545bd 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions-2.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions-2.snap
@@ -25,5 +25,5 @@ expression: second_runner_snapshot
│ ││ │
│ ││ │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
<←→> Move focus / <n> New / <x> Close / <r> Rename / <s> Sync / <TAB> Toggle / <ENTER> Select pane
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions.snap
index d891bab4..db168c4c 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions.snap
@@ -25,5 +25,5 @@ expression: first_runner_snapshot
│ ││ │
│ ││ │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab-2.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab-2.snap
index 5bf97567..1d108f8c 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab-2.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab-2.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 1521
+assertion_line: 1490
expression: second_runner_snapshot
---
Zellij (multiple_users_in_same_pane_and_tab)  Tab #1 [ ]
@@ -25,5 +25,5 @@ expression: second_runner_snapshot
│ ││ │
│ ││ │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab.snap
index 2316cf55..70542a4a 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__multiple_users_in_different_panes_and_same_tab.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 1520
+assertion_line: 1489
expression: first_runner_snapshot
---
Zellij (multiple_users_in_same_pane_and_tab)  Tab #1 [ ]
@@ -25,5 +25,5 @@ expression: first_runner_snapshot
│ ││ │
│ ││ │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap
index c4dd1fff..0df5280a 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 744
+assertion_line: 745
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
@@ -25,5 +25,5 @@ expression: last_snapshot
│ ││ │
│ ││ │
└────────────────────────────────────────────────────┘└────────────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap
index d7bf8cd5..4a184969 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 863
+assertion_line: 867
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
@@ -25,5 +25,5 @@ expression: last_snapshot
│ ││ │
│ ││ │
└────────────────────────────────────────────────┘└────────────────────────────────────────────────┘
- Ctrl + g  p  t  n  h  s  o  q 
+ Ctrl + g  p  t  n  h  s  o  q  Alt + <[]>  BASE 
QuickNav: Alt + <n> / Alt + <←↓↑→> or Alt + <hjkl> / Alt + <+|->
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane.snap
index ff4ce544..0b789c5d 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 274
+assertion_line: 275
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
@@ -25,5 +25,5 @@ expression: last_snapshot
│ ││line20 │
│ ││li█e21 │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
- <↓↑> Scroll / <PgDn|PgUp> Scroll / <d|u> Scroll / <e> Edit / <s> Search / <ENTER> Select
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
+ <↓↑> Scroll / <PgDn|PgUp> Scroll / <d|u> Scroll / <e> Edit / <s> Search / <ENTER> Select
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap
index e5132b9f..bc1ae996 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 1152
+assertion_line: 1121
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
@@ -25,5 +25,5 @@ expression: last_snapshot
│ ││line18 │
│ ││li█e19 │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap
index 0603ac26..d797b10b 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 1998
+assertion_line: 1990
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap
index 8dc5897b..2c4f2c76 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 154
+assertion_line: 155
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
@@ -25,5 +25,5 @@ expression: last_snapshot
│ ││ │
│ ││ │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap
index 0fe416cf..7a30c617 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 1198
+assertion_line: 1167
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
@@ -25,5 +25,5 @@ $ │$ █
│
│
│
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__tmux_mode.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__tmux_mode.snap
index e812fda8..0a3b4249 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__tmux_mode.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__tmux_mode.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 1802
+assertion_line: 1734
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
@@ -25,5 +25,5 @@ expression: last_snapshot
│ ││ │
│ ││ │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap
index 81c4b4fe..01f65fb1 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 1683
+assertion_line: 1687
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
@@ -26,4 +26,4 @@ expression: last_snapshot
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
- (FLOATING PANES VISIBLE): Press Ctrl+p, <w> to hide.
+ (FLOATING PANES VISIBLE): Press Ctrl+p, <w> to hide.
diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_pane_fullscreen.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_pane_fullscreen.snap
index ad24c740..76ffb7e6 100644
--- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_pane_fullscreen.snap
+++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_pane_fullscreen.snap
@@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 334
+assertion_line: 335
expression: last_snapshot
---
Zellij (e2e-test)  Tab #1 
@@ -25,5 +25,5 @@ expression: last_snapshot
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
- Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  BASE 
(FULLSCREEN): + 1 hidden panes
diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs
index 91e11f10..f095e0c6 100644
--- a/zellij-server/src/lib.rs
+++ b/zellij-server/src/lib.rs
@@ -108,6 +108,7 @@ pub(crate) struct SessionMetaData {
pub capabilities: PluginCapabilities,
pub client_attributes: ClientAttributes,
pub default_shell: Option<TerminalAction>,
+ pub layout: Box<Layout>,
screen_thread: Option<thread::JoinHandle<()>>,
pty_thread: Option<thread::JoinHandle<()>>,
plugin_thread: Option<thread::JoinHandle<()>>,
@@ -346,7 +347,7 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
})
});
- let spawn_tabs = |tab_layout, floating_panes_layout, tab_name| {
+ let spawn_tabs = |tab_layout, floating_panes_layout, tab_name, swap_layouts| {
session_data
.read()
.unwrap()
@@ -358,6 +359,7 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
tab_layout,
floating_panes_layout,
tab_name,
+ swap_layouts,
client_id,
))
.unwrap()
@@ -369,6 +371,10 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
Some(tab_layout.clone()),
floating_panes_layout.clone(),
tab_name,
+ (
+ layout.swap_tiled_layouts.clone(),
+ layout.swap_floating_layouts.clone(),
+ ),
);
}
@@ -386,7 +392,15 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
.unwrap();
}
} else {
- spawn_tabs(None, layout.floating_panes_template.clone(), None);
+ spawn_tabs(
+ None,
+ layout.template.map(|t| t.1).clone().unwrap_or_default(),
+ None,
+ (
+ layout.swap_tiled_layouts.clone(),
+ layout.swap_floating_layouts.clone(),
+ ),
+ );
}
session_data
.read()
@@ -751,6 +765,7 @@ fn init_session(
);
let store = get_store();
+ let layout = layout.clone();
move || {
plugin_thread_main(
plugin_bus,
@@ -811,6 +826,7 @@ fn init_session(
capabilities,
default_shell,
client_attributes,
+ layout,
screen_thread: Some(screen_thread),
pty_thread: Some(pty_thread),
plugin_thread: Some(plugin_thread),
diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs
index 8e863af4..abcf24c8 100644
--- a/zellij-server/src/os_input_output.rs
+++ b/zellij-server/src/os_input_output.rs
@@ -396,10 +396,11 @@ pub struct ServerOsInputOutput {
orig_termios: Arc<Mutex<termios::Termios>>,
client_senders: Arc<Mutex<HashMap<ClientId, ClientSender>>>,
terminal_id_to_raw_fd: Arc<Mutex<BTreeMap<u32, Option<RawFd>>>>, // A value of None means the
- // terminal_id exists but is
- // not connected to an fd (eg.
- // a command pane with a
- // non-existing command)
+ // terminal_id exists but is
+ // not connected to an fd (eg.
+ // a command pane with a
+ // non-existing command)
+ cached_resizes: Arc<Mutex<Option<BTreeMap<u32, (u16, u16)>>>>, // <terminal_id, (cols, rows)>
}
// async fn in traits is not supported by rust, so dtolnay's excellent async_trait macro is being
@@ -481,6 +482,8 @@ pub trait ServerOsApi: Send + Sync {
quit_cb: Box<dyn Fn(PaneId, Option<i32>, RunCommand) + Send>, // u32 is the exit status
) -> Result<(RawFd, RawFd)>;
fn clear_terminal_id(&self, terminal_id: u32) -> Result<()>;
+ fn cache_resizes(&mut self) {}
+ fn apply_cached_resizes(&mut self) {}
}
impl ServerOsApi for ServerOsInputOutput {
@@ -491,6 +494,10 @@ impl ServerOsApi for ServerOsInputOutput {
id, rows, cols
)
};
+ if let Some(cached_resizes) = self.cached_resizes.lock().unwrap().as_mut() {
+ cached_resizes.insert(id, (cols, rows));
+ return Ok(());
+ }
match self
.terminal_id_to_raw_fd
@@ -752,6 +759,19 @@ impl ServerOsApi for ServerOsInputOutput {
.remove(&terminal_id);
Ok(())
}
+ fn cache_resizes(&mut self) {
+ if self.cached_resizes.lock().unwrap().is_none() {
+ *self.cached_resizes.lock().unwrap() = Some(BTreeMap::new());
+ }
+ }
+ fn apply_cached_resizes(&mut self) {
+ let mut cached_resizes = self.cached_resizes.lock().unwrap().take();
+ if let Some(cached_resizes) = cached_resizes.as_mut() {
+ for (terminal_id, (cols, rows)) in cached_resizes.iter() {
+ let _ = self.set_terminal_size_using_terminal_id(*terminal_id, *cols, *rows);
+ }
+ }
+ }
}
impl Clone for Box<dyn ServerOsApi> {
@@ -767,6 +787,7 @@ pub fn get_server_os_input() -> Result<ServerOsInputOutput, nix::Error> {
orig_termios,
client_senders: Arc::new(Mutex::new(HashMap::new())),
terminal_id_to_raw_fd: Arc::new(Mutex::new(BTreeMap::new())),
+ cached_resizes: Arc::new(Mutex::new(None)),
})
}
diff --git a/zellij-server/src/panes/active_panes.rs b/zellij-server/src/panes/active_panes.rs
index 3fce0a9f..c726bafe 100644
--- a/zellij-server/src/panes/active_panes.rs
+++ b/zellij-server/src/panes/active_panes.rs
@@ -3,6 +3,7 @@ use crate::tab::Pane;
use crate::{os_input_output::ServerOsApi, panes::PaneId, ClientId};
use std::collections::{BTreeMap, HashMap};
+#[derive(Clone)]
pub struct ActivePanes {
active_panes: HashMap<ClientId, PaneId>,
os_api: Box<dyn ServerOsApi>,
diff --git a/zellij-server/src/panes/floating_panes/floating_pane_grid.rs b/zellij-server/src/panes/floating_panes/floating_pane_grid.rs
index 2245ee16..afeecc8d 100644
--- a/zellij-server/src/panes/floating_panes/floating_pane_grid.rs
+++ b/zellij-server/src/panes/floating_panes/floating_pane_grid.rs
@@ -703,6 +703,56 @@ impl<'a> FloatingPaneGrid<'a> {
.copied();
next_index
}
+ pub fn next_selectable_pane_id(&self, current_pane_id: &PaneId) -> Option<PaneId> {
+ let panes = self.panes.borrow();
+ let mut panes: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes
+ .iter()
+ .filter(|(_, p)| p.selectable())
+ .map(|(p_id, p)| (*p_id, p))
+ .collect();
+ panes.sort_by(|(_a_id, a_pane), (_b_id, b_pane)| {
+ if a_pane.y() == b_pane.y() {
+ a_pane.x().cmp(&b_pane.x())
+ } else {
+ a_pane.y().cmp(&b_pane.y())
+ }
+ });
+ let active_pane_position = panes
+ .iter()
+ .position(|(id, _)| id == current_pane_id)
+ .unwrap();
+
+ let next_active_pane_id = panes
+ .get(active_pane_position + 1)
+ .or_else(|| panes.get(0))
+ .map(|p| p.0)
+ .unwrap();
+ Some(next_active_pane_id)
+ }
+ pub fn previous_selectable_pane_id(&self, current_pane_id: &PaneId) -> Option<PaneId> {
+ let panes = self.panes.borrow();
+ let mut panes: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes
+ .iter()
+ .filter(|(_, p)| p.selectable())
+ .map(|(p_id, p)| (*p_id, p))
+ .collect();
+ panes.sort_by(|(_a_id, a_pane), (_b_id, b_pane)| {
+ if a_pane.y() == b_pane.y() {
+ a_pane.x().cmp(&b_pane.x())
+ } else {
+ a_pane.y().cmp(&b_pane.y())
+ }
+ });
+ let active_pane_position = panes.iter().position(|(id, _)| id == current_pane_id)?;
+
+ let last_pane = panes.last()?;
+ let previous_active_pane_id = if active_pane_position == 0 {
+ last_pane.0
+ } else {
+ panes.get(active_pane_position - 1)?.0
+ };
+ Some(previous_active_pane_id)
+ }
pub fn find_room_for_new_pane(&self) -> Option<PaneGeom> {
let panes = self.panes.borrow();
let pane_geoms: Vec<PaneGeom> = panes.values().map(|p| p.position_and_size()).collect();
@@ -766,6 +816,7 @@ fn half_size_middle_geom(space: &Viewport, offset: usize) -> PaneGeom {
y: space.y + (space.rows as f64 / 4.0).round() as usize + offset,
cols: Dimension::fixed(space.cols / 2),
rows: Dimension::fixed(space.rows / 2),
+ is_stacked: false,
};
geom.cols.set_inner(space.cols / 2);
geom.rows.set_inner(space.rows / 2);
@@ -778,6 +829,7 @@ fn half_size_top_left_geom(space: &Viewport, offset: usize) -> PaneGeom {
y: space.y + 2 + offset,
cols: Dimension::fixed(space.cols / 3),
rows: Dimension::fixed(space.rows / 3),
+ is_stacked: false,
};
geom.cols.set_inner(space.cols / 3);
geom.rows.set_inner(space.rows / 3);
@@ -790,6 +842,7 @@ fn half_size_top_right_geom(space: &Viewport, offset: usize) -> PaneGeom {
y: space.y + 2 + offset,
cols: Dimension::fixed(space.cols / 3),
rows: Dimension::fixed(space.rows / 3),
+ is_stacked: false,
};
geom.cols.set_inner(space.cols / 3);
geom.rows.set_inner(space.rows / 3);
@@ -802,6 +855,7 @@ fn half_size_bottom_left_geom(space: &Viewport, offset: usize) -> PaneGeom {
y: ((space.y + space.rows) - (space.rows / 3) - 2).saturating_sub(offset),
cols: Dimension::fixed(space.cols / 3),
rows: Dimension::fixed(space.rows / 3),
+ is_stacked: false,
};
geom.cols.set_inner(space.cols / 3);
geom.rows.set_inner(space.rows / 3);
@@ -814,6 +868,7 @@ fn half_size_bottom_right_geom(space: &Viewport, offset: usize) -> PaneGeom {
y: ((space.y + space.rows) - (space.rows / 3) - 2).saturating_sub(offset),
cols: Dimension::fixed(space.cols / 3),
rows: Dimension::fixed(space.rows / 3),
+ is_stacked: false,
};
geom.cols.set_inner(space.cols / 3);
geom.rows.set_inner(space.rows / 3);
diff --git a/zellij-server/src/panes/floating_panes/mod.rs b/zellij-server/src/panes/floating_panes/mod.rs
index 47b3e2f2..399d16c9 100644
--- a/zellij-server/src/panes/floating_panes/mod.rs
+++ b/zellij-server/src/panes/floating_panes/mod.rs
@@ -25,7 +25,7 @@ use zellij_utils::{
data::{ModeInfo, Style},
errors::prelude::*,
input::command::RunCommand,
- input::layout::FloatingPanesLayout,
+ input::layout::FloatingPaneLayout,
pane_size::{Dimension, Offset, PaneGeom, Size, Viewport},
};
@@ -200,6 +200,14 @@ impl FloatingPanes {
pub fn active_pane_id(&self, client_id: ClientId) -> Option<PaneId> {
self.active_panes.get(&client_id).copied()
}
+ pub fn active_pane_id_or_focused_pane_id(&self, client_id: Option<ClientId>) -> Option<PaneId> {
+ // returns the focused pane of any client_id - should be safe because the way things are
+ // set up at the time of writing, all clients are focused on the same floating pane due to
+ // z_index issues
+ client_id
+ .and_then(|client_id| self.active_panes.get(&client_id).copied())
+ .or_else(|| self.panes.keys().next().copied())
+ }
pub fn toggle_show_panes(&mut self, should_show_floating_panes: bool) {
self.show_panes = should_show_floating_panes;
if should_show_floating_panes {
@@ -227,7 +235,7 @@ impl FloatingPanes {
}
pub fn position_floating_pane_layout(
&mut self,
- floating_pane_layout: &FloatingPanesLayout,
+ floating_pane_layout: &FloatingPaneLayout,
) -> PaneGeom {
let display_area = *self.display_area.borrow();
let viewport = *self.viewport.borrow();
@@ -239,32 +247,32 @@ impl FloatingPanes {
);
let mut position = floating_pane_grid.find_room_for_new_pane().unwrap(); // TODO: no unwrap
if let Some(x) = &floating_pane_layout.x {
- position.x = x.to_position(display_area.cols);
+ position.x = x.to_position(viewport.cols);
}
if let Some(y) = &floating_pane_layout.y {
- position.y = y.to_position(display_area.rows);
+ position.y = y.to_position(viewport.rows);
}
if let Some(width) = &floating_pane_layout.width {
- position.cols = Dimension::fixed(width.to_position(display_area.cols));
+ position.cols = Dimension::fixed(width.to_position(viewport.cols));
}
if let Some(height) = &floating_pane_layout.height {
- position.rows = Dimension::fixed(height.to_position(display_area.rows));
+ position.rows = Dimension::fixed(height.to_position(viewport.rows));
}
- if position.cols.as_usize() > display_area.cols {
- position.cols = Dimension::fixed(display_area.cols);
+ if position.cols.as_usize() > viewport.cols {
+ position.cols = Dimension::fixed(viewport.cols);
}
- if position.rows.as_usize() > display_area.rows {
- position.rows = Dimension::fixed(display_area.rows);
+ if position.rows.as_usize() > viewport.rows {
+ position.rows = Dimension::fixed(viewport.rows);
}
- if position.x + position.cols.as_usize() > display_area.cols {
+ if position.x + position.cols.as_usize() > viewport.cols {
position.x = position
.x
- .saturating_sub((position.x + position.cols.as_usize()) - display_area.cols);
+ .saturating_sub((position.x + position.cols.as_usize()) - viewport.cols);
}
- if position.y + position.rows.as_usize() > display_area.rows {
+ if position.y + position.rows.as_usize() > viewport.rows {
position.y = position
.y
- .saturating_sub((position.y + position.rows.as_usize()) - display_area.rows);
+ .saturating_sub((position.y + position.rows.as_usize()) - viewport.rows);
}
position
}
@@ -333,6 +341,9 @@ impl FloatingPanes {
&active_panes,
multiple_users_exist_in_session,
Some(z_index + 1), // +1 because 0 is reserved for non-floating panes
+ false,
+ false,
+ true,
);
for client_id in &connected_clients {
let client_mode = self
@@ -570,6 +581,50 @@ impl FloatingPanes {
self.set_force_render();
}
}
+ pub fn move_active_pane(
+ &mut self,
+ search_backwards: bool,
+ os_api: &mut Box<dyn ServerOsApi>,
+ client_id: ClientId,
+ ) {
+ let active_pane_id = self.get_active_pane_id(client_id).unwrap();
+
+ let new_position_id = {
+ let pane_grid = FloatingPaneGrid::new(
+ &mut self.panes,
+ &mut self.desired_pane_positions,
+ *self.display_area.borrow(),
+ *self.viewport.borrow(),
+ );
+ if search_backwards {
+ pane_grid.previous_selectable_pane_id(&active_pane_id)
+ } else {
+ pane_grid.next_selectable_pane_id(&active_pane_id)
+ }
+ };
+ if let Some(new_position_id) = new_position_id {
+ let current_position = self.panes.get(&active_pane_id).unwrap();
+ let prev_geom = current_position.position_and_size();
+ let prev_geom_override = current_position.geom_override();
+
+ let new_position = self.panes.get_mut(&new_position_id).unwrap();
+ let next_geom = new_position.position_and_size();
+ let next_geom_override = new_position.geom_override();
+ new_position.set_geom(prev_geom);
+ if let Some(geom) = prev_geom_override {
+ new_position.set_geom_override(geom);
+ }
+ new_position.set_should_render(true);
+
+ let current_position = self.panes.get_mut(&active_pane_id).unwrap();
+ current_position.set_geom(next_geom);
+ if let Some(geom) = next_geom_override {
+ current_position.set_geom_override(geom);
+ }
+ current_position.set_should_render(true);
+ let _ = self.set_pane_frames(os_api);
+ }
+ }
pub fn move_clients_out_of_pane(&mut self, pane_id: PaneId) {
let active_panes: Vec<(ClientId, PaneId)> = self
.active_panes
@@ -735,6 +790,17 @@ impl FloatingPanes {
pub fn get_panes(&self) -> impl Iterator<Item = (&PaneId, &Box<dyn Pane>)> {
self.panes.iter()
}
+ pub fn visible_panes_count(&self) -> usize {
+ self.panes.len()
+ }
+ pub fn drain(&mut self) -> BTreeMap<PaneId, Box<dyn Pane>> {
+ self.z_indices.clear();
+ self.desired_pane_positions.clear();
+ match self.panes.iter().next().map(|(pid, _p)| *pid) {
+ Some(first_pid) => self.panes.split_off(&first_pid),
+ None => BTreeMap::new(),
+ }
+ }
fn move_clients_between_panes(&mut self, from_pane_id: PaneId, to_pane_id: PaneId) {
let clients_in_pane: Vec<ClientId> = self
.active_panes
@@ -748,4 +814,36 @@ impl FloatingPanes {
.insert(client_id, to_pane_id, &mut self.panes);
}
}
+ pub fn reapply_pane_focus(&mut self) {
+ if let Some(focused_pane) = self.first_active_floating_pane_id() {
+ // floating pane focus is the same for all clients
+ self.focus_pane_for_all_clients(focused_pane);
+ }
+ }
+ pub fn switch_active_pane_with(&mut self, os_api: &mut Box<dyn ServerOsApi>, pane_id: PaneId) {
+ if let Some(active_pane_id) = self.first_active_floating_pane_id() {
+ let current_position = self.panes.get(&active_pane_id).unwrap();
+ let prev_geom = current_position.position_and_size();
+ let prev_geom_override = current_position.geom_override();
+
+ let new_position = self.panes.get_mut(&pane_id).unwrap();
+ let next_geom = new_position.position_and_size();
+ let next_geom_override = new_position.geom_override();
+ new_position.set_geom(prev_geom);
+ if let Some(geom) = prev_geom_override {
+ new_position.set_geom_override(geom);
+ }
+ resize_pty!(new_position, os_api, self.senders).unwrap();
+ new_position.set_should_render(true);
+
+ let current_position = self.panes.get_mut(&active_pane_id).unwrap();
+ current_position.set_geom(next_geom);
+ if let Some(geom) = next_geom_override {
+ current_position.set_geom_override(geom);
+ }
+ resize_pty!(current_position, os_api, self.senders).unwrap();
+ current_position.set_should_render(true);
+ self.focus_pane_for_all_clients(active_pane_id);
+ }
+ }
}
diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs
index babb66b6..c6896f90 100644
--- a/zellij-server/src/panes/plugin_pane.rs
+++ b/zellij-server/src/panes/plugin_pane.rs
@@ -16,6 +16,7 @@ use zellij_utils::{
channels::SenderWithContext,
data::{Event, InputMode, Mouse, Palette, PaletteColor, Style},
errors::prelude::*,
+ input::layout::Run,
pane_size::PaneGeom,
shared::make_terminal_title,
vte,
@@ -65,6 +66,7 @@ pub(crate) struct PluginPane {
frame: HashMap<ClientId, PaneFrame>,
borderless: bool,
pane_frame_color_override: Option<(PaletteColor, Option<String>)>,
+ invoked_with: Option<Run>,
}
impl PluginPane {
@@ -80,6 +82,7 @@ impl PluginPane {
link_handler: Rc<RefCell<LinkHandler>>,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
style: Style,
+ invoked_with: Option<Run>,
) -> Self {
Self {
pid,
@@ -104,6 +107,7 @@ impl PluginPane {
grids: HashMap::new(),
style,
pane_frame_color_override: None,
+ invoked_with,
}
}
}
@@ -222,6 +226,11 @@ impl Pane for PluginPane {
if self.should_render.get(&client_id).copied().unwrap_or(false) {
let content_x = self.get_content_x();
let content_y = self.get_content_y();
+ let rows = self.get_content_rows();
+ let columns = self.get_content_columns();
+ if rows < 1 || columns < 1 {
+ return Ok(None);
+ }
if let Some(grid) = self.grids.get_mut(&client_id) {
match grid.render(content_x, content_y, &self.style) {
Ok(rendered_assets) => {
@@ -265,8 +274,15 @@ impl Pane for PluginPane {
self.pane_name.clone()
};
+ let mut frame_geom = self.current_geom();
+ if !frame_params.should_draw_pane_frames {
+ // in this case the width of the frame needs not include the pane corners
+ frame_geom
+ .cols
+ .set_inner(frame_geom.cols.as_usize().saturating_sub(1));
+ }
let mut frame = PaneFrame::new(
- self.current_geom().into(),
+ frame_geom.into(),
grid.scrollback_position_and_length(),
pane_title,
frame_params,
@@ -491,6 +507,12 @@ impl Pane for PluginPane {
.as_ref()
.map(|(color, _text)| *color)
}
+ fn invoked_with(&self) -> &Option<Run> {
+ &self.invoked_with
+ }
+ fn set_title(&mut self, title: String) {
+ self.pane_title = title;
+ }
}
impl PluginPane {
diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs
index d206245a..e9fffb18 100644
--- a/zellij-server/src/panes/terminal_pane.rs
+++ b/zellij-server/src/panes/terminal_pane.rs
@@ -18,6 +18,7 @@ use zellij_utils::pane_size::Offset;
use zellij_utils::{
data::{InputMode, Palette, PaletteColor, Style},
errors::prelude::*,
+ input::layout::Run,
pane_size::PaneGeom,
pane_size::SizeInPixels,
position::Position,
@@ -111,6 +112,7 @@ pub struct TerminalPane {
banner: Option<String>, // a banner to be rendered inside this TerminalPane, used for panes
// held on startup and can possibly be used to display some errors
pane_frame_color_override: Option<(PaletteColor, Option<String>)>,
+ invoked_with: Option<Run>,
}
impl Pane for TerminalPane {
@@ -165,6 +167,10 @@ impl Pane for TerminalPane {
}
fn cursor_coordinates(&self) -> Option<(usize, usize)> {
// (x, y)
+ if self.get_content_rows() < 1 || self.get_content_columns() < 1 {
+ // do not render cursor if there's no room for it
+ return None;
+ }
let Offset { top, left, .. } = self.content_offset;
self.grid
.cursor_coordinates()
@@ -283,6 +289,11 @@ impl Pane for TerminalPane {
if self.should_render() {
let content_x = self.get_content_x();
let content_y = self.get_content_y();
+ let rows = self.get_content_rows();
+ let columns = self.get_content_columns();
+ if rows < 1 || columns < 1 {
+ return Ok(None);
+ }
match self.grid.render(content_x, content_y, &self.style) {
Ok(rendered_assets) => {
self.set_should_render(false);
@@ -347,8 +358,15 @@ impl Pane for TerminalPane {
self.pane_name.clone()
};
+ let mut frame_geom = self.current_geom();
+ if !frame_params.should_draw_pane_frames {
+ // in this case the width of the frame needs not include the pane corners
+ frame_geom
+ .cols
+ .set_inner(frame_geom.cols.as_usize().saturating_sub(1));
+ }
let mut frame = PaneFrame::new(
- self.current_geom().into(),
+ frame_geom.into(),
self.grid.scrollback_position_and_length(),
pane_title,
frame_params,
@@ -690,6 +708,12 @@ impl Pane for TerminalPane {
.as_ref()
.map(|(color, _text)| *color)
}
+ fn invoked_with(&self) -> &Option<Run> {
+ &self.invoked_with
+ }
+ fn set_title(&mut self, title: String) {
+ self.pane_title = title;
+ }
}
impl TerminalPane {
@@ -706,6 +730,7 @@ impl TerminalPane {
terminal_emulator_colors: Rc<RefCell<Palette>>,
terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
initial_pane_title: Option<String>,
+ invoked_with: Option<Run>,
) -> TerminalPane {
let initial_pane_title =
initial_pane_title.unwrap_or_else(|| format!("Pane #{}", pane_index));
@@ -739,6 +764,7 @@ impl TerminalPane {
is_held: None,
banner: None,
pane_frame_color_override: None,
+ invoked_with,
}
}
pub fn get_x(&self) -> usize {
@@ -780,6 +806,10 @@ impl TerminalPane {
}
pub fn cursor_coordinates(&self) -> Option<(usize, usize)> {
// (x, y)
+ if self.get_content_rows() < 1 || self.get_content_columns() < 1 {
+ // do not render cursor if there's no room for it
+ return None;
+ }
self.grid.cursor_coordinates()
}
fn render_first_run_banner(&mut self) {
diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs
index cad53e3f..bd6470c9 100644
--- a/zellij-server/src/panes/tiled_panes/mod.rs
+++ b/zellij-server/src/panes/tiled_panes/mod.rs
@@ -1,4 +1,5 @@
mod pane_resizer;
+mod stacked_panes;
mod tiled_pane_grid;
use crate::resize_pty;
@@ -15,6 +16,7 @@ use crate::{
ui::pane_contents_and_ui::PaneContentsAndUi,
ClientId,
};
+use stacked_panes::StackedPanes;
use zellij_utils::{
data::{ModeInfo, ResizeStrategy, Style},
errors::prelude::*,
@@ -249,6 +251,10 @@ impl TiledPanes {
self.set_pane_frames(self.draw_pane_frames);
}
+ pub fn reapply_pane_frames(&mut self) {
+ // same as set_pane_frames except it reapplies the current situation
+ self.set_pane_frames(self.draw_pane_frames);
+ }
pub fn set_pane_frames(&mut self, draw_pane_frames: bool) {
self.draw_pane_frames = draw_pane_frames;
let viewport = *self.viewport.borrow();
@@ -276,7 +282,12 @@ impl TiledPanes {
let position_and_size = pane.current_geom();
let (pane_columns_offset, pane_rows_offset) =
pane_content_offset(&position_and_size, &viewport);
- pane.set_content_offset(Offset::shift(pane_rows_offset, pane_columns_offset));
+ if !draw_pane_frames && pane.current_geom().is_stacked {
+ // stacked panes should always leave 1 top row for a title
+ pane.set_content_offset(Offset::shift_right_and_top(pane_columns_offset, 1));
+ } else {
+ pane.set_content_offset(Offset::shift(pane_rows_offset, pane_columns_offset));
+ }
}
resize_pty!(pane, self.os_api, self.senders).unwrap();
@@ -287,7 +298,9 @@ impl TiledPanes {
if let Some(active_pane_id) = &self.active_panes.get(&client_id) {
if let Some(active_pane) = self.panes.get_mut(active_pane_id) {
let full_pane_size = active_pane.position_and_size();
- if full_pane_size.rows.as_usize() < MIN_TERMINAL_HEIGHT * 2 {
+ if full_pane_size.rows.as_usize() < MIN_TERMINAL_HEIGHT * 2
+ || full_pane_size.is_stacked
+ {
return false;
} else {
return split(SplitDirection::Horizontal, &full_pane_size).is_some();
@@ -300,7 +313,9 @@ impl TiledPanes {
if let Some(active_pane_id) = &self.active_panes.get(&client_id) {
if let Some(active_pane) = self.panes.get_mut(active_pane_id) {
let full_pane_size = active_pane.position_and_size();
- if full_pane_size.cols.as_usize() < MIN_TERMINAL_WIDTH * 2 {
+ if full_pane_size.cols.as_usize() < MIN_TERMINAL_WIDTH * 2
+ || full_pane_size.is_stacked
+ {
return false;
}
return split(SplitDirection::Vertical, &full_pane_size).is_some();
@@ -312,7 +327,7 @@ impl TiledPanes {
let active_pane_id = &self.active_panes.get(&client_id).unwrap();
let active_pane = self.panes.get(active_pane_id).unwrap();
let full_pane_size = active_pane.position_and_size();
- if full_pane_size.rows.is_fixed() {
+ if full_pane_size.rows.is_fixed() || full_pane_size.is_stacked {
return false;
}
if split(SplitDirection::Horizontal, &full_pane_size).is_some() {
@@ -343,7 +358,7 @@ impl TiledPanes {
let active_pane_id = &self.active_panes.get(&client_id).unwrap();
let active_pane = self.panes.get(active_pane_id).unwrap();
let full_pane_size = active_pane.position_and_size();
- if full_pane_size.cols.is_fixed() {
+ if full_pane_size.cols.is_fixed() || full_pane_size.is_stacked {
return false;
}
if split(SplitDirection::Vertical, &full_pane_size).is_some() {
@@ -370,7 +385,83 @@ impl TiledPanes {
self.relayout(SplitDirection::Horizontal);
}
}
+ pub fn focus_pane_for_all_clients(&mut self, pane_id: PaneId) {
+ let connected_clients: Vec<ClientId> =
+ self.connected_clients.borrow().iter().copied().collect();
+ for client_id in connected_clients {
+ if self
+ .panes
+ .get(&pane_id)
+ .map(|p| p.current_geom().is_stacked)
+ .unwrap_or(false)
+ {
+ let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
+ .focus_pane(&pane_id);
+ }
+ self.active_panes
+ .insert(client_id, pane_id, &mut self.panes);
+ self.set_pane_active_at(pane_id);
+ }
+ self.set_force_render();
+ self.reapply_pane_frames();
+ }
+ pub fn reapply_pane_focus(&mut self) {
+ let connected_clients: Vec<ClientId> =
+ self.connected_clients.borrow().iter().copied().collect();
+ for client_id in connected_clients {
+ match &self.active_panes.get(&client_id).copied() {
+ Some(pane_id) => {
+ if self
+ .panes
+ .get(&pane_id)
+ .map(|p| p.current_geom().is_stacked)
+ .unwrap_or(false)
+ {
+ let _ =
+ StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
+ .focus_pane(&pane_id);
+ }
+ self.active_panes
+ .insert(client_id, *pane_id, &mut self.panes);
+ self.set_pane_active_at(*pane_id);
+ },
+ None => {
+ if let Some(first_pane_id) = self.first_selectable_pane_id() {
+ let pane_id = first_pane_id; // TODO: combine with above
+ if self
+ .panes
+ .get(&pane_id)
+ .map(|p| p.current_geom().is_stacked)
+ .unwrap_or(false)
+ {
+ let _ = StackedPanes::new_from_btreemap(
+ &mut self.panes,
+ &self.panes_to_hide,
+ )
+ .focus_pane(&pane_id);
+ }
+ self.active_panes
+ .insert(client_id, pane_id, &mut self.panes);
+ self.set_pane_active_at(pane_id);
+ }
+ },
+ }
+ }
+ self.set_force_render();
+ self.reapply_pane_frames();
+ }
pub fn focus_pane(&mut self, pane_id: PaneId, client_id: ClientId) {
+ if self
+ .panes
+ .get(&pane_id)
+ .map(|p| p.current_geom().is_stacked)
+ .unwrap_or(false)
+ {
+ let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
+ .focus_pane(&pane_id);
+ self.reapply_pane_frames();
+ }
+
self.active_panes
.insert(client_id, pane_id, &mut self.panes);
if self.session_is_mirrored {
@@ -384,6 +475,34 @@ impl TiledPanes {
}
self.reset_boundaries();
}
+ pub fn focus_pane_at_position(&mut self, position_and_size: PaneGeom, client_id: ClientId) {
+ if let Some(pane_id) = self
+ .panes
+ .iter()
+ .find(|(_pid, pane)| pane.position_and_size() == position_and_size)
+ .map(|(pid, _p)| *pid)
+ {
+ if let Some(currently_active_pane_id) = self.active_panes.get(&client_id) {
+ let prev_geom = {
+ if let Some(currently_focused_pane) =
+ self.panes.get_mut(currently_active_pane_id)
+ {
+ let prev_geom = currently_focused_pane.position_and_size();
+ currently_focused_pane.set_geom(position_and_size);
+ Some(prev_geom)
+ } else {
+ None
+ }
+ };
+ if let Some(prev_geom) = prev_geom {
+ if let Some(previous_pane) = self.panes.get_mut(&pane_id) {
+ previous_pane.set_geom(prev_geom);
+ self.reset_boundaries();
+ }
+ }
+ }
+ }
+ }
pub fn focus_pane_if_client_not_focused(&mut self, pane_id: PaneId, client_id: ClientId) {
if self.active_panes.get(&client_id).is_none() {
self.focus_pane(pane_id, client_id)
@@ -448,8 +567,20 @@ impl TiledPanes {
.map(|(client_id, pane_id)| (*client_id, *pane_id))
.collect()
};
+ let (stacked_pane_ids_under_flexible_pane, stacked_pane_ids_over_flexible_pane) = {
+ // TODO: do not recalculate this every time on render
+ StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
+ .stacked_pane_ids_under_and_over_flexible_panes()
+ .unwrap() // TODO: no unwrap
+ };
for (kind, pane) in self.panes.iter_mut() {
if !self.panes_to_hide.contains(&pane.pid()) {
+ let pane_is_stacked_under =
+ stacked_pane_ids_under_flexible_pane.contains(&pane.pid());
+ let pane_is_stacked_over =
+ stacked_pane_ids_over_flexible_pane.contains(&pane.pid());
+ let should_draw_pane_frames = self.draw_pane_frames;
+ let pane_is_stacked = pane.current_geom().is_stacked;
let mut pane_contents_and_ui = PaneContentsAndUi::new(
pane,
output,
@@ -457,6 +588,9 @@ impl TiledPanes {
&active_panes,
multiple_users_exist_in_session,
None,
+ pane_is_stacked_under,
+ pane_is_stacked_over,
+ should_draw_pane_frames,
);
for client_id in &connected_clients {
let client_mode = self
@@ -476,6 +610,22 @@ impl TiledPanes {
pane_contents_and_ui
.render_pane_frame(*client_id, client_mode, self.session_is_mirrored)
.with_context(err_context)?;
+ } else if pane_is_stacked {
+ // if we have no pane frames but the pane is stacked, we need to render its
+ // frame which will amount to only rendering the title line
+ pane_contents_and_ui
+ .render_pane_frame(*client_id, client_mode, self.session_is_mirrored)
+ .with_context(err_context)?;
+ // we also need to render its boundaries as normal
+ let boundaries = client_id_to_boundaries
+ .entry(*client_id)
+ .or_insert_with(|| Boundaries::new(*self.viewport.borrow()));
+ pane_contents_and_ui.render_pane_boundaries(
+ *client_id,
+ client_mode,
+ boundaries,
+ self.session_is_mirrored,
+ );
} else {
let boundaries = client_id_to_boundaries
.entry(*client_id)
@@ -542,6 +692,8 @@ impl TiledPanes {
Err(e) => match e.downcast_ref::<ZellijError>() {
Some(ZellijError::PaneSizeUnchanged) => {}, // ignore unchanged layout
_ => {
+ // display area still changed, even if we had an error
+ display_area.cols = cols;
Err::<(), _>(anyError::msg(e))
.context("failed to resize tab horizontally")
.non_fatal();
@@ -557,6 +709,8 @@ impl TiledPanes {
Err(e) => match e.downcast_ref::<ZellijError>() {
Some(ZellijError::PaneSizeUnchanged) => {}, // ignore unchanged layout
_ => {
+ // display area still changed, even if we had an error
+ display_area.rows = rows;
Err::<(), _>(anyError::msg(e))
.context("failed to resize tab vertically")
.non_fatal();
@@ -629,13 +783,26 @@ impl TiledPanes {
let connected_clients: Vec<ClientId> =
{ self.connected_clients.borrow().iter().copied().collect() };
let active_pane_id = self.get_active_pane_id(client_id).unwrap();
- let pane_grid = TiledPaneGrid::new(
- &mut self.panes,
- &self.panes_to_hide,
- *self.display_area.borrow(),
- *self.viewport.borrow(),
- );
- let next_active_pane_id = pane_grid.next_selectable_pane_id(&active_pane_id);
+ let next_active_pane_id = {
+ let pane_grid = TiledPaneGrid::new(
+ &mut self.panes,
+ &self.panes_to_hide,
+ *self.display_area.borrow(),
+ *self.viewport.borrow(),
+ );
+ pane_grid.next_selectable_pane_id(&active_pane_id)
+ };
+ if self
+ .panes
+ .get(&next_active_pane_id)
+ .map(|p| p.current_geom().is_stacked)
+ .unwrap_or(false)
+ {
+ let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
+ .focus_pane(&next_active_pane_id);
+ self.reapply_pane_frames();
+ }
+
for client_id in connected_clients {
self.active_panes
.insert(client_id, next_active_pane_id, &mut self.panes);
@@ -647,13 +814,26 @@ impl TiledPanes {
let connected_clients: Vec<ClientId> =
{ self.connected_clients.borrow().iter().copied().collect() };
let active_pane_id = self.get_active_pane_id(client_id).unwrap();
- let pane_grid = TiledPaneGrid::new(
- &mut self.panes,
- &self.panes_to_hide,
- *self.display_area.borrow(),
- *self.viewport.borrow(),
- );
- let next_active_pane_id = pane_grid.previous_selectable_pane_id(&active_pane_id);
+ let next_active_pane_id = {
+ let pane_grid = TiledPaneGrid::new(
+ &mut self.panes,
+ &self.panes_to_hide,
+ *self.display_area.borrow(),
+ *self.viewport.borrow(),
+ );
+ pane_grid.previous_selectable_pane_id(&active_pane_id)
+ };
+
+ if self
+ .panes
+ .get(&next_active_pane_id)
+ .map(|p| p.current_geom().is_stacked)
+ .unwrap_or(false)
+ {
+ let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
+ .focus_pane(&next_active_pane_id);
+ self.reapply_pane_frames();
+ }
for client_id in connected_clients {
self.active_panes
.insert(client_id, next_active_pane_id, &mut self.panes);
@@ -716,13 +896,15 @@ impl TiledPanes {
pub fn move_focus_down(&mut self, client_id: ClientId) -> bool {
match self.get_active_pane_id(client_id) {
Some(active_pane_id) => {
- let pane_grid = TiledPaneGrid::new(
+ let mut pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
- let next_index = pane_grid.next_selectable_pane_id_below(&active_pane_id);
+ let next_index = pane_grid
+ .next_selectable_pane_id_below(&active_pane_id)
+ .or_else(|| pane_grid.progress_stack_down_if_in_stack(&active_pane_id));
match next_index {
Some(p) => {
// render previously active pane so that its frame does not remain actively
@@ -732,12 +914,16 @@ impl TiledPanes {
.get_mut(self.active_panes.get(&client_id).unwrap())
.unwrap();
+ let previously_active_pane_is_stacked =
+ previously_active_pane.current_geom().is_stacked;
previously_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor)
previously_active_pane.render_full_viewport();
let next_active_pane = self.panes.get_mut(&p).unwrap();
+ let next_active_pane_is_stacked =
+ next_active_pane.current_geom().is_stacked;
next_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor)
@@ -745,6 +931,13 @@ impl TiledPanes {
self.focus_pane(p, client_id);
self.set_pane_active_at(p);
+ if previously_active_pane_is_stacked || next_active_pane_is_stacked {
+ // we do this because a stack pane focus change also changes its
+ // geometry and we need to let the pty know about this (like in a
+ // normal size change)
+ self.focus_pane_for_all_clients(p); // TODO: for all client *in stack*
+ self.reapply_pane_frames();
+ }
true
},
@@ -757,13 +950,15 @@ impl TiledPanes {
pub fn move_focus_up(&mut self, client_id: ClientId) -> bool {
match self.get_active_pane_id(client_id) {
Some(active_pane_id) => {
- let pane_grid = TiledPaneGrid::new(
+ let mut pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
- let next_index = pane_grid.next_selectable_pane_id_above(&active_pane_id);
+ let next_index = pane_grid
+ .next_selectable_pane_id_above(&active_pane_id)
+ .or_else(|| pane_grid.progress_stack_up_if_in_stack(&active_pane_id));
match next_index {
Some(p) => {
// render previously active pane so that its frame does not remain actively
@@ -773,12 +968,16 @@ impl TiledPanes {
.get_mut(self.active_panes.get(&client_id).unwrap())
.unwrap();
+ let previously_active_pane_is_stacked =
+ previously_active_pane.current_geom().is_stacked;
previously_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor)
previously_active_pane.render_full_viewport();
let next_active_pane = self.panes.get_mut(&p).unwrap();
+ let next_active_pane_is_stacked =
+ next_active_pane.current_geom().is_stacked;
next_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor)
@@ -786,6 +985,13 @@ impl TiledPanes {
self.focus_pane(p, client_id);
self.set_pane_active_at(p);
+ if previously_active_pane_is_stacked || next_active_pane_is_stacked {
+ // we do this because a stack pane focus change also changes its
+ // geometry and we need to let the pty know about this (like in a
+ // normal size change)
+ self.focus_pane_for_all_clients(p); // TODO: for all client *in stack*
+ self.reapply_pane_frames();
+ }
true
},
@@ -836,15 +1042,66 @@ impl TiledPanes {
None => false,
}
}
- pub fn move_active_pane(&mut self, client_id: ClientId) {
+ pub fn switch_active_pane_with(&mut self, pane_id: PaneId) {
+ if let Some(active_pane_id) = self.first_active_pane_id() {
+ if let PaneId::Plugin(_) = active_pane_id {
+ // we do not implicitly change the location of plugin panes
+ // TODO: we might want to make this configurable through a layout property or a
+ // plugin API
+ return;
+ }
+ let current_position = self.panes.get(&active_pane_id).unwrap();
+ let prev_geom = current_position.position_and_size();
+ let prev_geom_override = current_position.geom_override();
+
+ let new_position = self.panes.get_mut(&pane_id).unwrap();
+ let next_geom = new_position.position_and_size();
+ let next_geom_override = new_position.geom_override();
+ new_position.set_geom(prev_geom);
+ if let Some(geom) = prev_geom_override {
+ new_position.set_geom_override(geom);
+ }
+ resize_pty!(new_position, self.os_api, self.senders).unwrap();
+ new_position.set_should_render(true);
+
+ let current_position = self.panes.get_mut(&active_pane_id).unwrap();
+ current_position.set_geom(next_geom);
+ if let Some(geom) = next_geom_override {
+ current_position.set_geom_override(geom);
+ }
+ resize_pty!(current_position, self.os_api, self.senders).unwrap();
+ current_position.set_should_render(true);
+ self.focus_pane_for_all_clients(active_pane_id);
+ self.set_pane_frames(self.draw_pane_frames);
+ }
+ }
+ pub fn move_active_pane(&mut self, search_backwards: bool, client_id: ClientId) {
let active_pane_id = self.get_active_pane_id(client_id).unwrap();
- let pane_grid = TiledPaneGrid::new(
- &mut self.panes,
- &self.panes_to_hide,
- *self.display_area.borrow(),
- *self.viewport.borrow(),
- );
- let new_position_id = pane_grid.next_selectable_pane_id(&active_pane_id);
+
+ let new_position_id = {
+ let pane_grid = TiledPaneGrid::new(
+ &mut self.panes,
+ &self.panes_to_hide,
+ *self.display_area.borrow(),
+ *self.viewport.borrow(),
+ );
+ if search_backwards {
+ pane_grid.previous_selectable_pane_id(&active_pane_id)
+ } else {
+ pane_grid.next_selectable_pane_id(&active_pane_id)
+ }
+ };
+ if self
+ .panes
+ .get(&new_position_id)
+ .map(|p| p.current_geom().is_stacked)
+ .unwrap_or(false)
+ {
+ let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
+ .focus_pane(&new_position_id);
+ self.reapply_pane_frames();
+ }
+
let current_position = self.panes.get(&active_pane_id).unwrap();
let prev_geom = current_position.position_and_size();
let prev_geom_override = current_position.geom_override();
@@ -870,13 +1127,15 @@ impl TiledPanes {
}
pub fn move_active_pane_down(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
- let pane_grid = TiledPaneGrid::new(
+ let mut pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
- let next_index = pane_grid.next_selectable_pane_id_below(&active_pane_id);
+ let next_index = pane_grid
+ .next_selectable_pane_id_below(&active_pane_id)
+ .or_else(|| pane_grid.progress_stack_down_if_in_stack(&active_pane_id));
if let Some(p) = next_index {
let active_pane_id = self.active_panes.get(&client_id).unwrap();
let current_position = self.panes.get(active_pane_id).unwrap();
@@ -978,13 +1237,15 @@ impl TiledPanes {
}
pub fn move_active_pane_up(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
- let pane_grid = TiledPaneGrid::new(
+ let mut pane_grid = TiledPaneGrid::new(
&mut self.panes,
&self.panes_to_hide,
*self.display_area.borrow(),
*self.viewport.borrow(),
);
- let next_index = pane_grid.next_selectable_pane_id_above(&active_pane_id);
+ let next_index = pane_grid
+ .next_selectable_pane_id_above(&active_pane_id)
+ .or_else(|| pane_grid.progress_stack_up_if_in_stack(&active_pane_id));
if let Some(p) = next_index {
let active_pane_id = self.active_panes.get(&client_id).unwrap();
let current_position = self.panes.get(active_pane_id).unwrap();
@@ -1033,11 +1294,21 @@ impl TiledPanes {
.map(|(pane_id, _pane)| **pane_id);
match next_active_pane_id {
- Some(next_active_pane) => {
+ Some(next_active_pane_id) => {
+ if self
+ .panes
+ .get(&next_active_pane_id)
+ .map(|p| p.current_geom().is_stacked)
+ .unwrap_or(false)
+ {
+ let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
+ .focus_pane(&next_active_pane_id);
+ self.reapply_pane_frames();
+ }
for (client_id, active_pane_id) in active_panes {
if active_pane_id == pane_id {
self.active_panes
- .insert(client_id, next_active_pane, &mut self.panes);
+ .insert(client_id, next_active_pane_id, &mut self.panes);
}
}
},
@@ -1160,13 +1431,13 @@ impl TiledPanes {
viewport_pane.set_geom_override(viewport_pane.position_and_size());
}
let viewport = { *self.viewport.borrow() };
- let active_terminal = self.get_pane_mut(active_pane_id).unwrap();
+ let active_pane = self.get_pane_mut(active_pane_id).unwrap();
let full_screen_geom = PaneGeom {
x: viewport.x,
y: viewport.y,
..Default::default()
};
- active_terminal.set_geom_override(full_screen_geom);
+ active_pane.set_geom_override(full_screen_geom);
}
let connected_client_list: Vec<ClientId> =
{ self.connected_clients.borrow().iter().copied().collect() };
@@ -1196,6 +1467,9 @@ impl TiledPanes {
pub fn panes_to_hide_count(&self) -> usize {
self.panes_to_hide.len()
}
+ pub fn visible_panes_count(&self) -> usize {
+ self.panes.len().saturating_sub(self.panes_to_hide.len())
+ }
pub fn add_to_hidden_panels(&mut self, pid: PaneId) {
self.panes_to_hide.insert(pid);
}
@@ -1208,6 +1482,18 @@ impl TiledPanes {
pub fn focus_all_panes(&mut self) {
self.active_panes.focus_all_panes(&mut self.panes);
}
+ pub fn drain(&mut self) -> BTreeMap<PaneId, Box<dyn Pane>> {
+ match self.panes.iter().next().map(|(pid, _p)| *pid) {
+ Some(first_pid) => self.panes.split_off(&first_pid),
+ None => BTreeMap::new(),
+ }
+ }
+ pub fn active_panes(&self) -> ActivePanes {
+ self.active_panes.clone()
+ }
+ pub fn set_active_panes(&mut self, active_panes: ActivePanes) {
+ self.active_panes = active_panes;
+ }
fn move_clients_between_panes(&mut self, from_pane_id: PaneId, to_pane_id: PaneId) {
let clients_in_pane: Vec<ClientId> = self
.active_panes
diff --git a/zellij-server/src/panes/tiled_panes/pane_resizer.rs b/zellij-server/src/panes/tiled_panes/pane_resizer.rs
index c01e42e4..2a2b5b6f 100644
--- a/zellij-server/src/panes/tiled_panes/pane_resizer.rs
+++ b/zellij-server/src/panes/tiled_panes/pane_resizer.rs
@@ -1,3 +1,4 @@
+use super::stacked_panes::StackedPanes;
use crate::{panes::PaneId, tab::Pane};
use cassowary::{
strength::{REQUIRED, STRONG},
@@ -35,8 +36,8 @@ type Grid = Vec<Vec<Span>>;
impl<'a> PaneResizer<'a> {
pub fn new(panes: Rc<RefCell<HashMap<PaneId, &'a mut Box<dyn Pane>>>>) -> Self {
let mut vars = HashMap::new();
- for &k in panes.borrow().keys() {
- vars.insert(k, Variable::new());
+ for &pane_id in panes.borrow().keys() {
+ vars.insert(pane_id, Variable::new());
}
PaneResizer {
panes,
@@ -129,32 +130,64 @@ impl<'a> PaneResizer<'a> {
fn apply_spans(&mut self, spans: Vec<Span>) -> Result<()> {
let err_context = || format!("Failed to apply spans");
- let mut panes = self.panes.borrow_mut();
let mut geoms_changed = false;
for span in spans {
- let pane = panes.get_mut(&span.pid).unwrap();
- let current_geom = pane.position_and_size();
- let new_geom = match span.direction {
- SplitDirection::Horizontal => PaneGeom {
- x: span.pos,
- cols: span.size,
- ..pane.current_geom()
- },
- SplitDirection::Vertical => PaneGeom {
- y: span.pos,
- rows: span.size,
- ..pane.current_geom()
- },
- };
- if new_geom.rows.as_usize() != current_geom.rows.as_usize()
- || new_geom.cols.as_usize() != current_geom.cols.as_usize()
- {
- geoms_changed = true;
- }
- if pane.geom_override().is_some() {
- pane.set_geom_override(new_geom);
+ let pane_is_stacked = self
+ .panes
+ .borrow()
+ .get(&span.pid)
+ .unwrap()
+ .current_geom()
+ .is_stacked;
+ if pane_is_stacked {
+ let current_geom = StackedPanes::new(self.panes.clone())
+ .position_and_size_of_stack(&span.pid)
+ .unwrap();
+ let new_geom = match span.direction {
+ SplitDirection::Horizontal => PaneGeom {
+ x: span.pos,
+ cols: span.size,
+ ..current_geom
+ },
+ SplitDirection::Vertical => PaneGeom {
+ y: span.pos,
+ rows: span.size,
+ ..current_geom
+ },
+ };
+ StackedPanes::new(self.panes.clone()).resize_panes_in_stack(&span.pid, new_geom)?;
+ // TODO: test with geom_override (fullscreen)
+ if new_geom.rows.as_usize() != current_geom.rows.as_usize()
+ || new_geom.cols.as_usize() != current_geom.cols.as_usize()
+ {
+ geoms_changed = true;
+ }
} else {
- pane.set_geom(new_geom);
+ let mut panes = self.panes.borrow_mut();
+ let pane = panes.get_mut(&span.pid).unwrap();
+ let current_geom = pane.position_and_size();
+ let new_geom = match span.direction {
+ SplitDirection::Horizontal => PaneGeom {
+ x: span.pos,
+ cols: span.size,
+ ..pane.current_geom()
+ },
+ SplitDirection::Vertical => PaneGeom {
+ y: span.pos,
+ rows: span.size,
+ ..pane.current_geom()
+ },
+ };
+ if new_geom.rows.as_usize() != current_geom.rows.as_usize()
+ || new_geom.cols.as_usize() != current_geom.cols.as_usize()
+ {
+ geoms_changed = true;
+ }
+ if pane.geom_override().is_some() {
+ pane.set_geom_override(new_geom);
+ } else {
+ pane.set_geom(new_geom);
+ }
}
}
if geoms_changed {
@@ -175,7 +208,7 @@ impl<'a> PaneResizer<'a> {
.panes
.borrow()
.values()
- .map(|p| self.get_span(!direction, p.as_ref()))
+ .filter_map(|p| self.get_span(!direction, p.as_ref()))
.collect();
let mut last_edge = 0;
@@ -197,38 +230,52 @@ impl<'a> PaneResizer<'a> {
.panes
.borrow()
.values()
- .filter(|p| {
- let s = self.get_span(!direction, p.as_ref());
- let span_bounds = (s.pos, s.pos + s.size.as_usize());
- bwn(span_bounds.0, boundary)
- || (bwn(boundary.0, span_bounds)
- && (bwn(boundary.1, span_bounds) || boundary.1 == span_bounds.1))
+ .filter(|p| match self.get_span(!direction, p.as_ref()) {
+ Some(s) => {
+ let span_bounds = (s.pos, s.pos + s.size.as_usize());
+ bwn(span_bounds.0, boundary)
+ || (bwn(boundary.0, span_bounds)
+ && (bwn(boundary.1, span_bounds) || boundary.1 == span_bounds.1))
+ },
+ None => false,
})
- .map(|p| self.get_span(direction, p.as_ref()))
+ .filter_map(|p| self.get_span(direction, p.as_ref()))
.collect();
spans.sort_unstable_by_key(|s| s.pos);
spans
}
- fn get_span(&self, direction: SplitDirection, pane: &dyn Pane) -> Span {
- let pas = pane.current_geom();
- // let size_var = self.vars[&pane.pid()];
+ fn get_span(&self, direction: SplitDirection, pane: &dyn Pane) -> Option<Span> {
+ let position_and_size = {
+ let pas = pane.current_geom();
+ if pas.is_stacked && pas.rows.is_percent() {
+ // this is the main pane of the stack
+ StackedPanes::new(self.panes.clone()).position_and_size_of_stack(&pane.pid())
+ } else if pas.is_stacked {
+ // this is a one-liner stacked pane and should be handled as the same rect with
+ // the rest of the stack, represented by the main pane in the if branch above
+ None
+ } else {
+ // non-stacked pane, treat normally
+ Some(pas)
+ }
+ }?;
let size_var = *self.vars.get(&pane.pid()).unwrap();
match direction {
- SplitDirection::Horizontal => Span {
+ SplitDirection::Horizontal => Some(Span {
pid: pane.pid(),
direction,
- pos: pas.x,
- size: pas.cols,
+ pos: position_and_size.x,
+ size: position_and_size.cols,
size_var,
- },
- SplitDirection::Vertical => Span {
+ }),
+ SplitDirection::Vertical => Some(Span {
pid: pane.pid(),
direction,
- pos: pas.y,
- size: pas.rows,
+ pos: position_and_size.y,
+ size: position_and_size.rows,
size_var,
- },
+ }),
}
}
}
@@ -249,7 +296,7 @@ fn constrain_spans(space: usize, spans: &[Span]) -> HashSet<cassowary::Constrain
let full_size = spans
.iter()
.fold(Expression::from_constant(0.0), |acc, s| acc + s.size_var);
- constraints.insert(full_size | EQ(REQUIRED) | space as f64);
+ constraints.insert(full_size.clone() | EQ(REQUIRED) | space as f64);
// Try to maintain ratios and lock non-flexible sizes
for span in spans {
diff --git a/zellij-server/src/panes/tiled_panes/stacked_panes.rs b/zellij-server/src/panes/tiled_panes/stacked_panes.rs
new file mode 100644
index 00000000..00b193f6
--- /dev/null
+++ b/zellij-server/src/panes/tiled_panes/stacked_panes.rs
@@ -0,0 +1,630 @@
+use crate::{panes::PaneId, tab::Pane};
+use std::cell::RefCell;
+use std::collections::{HashMap, HashSet};
+use std::rc::Rc;
+use zellij_utils::{
+ errors::prelude::*,
+ pane_size::{Dimension, PaneGeom},
+};
+
+pub struct StackedPanes<'a> {
+ panes: Rc<RefCell<HashMap<PaneId, &'a mut Box<dyn Pane>>>>,
+}
+
+impl<'a> StackedPanes<'a> {
+ pub fn new(panes: Rc<RefCell<HashMap<PaneId, &'a mut Box<dyn Pane>>>>) -> Self {
+ StackedPanes { panes }
+ }
+ pub fn new_from_btreemap(
+ panes: impl IntoIterator<Item = (&'a PaneId, &'a mut Box<dyn Pane>)>,
+ panes_to_hide: &HashSet<PaneId>,
+ ) -> Self {
+ let panes: HashMap<_, _> = panes
+ .into_iter()
+ .filter(|(p_id, _)| !panes_to_hide.contains(p_id))
+ .map(|(p_id, p)| (*p_id, p))
+ .collect();
+ let panes = Rc::new(RefCell::new(panes));
+ StackedPanes { panes }
+ }
+ pub fn move_down(
+ &mut self,
+ source_pane_id: &PaneId,
+ destination_pane_id: &PaneId,
+ ) -> Result<()> {
+ let err_context = || format!("Failed to move stacked pane focus down");
+ let source_pane_is_stacked = self
+ .panes
+ .borrow()
+ .get(source_pane_id)
+ .with_context(err_context)?
+ .position_and_size()
+ .is_stacked;
+ let destination_pane_is_stacked = self
+ .panes
+ .borrow()
+ .get(destination_pane_id)
+ .with_context(err_context)?
+ .position_and_size()
+ .is_stacked;
+ if source_pane_is_stacked && destination_pane_is_stacked {
+ let mut panes = self.panes.borrow_mut();
+ let source_pane = panes.get_mut(source_pane_id).with_context(err_context)?;
+ let mut source_pane_geom = source_pane.position_and_size();
+ let mut destination_pane_geom = source_pane_geom.clone();
+ destination_pane_geom.y = source_pane_geom.y + 1;
+ source_pane_geom.rows = Dimension::fixed(1);
+ source_pane.set_geom(source_pane_geom);
+ let destination_pane = panes
+ .get_mut(&destination_pane_id)
+ .with_context(err_context)?;
+ destination_pane.set_geom(destination_pane_geom);
+ } else if destination_pane_is_stacked {
+ // we're moving down to the highest pane in the stack, we need to expand it and shrink the
+ // expanded stack pane
+ self.make_highest_pane_in_stack_flexible(destination_pane_id)?;
+ }
+ Ok(())
+ }
+ pub fn move_up(&mut self, source_pane_id: &PaneId, destination_pane_id: &PaneId) -> Result<()> {
+ let err_context = || format!("Failed to move stacked pane focus up");
+ let source_pane_is_stacked = self
+ .panes
+ .borrow()
+ .get(source_pane_id)
+ .with_context(err_context)?
+ .position_and_size()
+ .is_stacked;
+ let destination_pane_is_stacked = self
+ .panes
+ .borrow()
+ .get(destination_pane_id)
+ .with_context(err_context)?
+ .position_and_size()
+ .is_stacked;
+ if source_pane_is_stacked && destination_pane_is_stacked {
+ let mut panes = self.panes.borrow_mut();
+ let source_pane = panes.get_mut(source_pane_id).with_context(err_context)?;
+ let mut source_pane_geom = source_pane.position_and_size();
+ let mut destination_pane_geom = source_pane_geom.clone();
+ source_pane_geom.y = (source_pane_geom.y + source_pane_geom.rows.as_usize()) - 1; // -1 because we want to be at the last line of the source pane, not the next line over
+ source_pane_geom.rows = Dimension::fixed(1);
+ source_pane.set_geom(source_pane_geom);
+ destination_pane_geom.y -= 1;
+ let destination_pane = panes
+ .get_mut(&destination_pane_id)
+ .with_context(err_context)?;
+ destination_pane.set_geom(destination_pane_geom);
+ } else if destination_pane_is_stacked {
+ // we're moving up to the lowest pane in the stack, we need to expand it and shrink the
+ // expanded stack pane
+ self.make_lowest_pane_in_stack_flexible(destination_pane_id)?;
+ }
+ Ok(())
+ }
+ pub fn focus_pane(&mut self, pane_id: &PaneId) -> Result<()> {
+ // this function doesn't actually change the focus (since it is controlled elsewhere)
+ // but rather makes sure pane_id is flexible if it were a one-liner before
+ let err_context = || format!("Failed to focus stacked pane");
+ let all_stacked_pane_positions =
+ self.positions_in_stack(pane_id).with_context(err_context)?;
+
+ let position_of_flexible_pane = self
+ .position_of_flexible_pane(&all_stacked_pane_positions)
+ .with_context(err_context)?;
+ let (flexible_pane_id, mut flexible_pane) = *all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .with_context(err_context)?;
+ if flexible_pane_id != *pane_id {
+ let mut panes = self.panes.borrow_mut();
+ let height_of_flexible_pane = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .map(|(_pid, p)| p.rows)
+ .with_context(err_context)?;
+ let position_of_pane_to_focus = all_stacked_pane_positions
+ .iter()
+ .position(|(pid, _p)| pid == pane_id)
+ .with_context(err_context)?;
+ let (_, mut pane_to_focus) = *all_stacked_pane_positions
+ .iter()
+ .nth(position_of_pane_to_focus)
+ .with_context(err_context)?;
+ pane_to_focus.rows = height_of_flexible_pane;
+ panes
+ .get_mut(pane_id)
+ .with_context(err_context)?
+ .set_geom(pane_to_focus);
+ flexible_pane.rows = Dimension::fixed(1);
+ panes
+ .get_mut(&flexible_pane_id)
+ .with_context(err_context)?
+ .set_geom(flexible_pane);
+
+ for (i, (pid, _position)) in all_stacked_pane_positions.iter().enumerate() {
+ if i > position_of_pane_to_focus && i <= position_of_flexible_pane {
+ // the flexible pane has moved up the stack, we need to push this pane down
+ let pane = panes.get_mut(pid).with_context(err_context)?;
+ let mut pane_position_and_size = pane.position_and_size();
+ pane_position_and_size.y += height_of_flexible_pane.as_usize() - 1;
+ pane.set_geom(pane_position_and_size);
+ } else if i > position_of_flexible_pane && i <= position_of_pane_to_focus {
+ // the flexible pane has moved down the stack, we need to pull this pane up
+ let pane = panes.get_mut(pid).with_context(err_context)?;
+ let mut pane_position_and_size = pane.position_and_size();
+ pane_position_and_size.y -= height_of_flexible_pane.as_usize() - 1;
+ pane.set_geom(pane_position_and_size);
+ }
+ }
+ }
+ Ok(())
+ }
+ pub fn flexible_pane_id_in_stack(&self, pane_id_in_stack: &PaneId) -> Option<PaneId> {
+ let all_stacked_pane_positions = self.positions_in_stack(pane_id_in_stack).ok()?;
+ all_stacked_pane_positions
+ .iter()
+ .find(|(_pid, p)| p.rows.is_percent())
+ .map(|(pid, _p)| *pid)
+ }
+ pub fn position_and_size_of_stack(&self, id: &PaneId) -> Option<PaneGeom> {
+ let all_stacked_pane_positions = self.positions_in_stack(id).ok()?;
+ let position_of_flexible_pane = self
+ .position_of_flexible_pane(&all_stacked_pane_positions)
+ .ok()?;
+ let (_flexible_pane_id, flexible_pane) = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)?;
+ let (_, first_pane_in_stack) = all_stacked_pane_positions.first()?;
+ let (_, last_pane_in_stack) = all_stacked_pane_positions.last()?;
+ let mut rows = flexible_pane.rows;
+ rows.set_inner(
+ (last_pane_in_stack.y - first_pane_in_stack.y) + last_pane_in_stack.rows.as_usize(),
+ );
+ Some(PaneGeom {
+ y: first_pane_in_stack.y,
+ x: first_pane_in_stack.x,
+ cols: first_pane_in_stack.cols,
+ rows,
+ is_stacked: true, // important because otherwise the minimum stack size will not be
+ // respected
+ ..Default::default()
+ })
+ }
+ pub fn increase_stack_width(&mut self, id: &PaneId, percent: f64) -> Result<()> {
+ let err_context = || format!("Failed to resize panes in stack");
+ let all_stacked_pane_positions = self.positions_in_stack(id).with_context(err_context)?;
+ for (pane_id, _pane_position) in all_stacked_pane_positions {
+ self.panes
+ .borrow_mut()
+ .get_mut(&pane_id)
+ .with_context(err_context)?
+ .increase_width(percent);
+ }
+ Ok(())
+ }
+ pub fn reduce_stack_width(&mut self, id: &PaneId, percent: f64) -> Result<()> {
+ let err_context = || format!("Failed to resize panes in stack");
+ let all_stacked_pane_positions = self.positions_in_stack(id).with_context(err_context)?;
+ for (pane_id, _pane_position) in all_stacked_pane_positions {
+ self.panes
+ .borrow_mut()
+ .get_mut(&pane_id)
+ .with_context(err_context)?
+ .reduce_width(percent);
+ }
+ Ok(())
+ }
+ pub fn increase_stack_height(&mut self, id: &PaneId, percent: f64) -> Result<()> {
+ let err_context = || format!("Failed to increase_stack_height");
+ let all_stacked_pane_positions = self.positions_in_stack(id).with_context(err_context)?;
+ let position_of_flexible_pane = self
+ .position_of_flexible_pane(&all_stacked_pane_positions)
+ .with_context(err_context)?;
+ let (flexible_pane_id, _flexible_pane) = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .with_context(err_context)?;
+ self.panes
+ .borrow_mut()
+ .get_mut(flexible_pane_id)
+ .with_context(err_context)?
+ .increase_height(percent);
+ Ok(())
+ }
+ pub fn reduce_stack_height(&mut self, id: &PaneId, percent: f64) -> Result<()> {
+ let err_context = || format!("Failed to increase_stack_height");
+ let all_stacked_pane_positions = self.positions_in_stack(id).with_context(err_context)?;
+ let position_of_flexible_pane = self
+ .position_of_flexible_pane(&all_stacked_pane_positions)
+ .with_context(err_context)?;
+ let (flexible_pane_id, _flexible_pane) = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .with_context(err_context)?;
+ self.panes
+ .borrow_mut()
+ .get_mut(flexible_pane_id)
+ .with_context(err_context)?
+ .reduce_height(percent);
+ Ok(())
+ }
+ pub fn min_stack_height(&mut self, id: &PaneId) -> Result<usize> {
+ let err_context = || format!("Failed to increase_stack_height");
+ let all_stacked_pane_positions = self.positions_in_stack(id).with_context(err_context)?;
+ Ok(all_stacked_pane_positions.len())
+ }
+ pub fn resize_panes_in_stack(
+ &mut self,
+ id: &PaneId,
+ new_full_stack_geom: PaneGeom,
+ ) -> Result<()> {
+ let err_context = || format!("Failed to resize panes in stack");
+ let all_stacked_pane_positions = self.positions_in_stack(id).with_context(err_context)?;
+ let position_of_flexible_pane =
+ self.position_of_flexible_pane(&all_stacked_pane_positions)?;
+ let (flexible_pane_id, flexible_pane) = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .with_context(err_context)?;
+ let current_rows = all_stacked_pane_positions.len() + (flexible_pane.rows.as_usize() - 1);
+ let new_rows = new_full_stack_geom.rows.as_usize();
+
+ let adjust_stack_geoms = |new_flexible_pane_geom: PaneGeom| -> Result<()> {
+ let new_flexible_pane_geom_rows = new_flexible_pane_geom.rows.as_usize();
+ for (i, (pane_id, pane_geom)) in all_stacked_pane_positions.iter().enumerate() {
+ let mut new_pane_geom = if i == position_of_flexible_pane {
+ new_flexible_pane_geom
+ } else {
+ *pane_geom
+ };
+ new_pane_geom.x = new_full_stack_geom.x;
+ new_pane_geom.cols = new_full_stack_geom.cols;
+ if i <= position_of_flexible_pane {
+ new_pane_geom.y = new_full_stack_geom.y + i;
+ } else {
+ new_pane_geom.y = new_full_stack_geom.y + i + (new_flexible_pane_geom_rows - 1);
+ }
+ self.panes
+ .borrow_mut()
+ .get_mut(&pane_id)
+ .with_context(err_context)?
+ .set_geom(new_pane_geom);
+ }
+ Ok(())
+ };
+
+ if new_rows >= current_rows {
+ let extra_rows = new_rows - current_rows;
+ let mut new_flexible_pane_geom = *flexible_pane;
+ new_flexible_pane_geom
+ .rows
+ .set_inner(new_flexible_pane_geom.rows.as_usize() + extra_rows);
+ self.panes
+ .borrow_mut()
+ .get_mut(&flexible_pane_id)
+ .with_context(err_context)?
+ .set_geom(new_flexible_pane_geom);
+ adjust_stack_geoms(new_flexible_pane_geom)?;
+ } else {
+ if new_rows < all_stacked_pane_positions.len() {
+ // TODO: test this!! we don't want crashes...
+ return Err(anyhow!("Not enough room for stacked panes"));
+ }
+ let rows_deficit = current_rows - new_rows;
+ let mut new_flexible_pane_geom = *flexible_pane;
+ new_flexible_pane_geom
+ .rows
+ .set_inner(new_flexible_pane_geom.rows.as_usize() - rows_deficit);
+ self.panes
+ .borrow_mut()
+ .get_mut(&flexible_pane_id)
+ .with_context(err_context)?
+ .set_geom(new_flexible_pane_geom);
+ adjust_stack_geoms(new_flexible_pane_geom)?;
+ }
+ Ok(())
+ }
+ fn pane_is_one_liner(&self, id: &PaneId) -> Result<bool> {
+ let err_context = || format!("Cannot determin if pane is one liner or not");
+ let panes = self.panes.borrow();
+ let pane_to_close = panes.get(id).with_context(err_context)?;
+ Ok(pane_to_close.position_and_size().rows.is_fixed())
+ }
+ fn positions_in_stack(&self, id: &PaneId) -> Result<Vec<(PaneId, PaneGeom)>> {
+ // find the full stack of panes around the given id, sorted by pane location top to bottom
+ let err_context = || format!("Failed to find stacked panes");
+ let panes = self.panes.borrow();
+ let pane_in_stack = panes.get(id).with_context(err_context)?;
+ let mut all_stacked_pane_positions: Vec<(PaneId, PaneGeom)> = panes
+ .iter()
+ .filter(|(_pid, p)| p.position_and_size().is_stacked)
+ .filter(|(_pid, p)| {
+ p.position_and_size().x == pane_in_stack.position_and_size().x
+ && p.position_and_size().cols == pane_in_stack.position_and_size().cols
+ })
+ .map(|(pid, p)| (*pid, p.position_and_size()))
+ .collect();
+ all_stacked_pane_positions.sort_by(|(_a_pid, a), (_b_pid, b)| a.y.cmp(&b.y));
+ Ok(all_stacked_pane_positions)
+ }
+ fn position_of_current_and_flexible_pane(
+ &self,
+ current_pane_id: &PaneId,
+ ) -> Result<(usize, usize)> {
+ // (current_pane, flexible_pane)
+ let err_context = || format!("Failed to position_of_current_and_flexible_pane");
+ let all_stacked_pane_positions = self.positions_in_stack(current_pane_id)?;
+ let panes = self.panes.borrow();
+ let pane_to_close = panes.get(current_pane_id).with_context(err_context)?;
+ let position_of_current_pane =
+ self.position_of_current_pane(&all_stacked_pane_positions, &pane_to_close)?;
+ let position_of_flexible_pane =
+ self.position_of_flexible_pane(&all_stacked_pane_positions)?;
+ Ok((position_of_current_pane, position_of_flexible_pane))
+ }
+ fn position_of_current_pane(
+ &self,
+ all_stacked_pane_positions: &Vec<(PaneId, PaneGeom)>,
+ pane_to_close: &Box<dyn Pane>,
+ ) -> Result<usize> {
+ let err_context = || format!("Failed to find position of current pane");
+ all_stacked_pane_positions
+ .iter()
+ .position(|(pid, _p)| pid == &pane_to_close.pid())
+ .with_context(err_context)
+ }
+ fn position_of_flexible_pane(
+ &self,
+ all_stacked_pane_positions: &Vec<(PaneId, PaneGeom)>,
+ ) -> Result<usize> {
+ let err_context = || format!("Failed to find position of flexible pane");
+ all_stacked_pane_positions
+ .iter()
+ .position(|(_pid, p)| p.rows.is_percent())
+ .with_context(err_context)
+ }
+ pub fn fill_space_over_pane_in_stack(&mut self, id: &PaneId) -> Result<bool> {
+ if self.pane_is_one_liner(id)? {
+ self.fill_space_over_one_liner_pane(id)
+ } else {
+ self.fill_space_over_visible_stacked_pane(id)
+ }
+ }
+ pub fn stacked_pane_ids_under_and_over_flexible_panes(
+ &self,
+ ) -> Result<(HashSet<PaneId>, HashSet<PaneId>)> {
+ let mut stacked_pane_ids_under_flexible_panes = HashSet::new();
+ let mut stacked_pane_ids_over_flexible_panes = HashSet::new();
+ let mut seen = HashSet::new();
+ let pane_ids_in_stacks: Vec<PaneId> = {
+ self.panes
+ .borrow()
+ .iter()
+ .filter(|(_p_id, p)| p.position_and_size().is_stacked)
+ .map(|(p_id, _p)| *p_id)
+ .collect()
+ };
+ for pane_id in pane_ids_in_stacks {
+ if !seen.contains(&pane_id) {
+ let mut current_pane_is_above_stack = true;
+ let positions_in_stack = self.positions_in_stack(&pane_id)?;
+ for (pane_id, pane_geom) in positions_in_stack {
+ seen.insert(pane_id);
+ if pane_geom.rows.is_percent() {
+ // this is the flexible pane
+ current_pane_is_above_stack = false;
+ continue;
+ }
+ if current_pane_is_above_stack {
+ stacked_pane_ids_over_flexible_panes.insert(pane_id);
+ } else {
+ stacked_pane_ids_under_flexible_panes.insert(pane_id);
+ }
+ }
+ seen.insert(pane_id);
+ }
+ }
+ Ok((
+ stacked_pane_ids_under_flexible_panes,
+ stacked_pane_ids_over_flexible_panes,
+ ))
+ }
+ fn fill_space_over_one_liner_pane(&mut self, id: &PaneId) -> Result<bool> {
+ let (position_of_current_pane, position_of_flexible_pane) =
+ self.position_of_current_and_flexible_pane(id)?;
+ if position_of_current_pane > position_of_flexible_pane {
+ self.fill_space_over_one_liner_pane_above_flexible_pane(id)
+ } else {
+ self.fill_space_over_one_liner_pane_below_flexible_pane(id)
+ }
+ }
+ fn fill_space_over_visible_stacked_pane(&mut self, id: &PaneId) -> Result<bool> {
+ let err_context = || format!("Failed to fill_space_over_visible_stacked_pane");
+ let all_stacked_pane_positions = self.positions_in_stack(id)?;
+ let mut panes = self.panes.borrow_mut();
+ let pane_to_close = panes.get(id).with_context(err_context)?;
+ let position_of_current_pane =
+ self.position_of_current_pane(&all_stacked_pane_positions, &pane_to_close)?;
+ if all_stacked_pane_positions.len() > position_of_current_pane + 1 {
+ let mut pane_to_close_position_and_size = pane_to_close.position_and_size();
+ pane_to_close_position_and_size
+ .rows
+ .set_inner(pane_to_close_position_and_size.rows.as_usize() + 1);
+ let pane_id_below = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_current_pane + 1)
+ .map(|(pid, _)| *pid)
+ .with_context(err_context)?;
+ let pane_below = panes.get_mut(&pane_id_below).with_context(err_context)?;
+ pane_below.set_geom(pane_to_close_position_and_size);
+ return Ok(true);
+ } else if position_of_current_pane > 0 {
+ let mut pane_to_close_position_and_size = pane_to_close.position_and_size();
+ pane_to_close_position_and_size
+ .rows
+ .set_inner(pane_to_close_position_and_size.rows.as_usize() + 1);
+ pane_to_close_position_and_size.y -= 1;
+ let pane_id_above = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_current_pane - 1)
+ .map(|(pid, _)| *pid)
+ .with_context(err_context)?;
+ let pane_above = panes.get_mut(&pane_id_above).with_context(err_context)?;
+ pane_above.set_geom(pane_to_close_position_and_size);
+ return Ok(true);
+ } else {
+ return Ok(false);
+ }
+ }
+ fn fill_space_over_one_liner_pane_above_flexible_pane(&mut self, id: &PaneId) -> Result<bool> {
+ let err_context =
+ || format!("Failed to fill_space_over_one_liner_pane_above_flexible_pane");
+ let all_stacked_pane_positions = self.positions_in_stack(id)?;
+ let mut panes = self.panes.borrow_mut();
+ let pane_to_close = panes.get(id).with_context(err_context)?;
+ let position_of_current_pane =
+ self.position_of_current_pane(&all_stacked_pane_positions, &pane_to_close)?;
+ let position_of_flexible_pane =
+ self.position_of_flexible_pane(&all_stacked_pane_positions)?;
+ let id_of_flexible_pane = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .map(|(pid, _p)| *pid)
+ .with_context(err_context)?;
+ let flexible_pane = panes
+ .get_mut(&id_of_flexible_pane)
+ .with_context(err_context)?;
+ let mut flexible_pane_position_and_size = flexible_pane.position_and_size();
+ flexible_pane_position_and_size
+ .rows
+ .set_inner(flexible_pane_position_and_size.rows.as_usize() + 1);
+ flexible_pane.set_geom(flexible_pane_position_and_size);
+ for (i, (pid, _position)) in all_stacked_pane_positions.iter().enumerate() {
+ if i > position_of_flexible_pane && i < position_of_current_pane {
+ let pane = panes.get_mut(pid).with_context(err_context)?;
+ let mut pane_position_and_size = pane.position_and_size();
+ pane_position_and_size.y += 1;
+ pane.set_geom(pane_position_and_size);
+ }
+ }
+ Ok(true)
+ }
+ fn fill_space_over_one_liner_pane_below_flexible_pane(&mut self, id: &PaneId) -> Result<bool> {
+ let err_context =
+ || format!("Failed to fill_space_over_one_liner_pane_below_flexible_pane");
+ let all_stacked_pane_positions = self.positions_in_stack(id)?;
+ let mut panes = self.panes.borrow_mut();
+ let pane_to_close = panes.get(id).with_context(err_context)?;
+ let position_of_current_pane =
+ self.position_of_current_pane(&all_stacked_pane_positions, &pane_to_close)?;
+ let position_of_flexible_pane =
+ self.position_of_flexible_pane(&all_stacked_pane_positions)?;
+ let id_of_flexible_pane = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .map(|(pid, _p)| *pid)
+ .with_context(err_context)?;
+ let flexible_pane = panes
+ .get_mut(&id_of_flexible_pane)
+ .with_context(err_context)?;
+ let mut flexible_pane_position_and_size = flexible_pane.position_and_size();
+ flexible_pane_position_and_size
+ .rows
+ .set_inner(flexible_pane_position_and_size.rows.as_usize() + 1);
+ flexible_pane.set_geom(flexible_pane_position_and_size);
+ for (i, (pid, _position)) in all_stacked_pane_positions.iter().enumerate() {
+ if i > position_of_current_pane && i <= position_of_flexible_pane {
+ let pane = panes.get_mut(pid).with_context(err_context)?;
+ let mut pane_position_and_size = pane.position_and_size();
+ pane_position_and_size.y = pane_position_and_size.y.saturating_sub(1);
+ pane.set_geom(pane_position_and_size);
+ }
+ }
+ Ok(true)
+ }
+ fn make_lowest_pane_in_stack_flexible(&mut self, destination_pane_id: &PaneId) -> Result<()> {
+ let err_context = || format!("Failed to make_lowest_pane_flexible");
+ let mut all_stacked_pane_positions = self.positions_in_stack(destination_pane_id)?;
+ let position_of_flexible_pane =
+ self.position_of_flexible_pane(&all_stacked_pane_positions)?;
+ if position_of_flexible_pane != all_stacked_pane_positions.len().saturating_sub(1) {
+ let mut panes = self.panes.borrow_mut();
+ let height_of_flexible_pane = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .map(|(_pid, p)| p.rows)
+ .with_context(err_context)?;
+ let (lowest_pane_id, mut lowest_pane_geom) = all_stacked_pane_positions
+ .last_mut()
+ .with_context(err_context)?;
+ lowest_pane_geom.rows = height_of_flexible_pane;
+ panes
+ .get_mut(lowest_pane_id)
+ .with_context(err_context)?
+ .set_geom(lowest_pane_geom);
+ let (flexible_pane_id, mut flexible_pane_geom) = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .with_context(err_context)?;
+ flexible_pane_geom.rows = Dimension::fixed(1);
+ panes
+ .get_mut(flexible_pane_id)
+ .with_context(err_context)?
+ .set_geom(flexible_pane_geom);
+ for (i, (pid, _position)) in all_stacked_pane_positions.iter().enumerate() {
+ if i > position_of_flexible_pane {
+ let pane = panes.get_mut(pid).with_context(err_context)?;
+ let mut pane_position_and_size = pane.position_and_size();
+ pane_position_and_size.y = pane_position_and_size
+ .y
+ .saturating_sub(height_of_flexible_pane.as_usize() - 1);
+ pane.set_geom(pane_position_and_size);
+ }
+ }
+ }
+ Ok(())
+ }
+ fn make_highest_pane_in_stack_flexible(&mut self, destination_pane_id: &PaneId) -> Result<()> {
+ let err_context = || format!("Failed to make_lowest_pane_flexible");
+ let mut all_stacked_pane_positions = self.positions_in_stack(destination_pane_id)?;
+ let position_of_flexible_pane =
+ self.position_of_flexible_pane(&all_stacked_pane_positions)?;
+ if position_of_flexible_pane != 0 {
+ let mut panes = self.panes.borrow_mut();
+ let height_of_flexible_pane = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .map(|(_pid, p)| p.rows)
+ .with_context(err_context)?;
+ let (highest_pane_id, mut highest_pane_geom) = all_stacked_pane_positions
+ .first_mut()
+ .with_context(err_context)?;
+ let y_of_whole_stack = highest_pane_geom.y;
+ highest_pane_geom.rows = height_of_flexible_pane;
+ panes
+ .get_mut(highest_pane_id)
+ .with_context(err_context)?
+ .set_geom(highest_pane_geom);
+ let (flexible_pane_id, mut flexible_pane_geom) = all_stacked_pane_positions
+ .iter()
+ .nth(position_of_flexible_pane)
+ .with_context(err_context)?;
+ flexible_pane_geom.rows = Dimension::fixed(1);
+ panes
+ .get_mut(flexible_pane_id)
+ .with_context(err_context)?
+ .set_geom(flexible_pane_geom);
+ for (i, (pid, _position)) in all_stacked_pane_positions.iter().enumerate() {
+ if i > 0 {
+ let pane = panes.get_mut(pid).with_context(err_context)?;
+ let mut pane_position_and_size = pane.position_and_size();
+ pane_position_and_size.y =
+ y_of_whole_stack + height_of_flexible_pane.as_usize() + (i - 1);
+ pane.set_geom(pane_position_and_size);
+ }
+ }
+ }
+ Ok(())
+ }
+}
diff --git a/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs b/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs
index e34164f9..8fc40d2b 100644
--- a/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs
+++ b/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs
@@ -1,5 +1,6 @@
use super::is_inside_viewport;
use super::pane_resizer::PaneResizer;
+use super::stacked_panes::StackedPanes;
use crate::tab::{MIN_TERMINAL_HEIGHT, MIN_TERMINAL_WIDTH};
use crate::{panes::PaneId, tab::Pane};
use std::cmp::Reverse;
@@ -49,42 +50,32 @@ impl<'a> TiledPaneGrid<'a> {
}
}
- /// Calculates an area for each pane and sums them all.
- ///
- /// Returns the product of "rows * columns", summed across all panes.
- #[cfg(debug_assertions)]
- fn total_panes_area(&self) -> f64 {
- let mut summed_area: f64 = 0.0;
-
- for pane in self.panes.clone().borrow().values() {
- let geom = pane.current_geom();
- summed_area += match (geom.rows.as_percent(), geom.cols.as_percent()) {
- (Some(rows), Some(cols)) => rows * cols,
- _ => continue,
- };
- }
-
- summed_area / (100.0 * 100.0)
- }
-
pub fn layout(&mut self, direction: SplitDirection, space: usize) -> Result<()> {
let mut pane_resizer = PaneResizer::new(self.panes.clone());
pane_resizer.layout(direction, space)
}
+ fn get_pane_geom(&self, pane_id: &PaneId) -> Option<PaneGeom> {
+ let panes = self.panes.borrow();
+ let pane_to_check = panes.get(pane_id)?;
+ let pane_geom = pane_to_check.current_geom();
+ if pane_geom.is_stacked {
+ StackedPanes::new(self.panes.clone()).position_and_size_of_stack(&pane_id)
+ } else {
+ Some(pane_geom)
+ }
+ }
fn pane_is_flexible(&self, direction: SplitDirection, pane_id: &PaneId) -> Result<bool> {
let err_context =
|| format!("failed to determine if pane {pane_id:?} is flexible in {direction:?}");
- let panes = self.panes.borrow();
- let pane_to_check = panes
- .get(pane_id)
+ let pane_geom = self
+ .get_pane_geom(pane_id)
.with_context(|| no_pane_id(pane_id))
.with_context(err_context)?;
- let geom = pane_to_check.current_geom();
Ok(!match direction {
- SplitDirection::Vertical => geom.rows,
- SplitDirection::Horizontal => geom.cols,
+ SplitDirection::Vertical => pane_geom.rows,
+ SplitDirection::Horizontal => pane_geom.cols,
}
.is_fixed())
}
@@ -99,12 +90,12 @@ impl<'a> TiledPaneGrid<'a> {
let neighbor_terminal_borders: HashSet<_> = if direction.is_horizontal() {
neighbor_terminals
.iter()
- .map(|t| self.panes.borrow().get(t).unwrap().y())
+ .filter_map(|t| self.get_pane_geom(t).map(|p| p.y))
.collect()
} else {
neighbor_terminals
.iter()
- .map(|t| self.panes.borrow().get(t).unwrap().x())
+ .filter_map(|t| self.get_pane_geom(t).map(|p| p.x))
.collect()
};
@@ -300,12 +291,12 @@ impl<'a> TiledPaneGrid<'a> {
let neighbor_terminal_borders: HashSet<_> = if direction.is_horizontal() {
neighbor_terminals
.iter()
- .map(|t| self.panes.borrow().get(t).unwrap().y())
+ .filter_map(|p| self.get_pane_geom(p).map(|p| p.y))
.collect()
} else {
neighbor_terminals
.iter()
- .map(|t| self.panes.borrow().get(t).unwrap().x())
+ .filter_map(|p| self.get_pane_geom(p).map(|p| p.x))
.collect()
};
@@ -408,34 +399,34 @@ impl<'a> TiledPaneGrid<'a> {
];
// For the borrow checker
{
- let panes = self.panes.borrow();
- let active_pane = panes
- .get(pane_id)
+ // let panes = self.panes.borrow();
+ let active_pane = self
+ .get_pane_geom(pane_id)
.with_context(|| no_pane_id(pane_id))
.with_context(err_context)?;
for p_id in self.viewport_pane_ids_directly_below(pane_id) {
- let pane = panes
- .get(&p_id)
+ let pane = self
+ .get_pane_geom(&p_id)
.with_context(|| no_pane_id(&p_id))
.with_context(err_context)?;
- if active_pane.x() + active_pane.cols() == pane.x() {
+ if active_pane.x + active_pane.cols.as_usize() == pane.x {
// right aligned
aligned_panes[0] = Some(p_id);
- } else if active_pane.x() == pane.x() + pane.cols() {
+ } else if active_pane.x == pane.x + pane.cols.as_usize() {
// left aligned
aligned_panes[1] = Some(p_id);
}
}
for p_id in self.viewport_pane_ids_directly_above(pane_id) {
- let pane = panes
- .get(&p_id)
+ let pane = self
+ .get_pane_geom(&p_id)
.with_context(|| no_pane_id(&p_id))
.with_context(err_context)?;
- if active_pane.x() + active_pane.cols() == pane.x() {
+ if active_pane.x + active_pane.cols.as_usize() == pane.x {
// right aligned
aligned_panes[2] = Some(p_id);
- } else if active_pane.x() == pane.x() + pane.cols() {
+ } else if active_pane.x == pane.x + pane.cols.as_usize() {
// left aligned
aligned_panes[3] = Some(p_id);
}
@@ -467,8 +458,15 @@ impl<'a> TiledPaneGrid<'a> {
..strategy
};
- if self.can_change_pane_size(pane_id, &main_strategy, change_by)?
- && self.can_change_pane_size(pane_id, &sub_strategy, change_by)?
+ // TODO: instead of unwrap_or(false) here we need to do the same with the fixed
+ // panes error above, only make sure that we only error if we cannot resize in
+ // any directions and have blocking fixed panes
+ if self
+ .can_change_pane_size(pane_id, &main_strategy, change_by)
+ .unwrap_or(false)
+ && self
+ .can_change_pane_size(pane_id, &sub_strategy, change_by)
+ .unwrap_or(false)
{
let result = self
.change_pane_size(pane_id, &main_strategy, change_by)
@@ -512,16 +510,6 @@ impl<'a> TiledPaneGrid<'a> {
return Ok(false);
}
- #[cfg(debug_assertions)]
- {
- let area = self.total_panes_area() * 100.0;
- debug_assert!(
- f64::abs(area - 100.0) < 1.0, // Tolerate a little rounding error
- "area consumed by panes doesn't fill the viewport! Total area is {area} %
- During operation: '{strategy}', on pane {pane_id:?}",
- );
- }
-
Ok(true)
}
@@ -529,16 +517,15 @@ impl<'a> TiledPaneGrid<'a> {
let err_context =
|| format!("failed to determine if pane {pane_id:?} can reduce width by {reduce_by} %");
- let panes = self.panes.borrow();
- let pane = panes
- .get(pane_id)
+ let pane = self
+ .get_pane_geom(pane_id)
.with_context(|| no_pane_id(pane_id))
.with_context(err_context)?;
- let current_fixed_cols = pane.position_and_size().cols.as_usize();
+ let current_fixed_cols = pane.cols.as_usize();
let will_reduce_by = ((self.display_area.cols as f64 / 100.0) * reduce_by) as usize;
- if current_fixed_cols.saturating_sub(will_reduce_by) < pane.min_width() {
+ if current_fixed_cols.saturating_sub(will_reduce_by) < MIN_TERMINAL_WIDTH {
Ok(false)
- } else if let Some(cols) = pane.position_and_size().cols.as_percent() {
+ } else if let Some(cols) = pane.cols.as_percent() {
Ok(cols - reduce_by >= RESIZE_PERCENT)
} else {
Ok(false)
@@ -549,16 +536,20 @@ impl<'a> TiledPaneGrid<'a> {
format!("failed to determine if pane {pane_id:?} can reduce height by {reduce_by} %")
};
- let panes = self.panes.borrow();
- let pane = panes
- .get(pane_id)
+ let pane = self
+ .get_pane_geom(pane_id)
.with_context(|| no_pane_id(pane_id))
.with_context(err_context)?;
- let current_fixed_rows = pane.position_and_size().rows.as_usize();
+ let min_terminal_height = if pane.is_stacked {
+ StackedPanes::new(self.panes.clone()).min_stack_height(pane_id)?
+ } else {
+ MIN_TERMINAL_HEIGHT
+ };
+ let current_fixed_rows = pane.rows.as_usize();
let will_reduce_by = ((self.display_area.rows as f64 / 100.0) * reduce_by) as usize;
- if current_fixed_rows.saturating_sub(will_reduce_by) < pane.min_height() {
+ if current_fixed_rows.saturating_sub(will_reduce_by) < min_terminal_height {
Ok(false)
- } else if let Some(rows) = pane.position_and_size().rows.as_percent() {
+ } else if let Some(rows) = pane.rows.as_percent() {
Ok(rows - reduce_by >= RESIZE_PERCENT)
} else {
Ok(false)
@@ -567,26 +558,70 @@ impl<'a> TiledPaneGrid<'a> {
fn reduce_pane_height(&mut self, id: &PaneId, percent: f64) {
if self.can_reduce_pane_height(id, percent).unwrap() {
- let mut panes = self.panes.borrow_mut();
- let terminal = panes.get_mut(id).unwrap();
- terminal.reduce_height(percent);
+ let current_pane_is_stacked = self
+ .panes
+ .borrow()
+ .get(id)
+ .unwrap()
+ .current_geom()
+ .is_stacked;
+ if current_pane_is_stacked {
+ let _ = StackedPanes::new(self.panes.clone()).reduce_stack_height(&id, percent);
+ } else {
+ let mut panes = self.panes.borrow_mut();
+ let terminal = panes.get_mut(id).unwrap();
+ terminal.reduce_height(percent);
+ }
}
}
fn increase_pane_height(&mut self, id: &PaneId, percent: f64) {
- let mut panes = self.panes.borrow_mut();
- let terminal = panes.get_mut(id).unwrap();
- terminal.increase_height(percent);
+ let current_pane_is_stacked = self
+ .panes
+ .borrow()
+ .get(id)
+ .unwrap()
+ .current_geom()
+ .is_stacked;
+ if current_pane_is_stacked {
+ let _ = StackedPanes::new(self.panes.clone()).increase_stack_height(&id, percent);
+ } else {
+ let mut panes = self.panes.borrow_mut();
+ let terminal = panes.get_mut(id).unwrap();
+ terminal.increase_height(percent);
+ }
}
fn increase_pane_width(&mut self, id: &PaneId, percent: f64) {
- let mut panes = self.panes.borrow_mut();
- let terminal = panes.get_mut(id).unwrap();
- terminal.increase_width(percent);
+ let current_pane_is_stacked = self
+ .panes
+ .borrow()
+ .get(id)
+ .unwrap()
+ .current_geom()
+ .is_stacked;
+ if current_pane_is_stacked {
+ let _ = StackedPanes::new(self.panes.clone()).increase_stack_width(&id, percent);
+ } else {
+ let mut panes = self.panes.borrow_mut();
+ let pane = panes.get_mut(id).unwrap();
+ pane.increase_width(percent);
+ }
}
fn reduce_pane_width(&mut self, id: &PaneId, percent: f64) {
if self.can_reduce_pane_width(id, percent).unwrap() {
- let mut panes = self.panes.borrow_mut();
- let terminal = panes.get_mut(id).unwrap();
- terminal.reduce_width(percent);
+ let current_pane_is_stacked = self
+ .panes
+ .borrow()
+ .get(id)
+ .unwrap()
+ .current_geom()
+ .is_stacked;
+ if current_pane_is_stacked {
+ let _ = StackedPanes::new(self.panes.clone()).reduce_stack_width(&id, percent);
+ } else {
+ let mut panes = self.panes.borrow_mut();
+ let terminal = panes.get_mut(id).unwrap();
+ terminal.reduce_width(percent);
+ }
}
}
@@ -597,27 +632,38 @@ impl<'a> TiledPaneGrid<'a> {
fn pane_ids_directly_next_to(&self, id: &PaneId, direction: &Direction) -> Result<Vec<PaneId>> {
let err_context = || format!("failed to find panes {direction} from pane {id:?}");
- let panes = self.panes.borrow();
let mut ids = vec![];
- let terminal_to_check = panes
- .get(id)
+ let pane_geom_to_check = self
+ .get_pane_geom(id)
.with_context(|| no_pane_id(id))
.with_context(err_context)?;
- for (&pid, terminal) in panes.iter() {
+ let panes = self.panes.borrow();
+ let mut seen = HashSet::new();
+ for pid in panes.keys() {
+ let pane = self
+ .get_pane_geom(pid)
+ .with_context(|| no_pane_id(id))
+ .with_context(err_context)?;
+ if seen.contains(&pane) {
+ continue;
+ } else {
+ seen.insert(pane);
+ }
if match direction {
- Direction::Left => (terminal.x() + terminal.cols()) == terminal_to_check.x(),
+ Direction::Left => (pane.x + pane.cols.as_usize()) == pane_geom_to_check.x,
Direction::Down => {
- terminal.y() == (terminal_to_check.y() + terminal_to_check.rows())
+ pane.y == (pane_geom_to_check.y + pane_geom_to_check.rows.as_usize())
},
- Direction::Up => (terminal.y() + terminal.rows()) == terminal_to_check.y(),
+ Direction::Up => (pane.y + pane.rows.as_usize()) == pane_geom_to_check.y,
Direction::Right => {
- terminal.x() == (terminal_to_check.x() + terminal_to_check.cols())
+ pane.x == (pane_geom_to_check.x + pane_geom_to_check.cols.as_usize())
},
} {
- ids.push(pid);
+ ids.push(*pid);
}
}
+
Ok(ids)
}
@@ -629,29 +675,38 @@ impl<'a> TiledPaneGrid<'a> {
) -> Result<Vec<PaneId>> {
let err_context = || format!("failed to find panes aligned {direction} with {pane_id:?}");
- let panes = self.panes.borrow();
- let pane_to_check = panes
- .get(pane_id)
+ let pane_to_check = self
+ .get_pane_geom(pane_id)
.with_context(|| no_pane_id(pane_id))
.with_context(err_context)?;
let mut result = vec![];
- for (p_id, pane) in panes.iter() {
- if p_id == pane_id {
+ let panes = self.panes.borrow();
+ let mut seen = HashSet::new();
+ for (pid, _pane) in panes.iter() {
+ let pane = self
+ .get_pane_geom(pid)
+ .with_context(|| no_pane_id(pane_id))
+ .with_context(err_context)?;
+ if seen.contains(&pane) || pid == pane_id {
continue;
+ } else {
+ seen.insert(pane);
}
if match direction {
- Direction::Left => pane.x() == pane_to_check.x(),
+ Direction::Left => pane.x == pane_to_check.x,
Direction::Down => {
- (pane.y() + pane.rows()) == (pane_to_check.y() + pane_to_check.rows())
+ (pane.y + pane.rows.as_usize())
+ == (pane_to_check.y + pane_to_check.rows.as_usize())
},
- Direction::Up => pane.y() == pane_to_check.y(),
+ Direction::Up => pane.y == pane_to_check.y,
Direction::Right => {
- (pane.x() + pane.cols()) == (pane_to_check.x() + pane_to_check.cols())
+ (pane.x + pane.cols.as_usize())
+ == (pane_to_check.x + pane_to_check.cols.as_usize())
},
} {
- result.push(*p_id)
+ result.push(*pid)
}
}
Ok(result)
@@ -671,9 +726,8 @@ impl<'a> TiledPaneGrid<'a> {
let input_error =
anyhow!("Invalid combination of alignment ({alignment}) and direction ({direction})");
- let panes = self.panes.borrow();
- let pane_to_check = panes
- .get(id)
+ let pane_to_check = self
+ .get_pane_geom(id)
.with_context(|| no_pane_id(id))
.with_context(err_context)?;
let mut result = vec![];
@@ -682,7 +736,7 @@ impl<'a> TiledPaneGrid<'a> {
.and_then(|pane_ids| {
Ok(pane_ids
.iter()
- .map(|p_id| panes.get(p_id).unwrap()) // <-- TODO: Bad unwrap!
+ .filter_map(|p_id| self.get_pane_geom(p_id).map(|pane_geom| (*p_id, pane_geom)))
.collect())
})
.with_context(err_context)?;
@@ -693,23 +747,26 @@ impl<'a> TiledPaneGrid<'a> {
use Direction::Up as U;
match (alignment, direction) {
- (&R, &U) | (&L, &U) => aligned_panes.sort_by_key(|a| Reverse(a.y())),
- (&R, &D) | (&L, &D) => aligned_panes.sort_by_key(|a| a.y()),
- (&D, &L) | (&U, &L) => aligned_panes.sort_by_key(|a| Reverse(a.x())),
- (&D, &R) | (&U, &R) => aligned_panes.sort_by_key(|a| a.x()),
+ (&R, &U) | (&L, &U) => aligned_panes.sort_by_key(|(_, a)| Reverse(a.y)),
+ (&R, &D) | (&L, &D) => aligned_panes.sort_by_key(|(_, a)| a.y),
+ (&D, &L) | (&U, &L) => aligned_panes.sort_by_key(|(_, a)| Reverse(a.x)),
+ (&D, &R) | (&U, &R) => aligned_panes.sort_by_key(|(_, a)| a.x),
_ => return Err(input_error).with_context(err_context),
};
- for pane in aligned_panes {
- let pane_to_check = result.last().unwrap_or(&pane_to_check);
+ for (pid, pane) in aligned_panes {
+ let pane_to_check = result
+ .last()
+ .map(|(_pid, pane)| pane)
+ .unwrap_or(&pane_to_check);
if match (alignment, direction) {
- (&R, &U) | (&L, &U) => (pane.y() + pane.rows()) == pane_to_check.y(),
- (&R, &D) | (&L, &D) => pane.y() == (pane_to_check.y() + pane_to_check.rows()),
- (&D, &L) | (&U, &L) => (pane.x() + pane.cols()) == pane_to_check.x(),
- (&D, &R) | (&U, &R) => pane.x() == (pane_to_check.x() + pane_to_check.cols()),
+ (&R, &U) | (&L, &U) => (pane.y + pane.rows.as_usize()) == pane_to_check.y,
+ (&R, &D) | (&L, &D) => pane.y == (pane_to_check.y + pane_to_check.rows.as_usize()),
+ (&D, &L) | (&U, &L) => (pane.x + pane.cols.as_usize()) == pane_to_check.x,
+ (&D, &R) | (&U, &R) => pane.x == (pane_to_check.x + pane_to_check.cols.as_usize()),
_ => return Err(input_error).with_context(err_context),
} {
- result.push(pane);
+ result.push((pid, pane));
}
}
@@ -720,12 +777,12 @@ impl<'a> TiledPaneGrid<'a> {
&R => self.viewport.x + self.viewport.cols,
};
- for pane in &result {
+ for (_, pane) in &result {
let pane_boundary = match direction {
- &L => pane.x() + pane.cols(),
- &D => pane.y(),
- &U => pane.y() + pane.rows(),
- &R => pane.x(),
+ &L => pane.x + pane.cols.as_usize(),
+ &D => pane.y,
+ &U => pane.y + pane.rows.as_usize(),
+ &R => pane.x,
};
if border.get(&pane_boundary).is_some() {
match direction {
@@ -742,24 +799,24 @@ impl<'a> TiledPaneGrid<'a> {
}
}
}
- result.retain(|pane| match direction {
- &L => pane.x() >= resize_border,
- &D => (pane.y() + pane.rows()) <= resize_border,
- &U => pane.y() >= resize_border,
- &R => (pane.x() + pane.cols()) <= resize_border,
+ result.retain(|(_pid, pane)| match direction {
+ &L => pane.x >= resize_border,
+ &D => (pane.y + pane.rows.as_usize()) <= resize_border,
+ &U => pane.y >= resize_border,
+ &R => (pane.x + pane.cols.as_usize()) <= resize_border,
});
let resize_border = if result.is_empty() {
match direction {
- &L => pane_to_check.x(),
- &D => pane_to_check.y() + pane_to_check.rows(),
- &U => pane_to_check.y(),
- &R => pane_to_check.x() + pane_to_check.cols(),
+ &L => pane_to_check.x,
+ &D => pane_to_check.y + pane_to_check.rows.as_usize(),
+ &U => pane_to_check.y,
+ &R => pane_to_check.x + pane_to_check.cols.as_usize(),
}
} else {
resize_border
};
- let pane_ids: Vec<PaneId> = result.iter().map(|t| t.pid()).collect();
+ let pane_ids: Vec<PaneId> = result.iter().map(|(pid, _t)| *pid).collect();
Ok((resize_border, pane_ids))
}
@@ -770,9 +827,8 @@ impl<'a> TiledPaneGrid<'a> {
left_border_x: usize,
right_border_x: usize,
) -> bool {
- let panes = self.panes.borrow();
- let pane = panes.get(id).unwrap();
- pane.x() >= left_border_x && pane.x() + pane.cols() <= right_border_x
+ let pane = self.get_pane_geom(id).unwrap();
+ pane.x >= left_border_x && pane.x + pane.cols.as_usize() <= right_border_x
}
fn pane_is_between_horizontal_borders(
@@ -781,9 +837,8 @@ impl<'a> TiledPaneGrid<'a> {
top_border_y: usize,
bottom_border_y: usize,
) -> bool {
- let panes = self.panes.borrow();
- let pane = panes.get(id).unwrap();
- pane.y() >= top_border_y && pane.y() + pane.rows() <= bottom_border_y
+ let pane = self.get_pane_geom(id).unwrap();
+ pane.y >= top_border_y && pane.y + pane.rows.as_usize() <= bottom_border_y
}
fn viewport_pane_ids_directly_above(&self, pane_id: &PaneId) -> Vec<PaneId> {
@@ -863,7 +918,7 @@ impl<'a> TiledPaneGrid<'a> {
.filter(|(_, p)| p.selectable())
.map(|(p_id, p)| (*p_id, p))
.collect();
- let next_index = panes
+ let next_pane = panes
.iter()
.enumerate()
.filter(|(_, (_, c))| {
@@ -871,9 +926,83 @@ impl<'a> TiledPaneGrid<'a> {
&& c.horizontally_overlaps_with(Box::as_ref(current_pane))
})
.max_by_key(|(_, (_, c))| c.active_at())
- .map(|(_, (pid, _))| pid)
- .copied();
- next_index
+ .map(|(_, (_, pane))| pane);
+ let next_pane_is_stacked = next_pane
+ .map(|p| p.current_geom().is_stacked)
+ .unwrap_or(false);
+ if next_pane_is_stacked {
+ if let Some(next_pane_id) = next_pane.map(|p| p.pid()) {
+ return StackedPanes::new(self.panes.clone())
+ .flexible_pane_id_in_stack(&next_pane_id);
+ }
+ }
+ next_pane.map(|p| p.pid())
+ }
+ pub fn progress_stack_up_if_in_stack(&mut self, source_pane_id: &PaneId) -> Option<PaneId> {
+ let destination_pane_id_in_stack = {
+ let panes = self.panes.borrow();
+ let source_pane = panes.get(source_pane_id)?;
+ let pane_list: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes
+ .iter()
+ .filter(|(_, p)| p.selectable())
+ .map(|(p_id, p)| (*p_id, p))
+ .collect();
+ let destination_pane_id = pane_list
+ .iter()
+ .enumerate()
+ .filter(|(_, (_, c))| {
+ c.is_directly_above(Box::as_ref(source_pane))
+ && c.vertically_overlaps_with(Box::as_ref(source_pane))
+ && c.current_geom().is_stacked
+ })
+ .max_by_key(|(_, (_, c))| c.active_at())
+ .map(|(_, (pid, _))| pid)
+ .copied();
+ destination_pane_id
+ };
+
+ match destination_pane_id_in_stack {
+ Some(destination_pane_id) => {
+ StackedPanes::new(self.panes.clone())
+ .move_up(source_pane_id, &destination_pane_id)
+ .ok()?;
+ Some(destination_pane_id)
+ },
+ None => None,
+ }
+ }
+ pub fn progress_stack_down_if_in_stack(&mut self, source_pane_id: &PaneId) -> Option<PaneId> {
+ let destination_pane_id_in_stack = {
+ let panes = self.panes.borrow();
+ let source_pane = panes.get(source_pane_id)?;
+ let pane_list: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes
+ .iter()
+ .filter(|(_, p)| p.selectable())
+ .map(|(p_id, p)| (*p_id, p))
+ .collect();
+ let destination_pane_id = pane_list
+ .iter()
+ .enumerate()
+ .filter(|(_, (_, c))| {
+ c.is_directly_below(Box::as_ref(source_pane))
+ && c.vertically_overlaps_with(Box::as_ref(source_pane))
+ && c.current_geom().is_stacked
+ })
+ .max_by_key(|(_, (_, c))| c.active_at())
+ .map(|(_, (pid, _))| pid)
+ .copied();
+ destination_pane_id
+ };
+
+ match destination_pane_id_in_stack {
+ Some(destination_pane_id) => {
+ StackedPanes::new(self.panes.clone())
+ .move_down(source_pane_id, &destination_pane_id)
+ .ok()?;
+ Some(destination_pane_id)
+ },
+ None => None,
+ }
}
pub fn next_selectable_pane_id_below(&self, current_pane_id: &PaneId) -> Option<PaneId> {
let panes = self.panes.borrow();
@@ -889,6 +1018,7 @@ impl<'a> TiledPaneGrid<'a> {
.filter(|(_, (_, c))| {
c.is_directly_below(Box::as_ref(current_pane))
&& c.vertically_overlaps_with(Box::as_ref(current_pane))
+ && !c.current_geom().is_stacked
})
.max_by_key(|(_, (_, c))| c.active_at())
.map(|(_, (pid, _))| pid)
@@ -909,6 +1039,7 @@ impl<'a> TiledPaneGrid<'a> {
.filter(|(_, (_, c))| {
c.is_directly_above(Box::as_ref(current_pane))
&& c.vertically_overlaps_with(Box::as_ref(current_pane))
+ && !c.current_geom().is_stacked
})
.max_by_key(|(_, (_, c))| c.active_at())
.map(|(_, (pid, _))| pid)
@@ -923,7 +1054,7 @@ impl<'a> TiledPaneGrid<'a> {
.filter(|(_, p)| p.selectable())
.map(|(p_id, p)| (*p_id, p))
.collect();
- let next_index = panes
+ let next_pane = panes
.iter()
.enumerate()
.filter(|(_, (_, c))| {
@@ -931,16 +1062,33 @@ impl<'a> TiledPaneGrid<'a> {
&& c.horizontally_overlaps_with(Box::as_ref(current_pane))
})
.max_by_key(|(_, (_, c))| c.active_at())
- .map(|(_, (pid, _))| pid)
+ .map(|(_, (_pid, pane))| pane)
.copied();
- next_index
+ let next_pane_is_stacked = next_pane
+ .map(|p| p.current_geom().is_stacked)
+ .unwrap_or(false);
+ if next_pane_is_stacked {
+ if let Some(next_pane_id) = next_pane.map(|p| p.pid()) {
+ return StackedPanes::new(self.panes.clone())
+ .flexible_pane_id_in_stack(&next_pane_id);
+ }
+ }
+ next_pane.map(|p| p.pid())
}
fn horizontal_borders(&self, pane_ids: &[PaneId]) -> HashSet<usize> {
pane_ids.iter().fold(HashSet::new(), |mut borders, p| {
let panes = self.panes.borrow();
let pane = panes.get(p).unwrap();
- borders.insert(pane.y());
- borders.insert(pane.y() + pane.rows());
+ if pane.current_geom().is_stacked {
+ let pane_geom = StackedPanes::new(self.panes.clone())
+ .position_and_size_of_stack(&pane.pid())
+ .unwrap();
+ borders.insert(pane_geom.y);
+ borders.insert(pane_geom.y + pane_geom.rows.as_usize());
+ } else {
+ borders.insert(pane.y());
+ borders.insert(pane.y() + pane.rows());
+ }
borders
})
}
@@ -1098,14 +1246,23 @@ impl<'a> TiledPaneGrid<'a> {
pub fn fill_space_over_pane(&mut self, id: PaneId) -> bool {
// true => successfully filled space over pane
// false => didn't succeed, so didn't do anything
- let (freed_width, freed_height) = {
+ let (freed_width, freed_height, pane_to_close_is_stacked) = {
let panes = self.panes.borrow_mut();
let pane_to_close = panes.get(&id).unwrap();
let freed_space = pane_to_close.position_and_size();
let freed_width = freed_space.cols.as_percent();
let freed_height = freed_space.rows.as_percent();
- (freed_width, freed_height)
+ let pane_to_close_is_stacked = pane_to_close.current_geom().is_stacked;
+ (freed_width, freed_height, pane_to_close_is_stacked)
};
+ if pane_to_close_is_stacked {
+ let successfully_filled_space = StackedPanes::new(self.panes.clone())
+ .fill_space_over_pane_in_stack(&id)
+ .unwrap_or(false);
+ if successfully_filled_space {
+ return true;
+ }
+ }
if let (Some(freed_width), Some(freed_height)) = (freed_width, freed_height) {
if let Some((panes_to_grow, direction)) = self.find_panes_to_grow(id) {
self.grow_panes(&panes_to_grow, direction, (freed_width, freed_height));
@@ -1126,8 +1283,10 @@ impl<'a> TiledPaneGrid<'a> {
cursor_height_width_ratio: Option<usize>,
) -> Option<(PaneId, SplitDirection)> {
let panes = self.panes.borrow();
- let pane_sequence: Vec<(&PaneId, &&mut Box<dyn Pane>)> =
- panes.iter().filter(|(_, p)| p.selectable()).collect();
+ let pane_sequence: Vec<(&PaneId, &&mut Box<dyn Pane>)> = panes
+ .iter()
+ .filter(|(_, p)| p.selectable() && !p.current_geom().is_stacked)
+ .collect();
let (_largest_pane_size, pane_id_to_split) = pane_sequence.iter().fold(
(0, None),
|(current_largest_pane_size, current_pane_id_to_split), id_and_pane_to_check| {
diff --git a/zellij-server/src/panes/unit/search_in_pane_tests.rs b/zellij-server/src/panes/unit/search_in_pane_tests.rs
index fb03b491..7e10e5f9 100644
--- a/zellij-server/src/panes/unit/search_in_pane_tests.rs
+++ b/zellij-server/src/panes/unit/search_in_pane_tests.rs
@@ -40,6 +40,7 @@ fn create_pane() -> TerminalPane {
Rc::new(RefCell::new(Palette::default())),
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
let content = read_fixture();
terminal_pane.handle_pty_bytes(content);
diff --git a/zellij-server/src/panes/unit/terminal_pane_tests.rs b/zellij-server/src/panes/unit/terminal_pane_tests.rs
index 744d2e90..291d65eb 100644
--- a/zellij-server/src/panes/unit/terminal_pane_tests.rs
+++ b/zellij-server/src/panes/unit/terminal_pane_tests.rs
@@ -48,6 +48,7 @@ pub fn scrolling_inside_a_pane() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
let mut text_to_fill_pane = String::new();
for i in 0..30 {
@@ -89,6 +90,7 @@ pub fn sixel_image_inside_terminal_pane() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
let sixel_image_bytes = "\u{1b}Pq
#0;2;0;0;0#1;2;100;100;0#2;2;0;100;0
@@ -130,6 +132,7 @@ pub fn partial_sixel_image_inside_terminal_pane() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
let pane_content = read_fixture("sixel-image-500px.six");
terminal_pane.handle_pty_bytes(pane_content);
@@ -165,6 +168,7 @@ pub fn overflowing_sixel_image_inside_terminal_pane() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
let pane_content = read_fixture("sixel-image-500px.six");
terminal_pane.handle_pty_bytes(pane_content);
@@ -199,6 +203,7 @@ pub fn scrolling_through_a_sixel_image() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
let mut text_to_fill_pane = String::new();
for i in 0..30 {
@@ -244,6 +249,7 @@ pub fn multiple_sixel_images_in_pane() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
let mut text_to_fill_pane = String::new();
for i in 0..5 {
@@ -287,6 +293,7 @@ pub fn resizing_pane_with_sixel_images() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
let mut text_to_fill_pane = String::new();
for i in 0..5 {
@@ -333,6 +340,7 @@ pub fn changing_character_cell_size_with_sixel_images() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
let mut text_to_fill_pane = String::new();
for i in 0..5 {
@@ -384,6 +392,7 @@ pub fn keep_working_after_corrupted_sixel_image() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
let sixel_image_bytes = "\u{1b}PI AM CORRUPTED BWAHAHAq
@@ -433,6 +442,7 @@ pub fn pane_with_frame_position_is_on_frame() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
terminal_pane.set_content_offset(Offset::frame(1));
@@ -518,6 +528,7 @@ pub fn pane_with_bottom_and_right_borders_position_is_on_frame() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
terminal_pane.set_content_offset(Offset::shift(1, 1));
@@ -603,6 +614,7 @@ pub fn frameless_pane_position_is_on_frame() {
terminal_emulator_colors,
terminal_emulator_color_codes,
None,
+ None,
); // 0 is the pane index
terminal_pane.set_content_offset(Offset::default());
diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs
index ba46a545..48d6e3a1 100644
--- a/zellij-server/src/plugins/mod.rs
+++ b/zellij-server/src/plugins/mod.rs
@@ -12,7 +12,7 @@ use zellij_utils::{
errors::{prelude::*, ContextType, PluginContext},
input::{
command::TerminalAction,
- layout::{FloatingPanesLayout, Layout, PaneLayout, Run, RunPlugin, RunPluginLocation},
+ layout::{FloatingPaneLayout, Layout, Run, RunPlugin, RunPluginLocation, TiledPaneLayout},
plugins::PluginsConfig,
},
pane_size::Size,
@@ -28,8 +28,8 @@ pub enum PluginInstruction {
RemoveClient(ClientId),
NewTab(
Option<TerminalAction>,
- Option<PaneLayout>,
- Vec<FloatingPanesLayout>,
+ Option<TiledPaneLayout>,
+ Vec<FloatingPaneLayout>,
Option<String>, // tab name
usize, // tab_index
ClientId,
@@ -102,6 +102,11 @@ pub(crate) fn plugin_thread_main(
.unwrap_or_else(|| layout.new_tab().0)
.extract_run_instructions();
let size = Size::default();
+ let floating_panes_layout = if floating_panes_layout.is_empty() {
+ layout.new_tab().1
+ } else {
+ floating_panes_layout
+ };
let mut extracted_floating_plugins: Vec<Option<Run>> = floating_panes_layout
.iter()
.map(|f| f.run.clone())
diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs
index f1b0735a..fd67234c 100644
--- a/zellij-server/src/pty.rs
+++ b/zellij-server/src/pty.rs
@@ -15,7 +15,7 @@ use zellij_utils::{
errors::{ContextType, PtyContext},
input::{
command::{RunCommand, TerminalAction},
- layout::{FloatingPanesLayout, Layout, PaneLayout, Run, RunPluginLocation},
+ layout::{FloatingPaneLayout, Layout, Run, RunPluginLocation, TiledPaneLayout},
},
};
@@ -49,8 +49,8 @@ pub enum PtyInstruction {
GoToTab(TabIndex, ClientId),
NewTab(
Option<TerminalAction>,
- Option<PaneLayout>,
- Vec<FloatingPanesLayout>,
+ Option<TiledPaneLayout>,
+ Vec<FloatingPaneLayout>,
Option<String>,
usize, // tab_index
HashMap<RunPluginLocation, Vec<u32>>, // plugin_ids
@@ -575,8 +575,8 @@ impl Pty {
}
pub fn spawn_terminals_for_layout(
&mut self,
- layout: PaneLayout,
- floating_panes_layout: Vec<FloatingPanesLayout>,
+ layout: TiledPaneLayout,
+ floating_panes_layout: Vec<FloatingPaneLayout>,
default_shell: Option<TerminalAction>,
plugin_ids: HashMap<RunPluginLocation, Vec<u32>>,
tab_index: usize,
diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs
index dce1c9ac..3de62c09 100644
--- a/zellij-server/src/route.rs
+++ b/zellij-server/src/route.rs
@@ -165,6 +165,12 @@ pub(crate) fn route_action(
.send_to_screen(screen_instr)
.with_context(err_context)?;
},
+ Action::MovePaneBackwards => {
+ session
+ .senders
+ .send_to_screen(ScreenInstruction::MovePaneBackwards(client_id))
+ .with_context(err_context)?;
+ },
Action::DumpScreen(val, full) => {
session
.senders
@@ -436,8 +442,18 @@ pub(crate) fn route_action(
.send_to_screen(ScreenInstruction::CloseFocusedPane(client_id))
.with_context(err_context)?;
},
- Action::NewTab(tab_layout, floating_panes_layout, tab_name) => {
+ Action::NewTab(
+ tab_layout,
+ floating_panes_layout,
+ swap_tiled_layouts,
+ swap_floating_layouts,
+ tab_name,
+ ) => {
let shell = session.default_shell.clone();
+ let swap_tiled_layouts =
+ swap_tiled_layouts.unwrap_or_else(|| session.layout.swap_tiled_layouts.clone());
+ let swap_floating_layouts = swap_floating_layouts
+ .unwrap_or_else(|| session.layout.swap_floating_layouts.clone());
session
.senders
.send_to_screen(ScreenInstruction::NewTab(
@@ -445,6 +461,7 @@ pub(crate) fn route_action(
tab_layout,
floating_panes_layout,
tab_name,
+ (swap_tiled_layouts, swap_floating_layouts),
client_id,
))
.with_context(err_context)?;
@@ -480,10 +497,13 @@ pub(crate) fn route_action(
.with_context(err_context)?;
},
Action::GoToTabName(name, create) => {
+ let swap_tiled_layouts = session.layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = session.layout.swap_floating_layouts.clone();
session
.senders
.send_to_screen(ScreenInstruction::GoToTabName(
name,
+ (swap_tiled_layouts, swap_floating_layouts),
create,
Some(client_id),
))
@@ -626,6 +646,18 @@ pub(crate) fn route_action(
.with_context(err_context)?;
},
Action::ToggleMouseMode => {}, // Handled client side
+ Action::PreviousSwapLayout => {
+ session
+ .senders
+ .send_to_screen(ScreenInstruction::PreviousSwapLayout(client_id))
+ .with_context(err_context)?;
+ },
+ Action::NextSwapLayout => {
+ session
+ .senders
+ .send_to_screen(ScreenInstruction::NextSwapLayout(client_id))
+ .with_context(err_context)?;
+ },
}
Ok(should_break)
}
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index 9a196f35..a91354ee 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -12,7 +12,9 @@ use zellij_utils::input::options::Clipboard;
use zellij_utils::pane_size::{Size, SizeInPixels};
use zellij_utils::{
input::command::TerminalAction,
- input::layout::{FloatingPanesLayout, PaneLayout, RunPluginLocation},
+ input::layout::{
+ FloatingPaneLayout, RunPluginLocation, SwapFloatingLayout, SwapTiledLayout, TiledPaneLayout,
+ },
position::Position,
};
@@ -149,6 +151,7 @@ pub enum ScreenInstruction {
MoveFocusRight(ClientId),
MoveFocusRightOrNextTab(ClientId),
MovePane(ClientId),
+ MovePaneBackwards(ClientId),
MovePaneUp(ClientId),
MovePaneDown(ClientId),
MovePaneRight(ClientId),
@@ -177,14 +180,15 @@ pub enum ScreenInstruction {
UndoRenamePane(ClientId),
NewTab(
Option<TerminalAction>,
- Option<PaneLayout>,
- Vec<FloatingPanesLayout>,
+ Option<TiledPaneLayout>,
+ Vec<FloatingPaneLayout>,
Option<String>,
+ (Vec<SwapTiledLayout>, Vec<SwapFloatingLayout>), // swap layouts
ClientId,
),
ApplyLayout(
- PaneLayout,
- Vec<FloatingPanesLayout>,
+ TiledPaneLayout,
+ Vec<FloatingPaneLayout>,
Vec<(u32, HoldForCommand)>, // new pane pids
Vec<(u32, HoldForCommand)>, // new floating pane pids
HashMap<RunPluginLocation, Vec<u32>>,
@@ -196,7 +200,12 @@ pub enum ScreenInstruction {
ToggleActiveSyncTab(ClientId),
CloseTab(ClientId),
GoToTab(u32, Option<ClientId>), // this Option is a hacky workaround, please do not copy this behaviour
- GoToTabName(String, bool, Option<ClientId>),
+ GoToTabName(
+ String,
+ (Vec<SwapTiledLayout>, Vec<SwapFloatingLayout>), // swap layouts
+ bool,
+ Option<ClientId>,
+ ),
ToggleTab(ClientId),
UpdateTabName(Vec<u8>, ClientId),
UndoRenameTab(ClientId),
@@ -231,6 +240,8 @@ pub enum ScreenInstruction {
SearchToggleWrap(ClientId),
AddRedPaneFrameColorOverride(Vec<PaneId>, Option<String>), // Option<String> => optional error text
ClearPaneFrameColorOverride(Vec<PaneId>),
+ PreviousSwapLayout(ClientId),
+ NextSwapLayout(ClientId),
}
impl From<&ScreenInstruction> for ScreenContext {
@@ -286,6 +297,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenContext::MoveFocusRightOrNextTab
},
ScreenInstruction::MovePane(..) => ScreenContext::MovePane,
+ ScreenInstruction::MovePaneBackwards(..) => ScreenContext::MovePaneBackwards,
ScreenInstruction::MovePaneDown(..) => ScreenContext::MovePaneDown,
ScreenInstruction::MovePaneUp(..) => ScreenContext::MovePaneUp,
ScreenInstruction::MovePaneRight(..) => ScreenContext::MovePaneRight,
@@ -370,6 +382,8 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::ClearPaneFrameColorOverride(..) => {
ScreenContext::ClearPaneFrameColorOverride
},
+ ScreenInstruction::PreviousSwapLayout(..) => ScreenContext::PreviousSwapLayout,
+ ScreenInstruction::NextSwapLayout(..) => ScreenContext::NextSwapLayout,
}
}
}
@@ -430,6 +444,7 @@ pub(crate) struct Screen {
default_mode_info: ModeInfo, // TODO: restructure ModeInfo to prevent this duplication
style: Style,
draw_pane_frames: bool,
+ auto_layout: bool,
session_is_mirrored: bool,
copy_options: CopyOptions,
}
@@ -442,6 +457,7 @@ impl Screen {
max_panes: Option<usize>,
mode_info: ModeInfo,
draw_pane_frames: bool,
+ auto_layout: bool,
session_is_mirrored: bool,
copy_options: CopyOptions,
) -> Self {
@@ -463,6 +479,7 @@ impl Screen {
mode_info: BTreeMap::new(),
default_mode_info: mode_info,
draw_pane_frames,
+ auto_layout,
session_is_mirrored,
copy_options,
}
@@ -903,7 +920,12 @@ impl Screen {
}
/// Creates a new [`Tab`] in this [`Screen`]
- pub fn new_tab(&mut self, tab_index: usize, client_id: ClientId) -> Result<()> {
+ pub fn new_tab(
+ &mut self,
+ tab_index: usize,
+ swap_layouts: (Vec<SwapTiledLayout>, Vec<SwapFloatingLayout>),
+ client_id: ClientId,
+ ) -> Result<()> {
let err_context = || format!("failed to create new tab for client {client_id:?}",);
let client_id = if self.get_active_tab(client_id).is_ok() {
@@ -932,20 +954,22 @@ impl Screen {
self.style,
self.default_mode_info.clone(),
self.draw_pane_frames,
+ self.auto_layout,
self.connected_clients.clone(),
self.session_is_mirrored,
client_id,
self.copy_options.clone(),
self.terminal_emulator_colors.clone(),
self.terminal_emulator_color_codes.clone(),
+ swap_layouts,
);
self.tabs.insert(tab_index, tab);
Ok(())
}
pub fn apply_layout(
&mut self,
- layout: PaneLayout,
- floating_panes_layout: Vec<FloatingPanesLayout>,
+ layout: TiledPaneLayout,
+ floating_panes_layout: Vec<FloatingPaneLayout>,
new_terminal_ids: Vec<(u32, HoldForCommand)>,
new_floating_terminal_ids: Vec<(u32, HoldForCommand)>,
new_plugin_ids: HashMap<RunPluginLocation, Vec<u32>>,
@@ -1091,6 +1115,7 @@ impl Screen {
.copied()
.collect()
};
+ let (active_swap_layout_name, is_swap_layout_dirty) = tab.swap_layout_info();
tab_data.push(TabInfo {
position: tab.position,
name: tab.name.clone(),
@@ -1100,6 +1125,8 @@ impl Screen {
is_sync_panes_active: tab.is_sync_panes_active(),
are_floating_panes_visible: tab.are_floating_panes_visible(),
other_focused_clients,
+ active_swap_layout_name,
+ is_swap_layout_dirty,
});
}
plugin_updates.push((None, Some(*client_id), Event::TabUpdate(tab_data)));
@@ -1355,6 +1382,7 @@ pub(crate) fn screen_thread_main(
) -> Result<()> {
let capabilities = config_options.simplified_ui;
let draw_pane_frames = config_options.pane_frames.unwrap_or(true);
+ let auto_layout = config_options.auto_layout.unwrap_or(true);
let session_is_mirrored = config_options.mirror_session.unwrap_or(false);
let copy_options = CopyOptions::new(
config_options.copy_command,
@@ -1374,6 +1402,7 @@ pub(crate) fn screen_thread_main(
},
),
draw_pane_frames,
+ auto_layout,
session_is_mirrored,
copy_options,
);
@@ -1476,7 +1505,7 @@ pub(crate) fn screen_thread_main(
},
ScreenInstruction::ToggleFloatingPanes(client_id, default_shell) => {
active_tab_and_connected_client_id!(screen, client_id, |tab: &mut Tab, client_id: ClientId| tab
- .toggle_floating_panes(client_id, default_shell), ?);
+ .toggle_floating_panes(Some(client_id), default_shell), ?);
screen.unblock_input()?;
screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
@@ -1570,6 +1599,7 @@ pub(crate) fn screen_thread_main(
);
screen.unblock_input()?;
screen.render()?;
+ screen.update_tabs()?; // TODO: no every time
},
ScreenInstruction::SwitchFocus(client_id) => {
active_tab_and_connected_client_id!(
@@ -1686,6 +1716,17 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane(client_id)
);
+ screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.render()?;
+ screen.unblock_input()?;
+ },
+ ScreenInstruction::MovePaneBackwards(client_id) => {
+ active_tab_and_connected_client_id!(
+ screen,
+ client_id,
+ |tab: &mut Tab, client_id: ClientId| tab.move_active_pane_backwards(client_id)
+ );
+ screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
},
@@ -1695,6 +1736,7 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane_down(client_id)
);
+ screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
},
@@ -1704,6 +1746,7 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane_up(client_id)
);
+ screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
},
@@ -1713,6 +1756,7 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane_right(client_id)
);
+ screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
},
@@ -1722,6 +1766,7 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane_left(client_id)
);
+ screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
},
@@ -1851,12 +1896,16 @@ pub(crate) fn screen_thread_main(
ScreenInstruction::ClosePane(id, client_id) => {
match client_id {
Some(client_id) => {
- active_tab!(screen, client_id, |tab: &mut Tab| tab.close_pane(id, false));
+ active_tab!(screen, client_id, |tab: &mut Tab| tab.close_pane(
+ id,
+ false,
+ Some(client_id)
+ ));
},
None => {
for tab in screen.tabs.values_mut() {
if tab.get_all_pane_ids().contains(&id) {
- tab.close_pane(id, false);
+ tab.close_pane(id, false, None);
break;
}
}
@@ -1945,10 +1994,11 @@ pub(crate) fn screen_thread_main(
layout,
floating_panes_layout,
tab_name,
+ swap_layouts,
client_id,
) => {
let tab_index = screen.get_new_tab_index();
- screen.new_tab(tab_index, client_id)?;
+ screen.new_tab(tab_index, swap_layouts, client_id)?;
screen
.bus
.senders
@@ -1999,7 +2049,7 @@ pub(crate) fn screen_thread_main(
screen.render()?;
}
},
- ScreenInstruction::GoToTabName(tab_name, create, client_id) => {
+ ScreenInstruction::GoToTabName(tab_name, swap_layouts, create, client_id) => {
let client_id = if client_id.is_none() {
None
} else if screen
@@ -2016,7 +2066,7 @@ pub(crate) fn screen_thread_main(
screen.render()?;
if create && !tab_exists {
let tab_index = screen.get_new_tab_index();
- screen.new_tab(tab_index, client_id)?;
+ screen.new_tab(tab_index, swap_layouts, client_id)?;
screen
.bus
.senders
@@ -2044,6 +2094,7 @@ pub(crate) fn screen_thread_main(
},
ScreenInstruction::TerminalResize(new_size) => {
screen.resize_to_screen(new_size)?;
+ screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
},
ScreenInstruction::TerminalPixelDimensions(pixel_dimensions) => {
@@ -2256,6 +2307,28 @@ pub(crate) fn screen_thread_main(
}
screen.render()?;
},
+ ScreenInstruction::PreviousSwapLayout(client_id) => {
+ active_tab_and_connected_client_id!(
+ screen,
+ client_id,
+ |tab: &mut Tab, client_id: ClientId| tab.previous_swap_layout(Some(client_id)),
+ ?
+ );
+ screen.render()?;
+ screen.update_tabs()?;
+ screen.unblock_input()?;
+ },
+ ScreenInstruction::NextSwapLayout(client_id) => {
+ active_tab_and_connected_client_id!(
+ screen,
+ client_id,
+ |tab: &mut Tab, client_id: ClientId| tab.next_swap_layout(Some(client_id), true),
+ ?
+ );
+ screen.render()?;
+ screen.update_tabs()?;
+ screen.unblock_input()?;
+ },
}
}
Ok(())
diff --git a/zellij-server/src/tab/layout_applier.rs b/zellij-server/src/tab/layout_applier.rs
index f8245f08..eed7f8c8 100644
--- a/zellij-server/src/tab/layout_applier.rs
+++ b/zellij-server/src/tab/layout_applier.rs
@@ -14,11 +14,11 @@ use crate::{
ClientId,
};
use std::cell::RefCell;
-use std::collections::HashMap;
+use std::collections::{BTreeMap, HashMap};
use std::rc::Rc;
use zellij_utils::{
data::{Palette, Style},
- input::layout::{FloatingPanesLayout, PaneLayout, Run, RunPluginLocation},
+ input::layout::{FloatingPaneLayout, Run, RunPluginLocation, TiledPaneLayout},
pane_size::{Offset, PaneGeom, Size, SizeInPixels, Viewport},
};
@@ -85,8 +85,8 @@ impl<'a> LayoutApplier<'a> {
}
pub fn apply_layout(
&mut self,
- layout: PaneLayout,
- floating_panes_layout: Vec<FloatingPanesLayout>,
+ layout: TiledPaneLayout,
+ floating_panes_layout: Vec<FloatingPaneLayout>,
new_terminal_ids: Vec<(u32, HoldForCommand)>,
new_floating_terminal_ids: Vec<(u32, HoldForCommand)>,
mut new_plugin_ids: HashMap<RunPluginLocation, Vec<u32>>,
@@ -103,28 +103,73 @@ impl<'a> LayoutApplier<'a> {
)?;
return Ok(layout_has_floating_panes);
}
+ pub fn apply_tiled_panes_layout_to_existing_panes(
+ &mut self,
+ layout: &TiledPaneLayout,
+ refocus_pane: bool,
+ client_id: Option<ClientId>,
+ ) -> Result<()> {
+ let err_context = || format!("failed to apply tiled panes layout");
+ let free_space = self.total_space_for_tiled_panes();
+ let tiled_panes_count = self.tiled_panes.visible_panes_count();
+ match layout.position_panes_in_space(&free_space, Some(tiled_panes_count)) {
+ Ok(positions_in_layout) => {
+ let currently_focused_pane_id =
+ client_id.and_then(|client_id| self.tiled_panes.focused_pane_id(client_id));
+ let mut existing_tab_state =
+ ExistingTabState::new(self.tiled_panes.drain(), currently_focused_pane_id);
+ let mut pane_focuser = PaneFocuser::new(refocus_pane);
+ for (layout, position_and_size) in positions_in_layout {
+ if let Some(mut pane) = existing_tab_state.find_and_extract_pane(
+ &layout.run,
+ &position_and_size,
+ layout.focus.unwrap_or(false),
+ true,
+ ) {
+ self.apply_layout_properties_to_pane(
+ &mut pane,
+ &layout,
+ Some(position_and_size),
+ );
+ pane_focuser.set_pane_id_in_focused_location(layout.focus, &pane);
+ resize_pty!(pane, self.os_api, self.senders)?;
+ self.tiled_panes
+ .add_pane_with_existing_geom(pane.pid(), pane);
+ }
+ }
+ let remaining_pane_ids: Vec<PaneId> = existing_tab_state.pane_ids();
+ for pane_id in remaining_pane_ids {
+ if let Some(mut pane) = existing_tab_state.remove_pane(&pane_id) {
+ self.apply_layout_properties_to_pane(&mut pane, &layout, None);
+ self.tiled_panes.insert_pane(pane.pid(), pane);
+ }
+ }
+ pane_focuser.focus_tiled_pane(&mut self.tiled_panes);
+ },
+ Err(e) => {
+ Err::<(), _>(anyError::msg(e))
+ .with_context(err_context)
+ .non_fatal(); // TODO: propagate this to the user
+ },
+ };
+ Ok(())
+ }
fn apply_tiled_panes_layout(
&mut self,
- layout: PaneLayout,
+ layout: TiledPaneLayout,
new_terminal_ids: Vec<(u32, HoldForCommand)>,
new_plugin_ids: &mut HashMap<RunPluginLocation, Vec<u32>>,
client_id: ClientId,
) -> Result<()> {
let err_context = || format!("failed to apply tiled panes layout");
- let (viewport_cols, viewport_rows) = {
- let viewport = self.viewport.borrow();
- (viewport.cols, viewport.rows)
- };
- let mut free_space = PaneGeom::default();
- free_space.cols.set_inner(viewport_cols);
- free_space.rows.set_inner(viewport_rows);
- match layout.position_panes_in_space(&free_space) {
+ let free_space = self.total_space_for_tiled_panes();
+ match layout.position_panes_in_space(&free_space, None) {
Ok(positions_in_layout) => {
let positions_and_size = positions_in_layout.iter();
let mut new_terminal_ids = new_terminal_ids.iter();
let mut focus_pane_id: Option<PaneId> = None;
- let mut set_focus_pane_id = |layout: &PaneLayout, pane_id: PaneId| {
+ let mut set_focus_pane_id = |layout: &TiledPaneLayout, pane_id: PaneId| {
if layout.focus.unwrap_or(false) && focus_pane_id.is_none() {
focus_pane_id = Some(pane_id);
}
@@ -154,6 +199,7 @@ impl<'a> LayoutApplier<'a> {
self.link_handler.clone(),
self.character_cell_size.clone(),
self.style,
+ layout.run.clone(),
);
new_plugin.set_borderless(layout.borderless);
self.tiled_panes
@@ -180,6 +226,7 @@ impl<'a> LayoutApplier<'a> {
self.terminal_emulator_colors.clone(),
self.terminal_emulator_color_codes.clone(),
initial_title,
+ layout.run.clone(),
);
new_pane.set_borderless(layout.borderless);
if let Some(held_command) = hold_for_command {
@@ -216,7 +263,7 @@ impl<'a> LayoutApplier<'a> {
}
fn apply_floating_panes_layout(
&mut self,
- floating_panes_layout: Vec<FloatingPanesLayout>,
+ floating_panes_layout: Vec<FloatingPaneLayout>,
new_floating_terminal_ids: Vec<(u32, HoldForCommand)>,
new_plugin_ids: &mut HashMap<RunPluginLocation, Vec<u32>>,
layout_name: Option<String>,
@@ -254,6 +301,7 @@ impl<'a> LayoutApplier<'a> {
self.link_handler.clone(),
self.character_cell_size.clone(),
self.style,
+ floating_pane_layout.run.clone(),
);
new_pane.set_borderless(false);
new_pane.set_content_offset(Offset::frame(1));
@@ -285,6 +333,7 @@ impl<'a> LayoutApplier<'a> {
self.terminal_emulator_colors.clone(),
self.terminal_emulator_color_codes.clone(),
initial_title,
+ floating_pane_layout.run.clone(),
);
new_pane.set_borderless(false);
new_pane.set_content_offset(Offset::frame(1));
@@ -309,6 +358,80 @@ impl<'a> LayoutApplier<'a> {
Ok(false)
}
}
+ pub fn apply_floating_panes_layout_to_existing_panes(
+ &mut self,
+ floating_panes_layout: &Vec<FloatingPaneLayout>,
+ refocus_pane: bool,
+ client_id: Option<ClientId>,
+ ) -> Result<bool> {
+ // true => has floating panes
+ let mut layout_has_floating_panes = false;
+ let layout_has_focused_pane = floating_panes_layout
+ .iter()
+ .find(|f| f.focus.map(|f| f).unwrap_or(false))
+ .is_some();
+ let floating_panes_layout = floating_panes_layout.iter();
+ let currently_focused_pane_id = self
+ .floating_panes
+ .active_pane_id_or_focused_pane_id(client_id);
+ let mut existing_tab_state =
+ ExistingTabState::new(self.floating_panes.drain(), currently_focused_pane_id);
+ let mut pane_focuser = PaneFocuser::new(refocus_pane);
+ for floating_pane_layout in floating_panes_layout {
+ let position_and_size = self
+ .floating_panes
+ .position_floating_pane_layout(&floating_pane_layout);
+ let is_focused = floating_pane_layout.focus.unwrap_or(false);
+ if let Some(mut pane) = existing_tab_state.find_and_extract_pane(
+ &floating_pane_layout.run,
+ &position_and_size,
+ is_focused,
+ false,
+ ) {
+ layout_has_floating_panes = true;
+ self.apply_floating_pane_layout_properties_to_pane(
+ &mut pane,
+ Some(&floating_pane_layout),
+ position_and_size,
+ );
+ let pane_is_focused = floating_pane_layout
+ .focus
+ .or(Some(!layout_has_focused_pane));
+ pane_focuser.set_pane_id_in_focused_location(pane_is_focused, &pane);
+ resize_pty!(pane, self.os_api, self.senders)?;
+ self.floating_panes.add_pane(pane.pid(), pane);
+ }
+ }
+ let remaining_pane_ids: Vec<PaneId> = existing_tab_state.pane_ids();
+ for pane_id in remaining_pane_ids {
+ match self.floating_panes.find_room_for_new_pane() {
+ Some(position_and_size) => {
+ if let Some(mut pane) = existing_tab_state.remove_pane(&pane_id) {
+ layout_has_floating_panes = true;
+ self.apply_floating_pane_layout_properties_to_pane(
+ &mut pane,
+ None,
+ position_and_size,
+ );
+ pane_focuser
+ .set_pane_id_in_focused_location(Some(!layout_has_focused_pane), &pane);
+ resize_pty!(pane, self.os_api, self.senders)?;
+ self.floating_panes.add_pane(pane.pid(), pane);
+ }
+ },
+ None => {
+ log::error!("could not find room for pane!")
+ },
+ }
+ }
+
+ if layout_has_floating_panes {
+ pane_focuser.focus_floating_pane(&mut self.floating_panes, &mut self.os_api);
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ }
fn resize_whole_tab(&mut self, new_screen_size: Size) -> Result<()> {
let err_context = || {
format!(
@@ -316,7 +439,6 @@ impl<'a> LayoutApplier<'a> {
new_screen_size
)
};
-
self.floating_panes.resize(new_screen_size);
// we need to do this explicitly because floating_panes.resize does not do this
self.floating_panes
@@ -385,4 +507,217 @@ impl<'a> LayoutApplier<'a> {
}
}
}
+ fn apply_layout_properties_to_pane(
+ &self,
+ pane: &mut Box<dyn Pane>,
+ layout: &TiledPaneLayout,
+ position_and_size: Option<PaneGeom>,
+ ) {
+ if let Some(position_and_size) = position_and_size {
+ pane.set_geom(position_and_size);
+ }
+ pane.set_borderless(layout.borderless);
+ if let Some(pane_title) = layout.name.as_ref() {
+ pane.set_title(pane_title.into());
+ }
+ }
+ fn apply_floating_pane_layout_properties_to_pane(
+ &self,
+ pane: &mut Box<dyn Pane>,
+ floating_pane_layout: Option<&FloatingPaneLayout>,
+ position_and_size: PaneGeom,
+ ) {
+ pane.set_geom(position_and_size);
+ pane.set_borderless(false);
+ if let Some(pane_title) = floating_pane_layout.and_then(|f| f.name.clone()) {
+ pane.set_title(pane_title);
+ }
+ pane.set_content_offset(Offset::frame(1));
+ }
+ fn total_space_for_tiled_panes(&self) -> PaneGeom {
+ // for tiled panes we need to take the display area rather than the viewport because the
+ // viewport can potentially also be changed
+ let (display_area_cols, display_area_rows) = {
+ let display_area = self.display_area.borrow();
+ (display_area.cols, display_area.rows)
+ };
+
+ let mut free_space = PaneGeom::default();
+ free_space.cols.set_inner(display_area_cols);
+ free_space.rows.set_inner(display_area_rows);
+ free_space
+ }
+}
+
+struct ExistingTabState {
+ existing_panes: BTreeMap<PaneId, Box<dyn Pane>>,
+ currently_focused_pane_id: Option<PaneId>,
+}
+
+impl ExistingTabState {
+ pub fn new(
+ existing_panes: BTreeMap<PaneId, Box<dyn Pane>>,
+ currently_focused_pane_id: Option<PaneId>,
+ ) -> Self {
+ ExistingTabState {
+ existing_panes,
+ currently_focused_pane_id,
+ }
+ }
+ pub fn find_and_extract_pane(
+ &mut self,
+ run: &Option<Run>,
+ position_and_size: &PaneGeom,
+ is_focused: bool,
+ default_to_closest_position: bool,
+ ) -> Option<Box<dyn Pane>> {
+ let candidates = self.pane_candidates(run, position_and_size, default_to_closest_position);
+ if let Some(current_pane_id_with_same_contents) =
+ self.find_pane_id_with_same_contents(&candidates, run)
+ {
+ return self
+ .existing_panes
+ .remove(&current_pane_id_with_same_contents);
+ } else if let Some(currently_focused_pane_id) =
+ self.find_focused_pane_id(is_focused, &candidates)
+ {
+ return self.existing_panes.remove(&currently_focused_pane_id);
+ } else if let Some(same_position_candidate_id) = candidates
+ .iter()
+ .find(|(_, p)| p.position_and_size() == *position_and_size)
+ .map(|(pid, _p)| *pid)
+ .copied()
+ {
+ return self.existing_panes.remove(&same_position_candidate_id);
+ } else if let Some(first_candidate) =
+ candidates.iter().next().map(|(pid, _p)| *pid).copied()
+ {
+ return self.existing_panes.remove(&first_candidate);
+ }
+ None
+ }
+ pub fn pane_ids(&self) -> Vec<PaneId> {
+ self.existing_panes.keys().copied().collect()
+ }
+ pub fn remove_pane(&mut self, pane_id: &PaneId) -> Option<Box<dyn Pane>> {
+ self.existing_panes.remove(pane_id)
+ }
+ fn pane_candidates(
+ &self,
+ run: &Option<Run>,
+ position_and_size: &PaneGeom,
+ default_to_closest_position: bool,
+ ) -> Vec<(&PaneId, &Box<dyn Pane>)> {
+ let mut candidates: Vec<_> = self.existing_panes.iter().collect();
+ candidates.sort_by(|(_a_id, a), (_b_id, b)| {
+ let a_invoked_with = a.invoked_with();
+ let b_invoked_with = b.invoked_with();
+ if Run::is_same_category(run, a_invoked_with)
+ && !Run::is_same_category(run, b_invoked_with)
+ {
+ std::cmp::Ordering::Less
+ } else if Run::is_same_category(run, b_invoked_with)
+ && !Run::is_same_category(run, a_invoked_with)
+ {
+ std::cmp::Ordering::Greater
+ } else if Run::is_terminal(a_invoked_with) && !Run::is_terminal(b_invoked_with) {
+ // we place terminals before everything else because when we can't find
+ // an exact match, we need to prefer terminals are more often than not
+ // we'd be doing the right thing here
+ std::cmp::Ordering::Less
+ } else if Run::is_terminal(b_invoked_with) && !Run::is_terminal(a_invoked_with) {
+ std::cmp::Ordering::Greater
+ } else {
+ // try to find the closest pane
+ if default_to_closest_position {
+ let abs = |a, b| (a as isize - b as isize).abs();
+ let a_x_distance = abs(a.position_and_size().x, position_and_size.x);
+ let a_y_distance = abs(a.position_and_size().y, position_and_size.y);
+ let b_x_distance = abs(b.position_and_size().x, position_and_size.x);
+ let b_y_distance = abs(b.position_and_size().y, position_and_size.y);
+ (a_x_distance + a_y_distance).cmp(&(b_x_distance + b_y_distance))
+ } else {
+ std::cmp::Ordering::Equal
+ }
+ }
+ });
+ candidates
+ }
+ fn find_focused_pane_id(
+ &self,
+ is_focused: bool,
+ candidates: &Vec<(&PaneId, &Box<dyn Pane>)>,
+ ) -> Option<PaneId> {
+ if is_focused {
+ candidates
+ .iter()
+ .find(|(pid, _p)| Some(**pid) == self.currently_focused_pane_id)
+ .map(|(pid, _p)| *pid)
+ .copied()
+ } else {
+ None
+ }
+ }
+ fn find_pane_id_with_same_contents(
+ &self,
+ candidates: &Vec<(&PaneId, &Box<dyn Pane>)>,
+ run: &Option<Run>,
+ ) -> Option<PaneId> {
+ candidates
+ .iter()
+ .find(|(_pid, p)| p.invoked_with() == run)
+ .map(|(pid, _p)| *pid)
+ .copied()
+ }
+}
+
+#[derive(Default, Debug)]
+struct PaneFocuser {
+ refocus_pane: bool,
+ pane_id_in_focused_location: Option<PaneId>,
+}
+
+impl PaneFocuser {
+ pub fn new(refocus_pane: bool) -> Self {
+ PaneFocuser {
+ refocus_pane,
+ ..Default::default()
+ }
+ }
+ pub fn set_pane_id_in_focused_location(
+ &mut self,
+ is_focused: Option<bool>,
+ pane: &Box<dyn Pane>,
+ ) {
+ if is_focused.unwrap_or(false) && pane.selectable() {
+ self.pane_id_in_focused_location = Some(pane.pid());
+ }
+ }
+ pub fn focus_tiled_pane(&self, tiled_panes: &mut TiledPanes) {
+ match self.pane_id_in_focused_location {
+ Some(pane_id_in_focused_location) => {
+ if self.refocus_pane {
+ tiled_panes.reapply_pane_focus();
+ tiled_panes.switch_active_pane_with(pane_id_in_focused_location);
+ } else {
+ tiled_panes.reapply_pane_focus();
+ }
+ },
+ None => {
+ tiled_panes.reapply_pane_focus();
+ },
+ }
+ }
+ pub fn focus_floating_pane(
+ &self,
+ floating_panes: &mut FloatingPanes,
+ os_api: &mut Box<dyn ServerOsApi>,
+ ) {
+ floating_panes.reapply_pane_focus();
+ if let Some(pane_id_in_focused_location) = self.pane_id_in_focused_location {
+ if self.refocus_pane {
+ floating_panes.switch_active_pane_with(os_api, pane_id_in_focused_location);
+ }
+ }
+ }
}
diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs
index 0dcd7ba5..e99794cf 100644
--- a/zellij-server/src/tab/mod.rs
+++ b/zellij-server/src/tab/mod.rs
@@ -4,6 +4,7 @@
mod clipboard;
mod copy_command;
mod layout_applier;
+mod swap_layouts;
use copy_command::CopyCommand;
use std::env::temp_dir;
@@ -19,6 +20,7 @@ use crate::pty_writer::PtyWriteInstruction;
use crate::screen::CopyOptions;
use crate::ui::pane_boundaries_frame::FrameParams;
use layout_applier::LayoutApplier;
+use swap_layouts::SwapLayouts;
use self::clipboard::ClipboardProvider;
use crate::{
@@ -44,7 +46,10 @@ use zellij_utils::{
data::{Event, InputMode, ModeInfo, Palette, PaletteColor, Style},
input::{
command::TerminalAction,
- layout::{FloatingPanesLayout, PaneLayout, RunPluginLocation},
+ layout::{
+ FloatingPaneLayout, Run, RunPluginLocation, SwapFloatingLayout, SwapTiledLayout,
+ TiledPaneLayout,
+ },
parse_keys,
},
pane_size::{Offset, PaneGeom, Size, SizeInPixels, Viewport},
@@ -108,6 +113,7 @@ pub(crate) struct Tab {
pub style: Style,
connected_clients: Rc<RefCell<HashSet<ClientId>>>,
draw_pane_frames: bool,
+ auto_layout: bool,
pending_vte_events: HashMap<u32, Vec<VteBytes>>,
pub selecting_with_mouse: bool, // this is only pub for the tests TODO: remove this once we combine write_text_to_clipboard with render
link_handler: Rc<RefCell<LinkHandler>>,
@@ -125,7 +131,8 @@ pub(crate) struct Tab {
// cursor_shape_csi)
is_pending: bool, // a pending tab is one that is still being loaded or otherwise waiting
pending_instructions: Vec<BufferedTabInstruction>, // instructions that came while the tab was
- // pending and need to be re-applied
+ // pending and need to be re-applied
+ swap_layouts: SwapLayouts,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
@@ -392,6 +399,8 @@ pub trait Pane {
fn add_red_pane_frame_color_override(&mut self, _error_text: Option<String>);
fn clear_pane_frame_color_override(&mut self);
fn frame_color_override(&self) -> Option<PaletteColor>;
+ fn invoked_with(&self) -> &Option<Run>;
+ fn set_title(&mut self, title: String);
}
#[derive(Clone, Debug)]
@@ -437,12 +446,14 @@ impl Tab {
style: Style,
default_mode_info: ModeInfo,
draw_pane_frames: bool,
+ auto_layout: bool,
connected_clients_in_app: Rc<RefCell<HashSet<ClientId>>>,
session_is_mirrored: bool,
client_id: ClientId,
copy_options: CopyOptions,
terminal_emulator_colors: Rc<RefCell<Palette>>,
terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
+ swap_layouts: (Vec<SwapTiledLayout>, Vec<SwapFloatingLayout>),
) -> Self {
let name = if name.is_empty() {
format!("Tab #{}", index + 1)
@@ -489,6 +500,7 @@ impl Tab {
Some(command) => ClipboardProvider::Command(CopyCommand::new(command)),
None => ClipboardProvider::Osc52(copy_options.clipboard),
};
+ let swap_layouts = SwapLayouts::new(swap_layouts, display_area.clone());
Tab {
index,
@@ -511,6 +523,7 @@ impl Tab {
mode_info,
default_mode_info,
draw_pane_frames,
+ auto_layout,
pending_vte_events: HashMap::new(),
connected_clients,
selecting_with_mouse: false,
@@ -525,18 +538,21 @@ impl Tab {
cursor_positions_and_shape: HashMap::new(),
is_pending: true, // will be switched to false once the layout is applied
pending_instructions: vec![],
+ swap_layouts,
}
}
pub fn apply_layout(
&mut self,
- layout: PaneLayout,
- floating_panes_layout: Vec<FloatingPanesLayout>,
+ layout: TiledPaneLayout,
+ floating_panes_layout: Vec<FloatingPaneLayout>,
new_terminal_ids: Vec<(u32, HoldForCommand)>,
new_floating_terminal_ids: Vec<(u32, HoldForCommand)>,
new_plugin_ids: HashMap<RunPluginLocation, Vec<u32>>,
client_id: ClientId,
) -> Result<()> {
+ self.swap_layouts
+ .set_base_layout((layout.clone(), floating_panes_layout.clone()));
let layout_has_floating_panes = LayoutApplier::new(
&self.viewport,
&self.senders,
@@ -563,14 +579,153 @@ impl Tab {
)?;
if layout_has_floating_panes {
if !self.floating_panes.panes_are_visible() {
- self.toggle_floating_panes(client_id, None)?;
+ self.toggle_floating_panes(Some(client_id), None)?;
}
}
- self.tiled_panes.set_pane_frames(self.draw_pane_frames);
+ self.tiled_panes.reapply_pane_frames();
self.is_pending = false;
self.apply_buffered_instructions()?;
Ok(())
}
+ pub fn swap_layout_info(&self) -> (Option<String>, bool) {
+ if self.floating_panes.panes_are_visible() {
+ self.swap_layouts.floating_layout_info()
+ } else {
+ let selectable_tiled_panes =
+ self.tiled_panes.get_panes().filter(|(_, p)| p.selectable());
+ if selectable_tiled_panes.count() > 1 {
+ self.swap_layouts.tiled_layout_info()
+ } else {
+ // no layout for single pane
+ (None, false)
+ }
+ }
+ }
+ fn relayout_floating_panes(
+ &mut self,
+ client_id: Option<ClientId>,
+ search_backwards: bool,
+ refocus_pane: bool,
+ ) -> Result<()> {
+ if let Some(layout_candidate) = self
+ .swap_layouts
+ .swap_floating_panes(&self.floating_panes, search_backwards)
+ {
+ LayoutApplier::new(
+ &self.viewport,
+ &self.senders,
+ &self.sixel_image_store,
+ &self.link_handler,
+ &self.terminal_emulator_colors,
+ &self.terminal_emulator_color_codes,
+ &self.character_cell_size,
+ &self.style,
+ &self.display_area,
+ &mut self.tiled_panes,
+ &mut self.floating_panes,
+ self.draw_pane_frames,
+ &mut self.focus_pane_id,
+ &self.os_api,
+ )
+ .apply_floating_panes_layout_to_existing_panes(
+ &layout_candidate,
+ refocus_pane,
+ client_id,
+ )?;
+ }
+ self.is_pending = false;
+ self.apply_buffered_instructions()?;
+ self.set_force_render();
+ Ok(())
+ }
+ fn relayout_tiled_panes(
+ &mut self,
+ client_id: Option<ClientId>,
+ search_backwards: bool,
+ refocus_pane: bool,
+ best_effort: bool,
+ ) -> Result<()> {
+ if self.tiled_panes.fullscreen_is_active() {
+ self.tiled_panes.unset_fullscreen();
+ }
+ let refocus_pane = if self.swap_layouts.is_tiled_damaged() {
+ false
+ } else {
+ refocus_pane
+ };
+ if let Some(layout_candidate) = self
+ .swap_layouts
+ .swap_tiled_panes(&self.tiled_panes, search_backwards)
+ .or_else(|| {
+ if best_effort {
+ self.swap_layouts
+ .best_effort_tiled_layout(&self.tiled_panes)
+ } else {
+ None
+ }
+ })
+ {
+ LayoutApplier::new(
+ &self.viewport,
+ &self.senders,
+ &self.sixel_image_store,
+ &self.link_handler,
+ &self.terminal_emulator_colors,
+ &self.terminal_emulator_color_codes,
+ &self.character_cell_size,
+ &self.style,
+ &self.display_area,
+ &mut self.tiled_panes,
+ &mut self.floating_panes,
+ self.draw_pane_frames,
+ &mut self.focus_pane_id,
+ &self.os_api,
+ )
+ .apply_tiled_panes_layout_to_existing_panes(
+ &layout_candidate,
+ refocus_pane,
+ client_id,
+ )?;
+ }
+ self.tiled_panes.reapply_pane_frames();
+ self.is_pending = false;
+ self.apply_buffered_instructions()?;
+ let display_area = *self.display_area.borrow();
+ // we do this so that the new swap layout has a chance to pass through the constraint system
+ self.tiled_panes.resize(display_area);
+ self.should_clear_display_before_rendering = true;
+ Ok(())
+ }
+ pub fn previous_swap_layout(&mut self, client_id: Option<ClientId>) -> Result<()> {
+ // warning, here we cache resizes rather than sending them to the pty, we do that in
+ // apply_cached_resizes below - beware when bailing on this function early!
+ self.os_api.cache_resizes();
+ let search_backwards = true;
+ if self.floating_panes.panes_are_visible() {
+ self.relayout_floating_panes(client_id, search_backwards, true)?;
+ } else {
+ self.relayout_tiled_panes(client_id, search_backwards, true, false)?;
+ }
+ self.os_api.apply_cached_resizes();
+ Ok(())
+ }
+ pub fn next_swap_layout(
+ &mut self,
+ client_id: Option<ClientId>,
+ refocus_pane: bool,
+ ) -> Result<()> {
+ // warning, here we cache resizes rather than sending them to the pty, we do that in
+ // apply_cached_resizes below - beware when bailing on this function early!
+ self.os_api.cache_resizes();
+ let search_backwards = false;
+ if self.floating_panes.panes_are_visible() {
+ self.relayout_floating_panes(client_id, search_backwards, refocus_pane)?;
+ } else {
+ self.relayout_tiled_panes(client_id, search_backwards, refocus_pane, false)?;
+ }
+ self.os_api.apply_cached_resizes();
+ Ok(())
+ }
pub fn apply_buffered_instructions(&mut self) -> Result<()> {
let buffered_instructions: Vec<BufferedTabInstruction> =
self.pending_instructions.drain(..).collect();
@@ -702,7 +857,7 @@ impl Tab {
if let Some(focused_floating_pane_id) = self.floating_panes.active_pane_id(client_id) {
if self.tiled_panes.has_room_for_new_pane() {
let floating_pane_to_embed = self
- .close_pane(focused_floating_pane_id, true)
+ .close_pane(focused_floating_pane_id, true, Some(client_id))
.with_context(|| format!(
"failed to find floating pane (ID: {focused_floating_pane_id:?}) to embed for client {client_id}",
))
@@ -713,6 +868,13 @@ impl Tab {
self.tiled_panes
.focus_pane(focused_floating_pane_id, client_id);
self.hide_floating_panes();
+ if self.auto_layout && !self.swap_layouts.is_tiled_damaged() {
+ // only do this if we're already in this layout, otherwise it might be
+ // confusing and not what the user intends
+ self.swap_layouts.set_is_tiled_damaged(); // we do this so that we won't skip to the
+ // next layout
+ self.next_swap_layout(Some(client_id), true)?;
+ }
}
}
} else if let Some(focused_pane_id) = self.tiled_panes.focused_pane_id(client_id) {
@@ -721,7 +883,9 @@ impl Tab {
// don't close the only pane on screen...
return Ok(());
}
- if let Some(mut embedded_pane_to_float) = self.close_pane(focused_pane_id, true) {
+ if let Some(mut embedded_pane_to_float) =
+ self.close_pane(focused_pane_id, true, Some(client_id))
+ {
if !embedded_pane_to_float.borderless() {
// floating panes always have a frame unless they're explicitly borderless
embedded_pane_to_float.set_content_offset(Offset::frame(1));
@@ -734,6 +898,13 @@ impl Tab {
.add_pane(focused_pane_id, embedded_pane_to_float);
self.floating_panes.focus_pane(focused_pane_id, client_id);
self.show_floating_panes();
+ if self.auto_layout && !self.swap_layouts.is_floating_damaged() {
+ // only do this if we're already in this layout, otherwise it might be
+ // confusing and not what the user intends
+ self.swap_layouts.set_is_floating_damaged(); // we do this so that we won't skip to the
+ // next layout
+ self.next_swap_layout(Some(client_id), true)?;
+ }
}
}
}
@@ -741,7 +912,7 @@ impl Tab {
}
pub fn toggle_floating_panes(
&mut self,
- client_id: ClientId,
+ client_id: Option<ClientId>,
default_shell: Option<TerminalAction>,
) -> Result<()> {
if self.floating_panes.panes_are_visible() {
@@ -750,24 +921,34 @@ impl Tab {
} else {
self.show_floating_panes();
match self.floating_panes.last_floating_pane_id() {
- Some(first_floating_pane_id) => {
- if !self.floating_panes.active_panes_contain(&client_id) {
+ Some(first_floating_pane_id) => match client_id {
+ Some(client_id) => {
+ if !self.floating_panes.active_panes_contain(&client_id) {
+ self.floating_panes
+ .focus_pane(first_floating_pane_id, client_id);
+ }
+ },
+ None => {
self.floating_panes
- .focus_pane(first_floating_pane_id, client_id);
- }
+ .focus_pane_for_all_clients(first_floating_pane_id);
+ },
},
None => {
let name = None;
let should_float = true;
+ let client_id_or_tab_index = match client_id {
+ Some(client_id) => ClientOrTabIndex::ClientId(client_id),
+ None => ClientOrTabIndex::TabIndex(self.index),
+ };
let instruction = PtyInstruction::SpawnTerminal(
default_shell,
Some(should_float),
name,
- ClientOrTabIndex::ClientId(client_id),
+ client_id_or_tab_index,
);
- self.senders.send_to_pty(instruction).with_context(|| {
- format!("failed to open a floating pane for client {client_id}")
- })?;
+ self.senders
+ .send_to_pty(instruction)
+ .with_context(|| format!("failed to open a floating pane for client"))?;
},
}
self.floating_panes.set_force_render();
@@ -807,12 +988,21 @@ impl Tab {
self.terminal_emulator_colors.clone(),
self.terminal_emulator_color_codes.clone(),
initial_pane_title,
+ None,
);
+ new_pane.set_active_at(Instant::now());
new_pane.set_content_offset(Offset::frame(1)); // floating panes always have a frame
resize_pty!(new_pane, self.os_api, self.senders).with_context(err_context)?;
self.floating_panes.add_pane(pid, Box::new(new_pane));
self.floating_panes.focus_pane_for_all_clients(pid);
}
+ if self.auto_layout && !self.swap_layouts.is_floating_damaged() {
+ // only do this if we're already in this layout, otherwise it might be
+ // confusing and not what the user intends
+ self.swap_layouts.set_is_floating_damaged(); // we do this so that we won't skip to the
+ // next layout
+ self.next_swap_layout(client_id, true)?;
+ }
}
} else {
if self.tiled_panes.fullscreen_is_active() {
@@ -821,7 +1011,7 @@ impl Tab {
if self.tiled_panes.has_room_for_new_pane() {
if let PaneId::Terminal(term_pid) = pid {
let next_terminal_position = self.get_next_terminal_position();
- let new_terminal = TerminalPane::new(
+ let mut new_terminal = TerminalPane::new(
term_pid,
PaneGeom::default(), // the initial size will be set later
self.style,
@@ -833,7 +1023,9 @@ impl Tab {
self.terminal_emulator_colors.clone(),
self.terminal_emulator_color_codes.clone(),
initial_pane_title,
+ None,
);
+ new_terminal.set_active_at(Instant::now());
self.tiled_panes.insert_pane(pid, Box::new(new_terminal));
self.should_clear_display_before_rendering = true;
if let Some(client_id) = client_id {
@@ -841,6 +1033,13 @@ impl Tab {
}
}
}
+ if self.auto_layout && !self.swap_layouts.is_tiled_damaged() {
+ // only do this if we're already in this layout, otherwise it might be
+ // confusing and not what the user intends
+ self.swap_layouts.set_is_tiled_damaged(); // we do this so that we won't skip to the
+ // next layout
+ self.next_swap_layout(client_id, true)?;
+ }
}
Ok(())
}
@@ -865,6 +1064,7 @@ impl Tab {
self.terminal_emulator_colors.clone(),
self.terminal_emulator_color_codes.clone(),
None,
+ None,
);
new_pane.update_name("EDITING SCROLLBACK"); // we do this here and not in the
// constructor so it won't be overrided
@@ -934,11 +1134,13 @@ impl Tab {
self.terminal_emulator_colors.clone(),
self.terminal_emulator_color_codes.clone(),
initial_pane_title,
+ None,
);
self.tiled_panes
.split_pane_horizontally(pid, Box::new(new_terminal), client_id);
self.should_clear_display_before_rendering = true;
self.tiled_panes.focus_pane(pid, client_id);
+ self.swap_layouts.set_is_tiled_damaged();
}
} else {
log::error!("No room to split pane horizontally");
@@ -946,7 +1148,7 @@ impl Tab {
self.senders
.send_to_background_jobs(BackgroundJob::DisplayPaneError(
vec![active_pane_id],
- "TOO SMALL!".into(),
+ "CAN'T SPLIT!".into(),
))
.with_context(err_context)?;
}
@@ -988,11 +1190,13 @@ impl Tab {
self.terminal_emulator_colors.clone(),
self.terminal_emulator_color_codes.clone(),
initial_pane_title,
+ None,
);
self.tiled_panes
.split_pane_vertically(pid, Box::new(new_terminal), client_id);
self.should_clear_display_before_rendering = true;
self.tiled_panes.focus_pane(pid, client_id);
+ self.swap_layouts.set_is_tiled_damaged();
}
} else {
log::error!("No room to split pane vertically");
@@ -1000,7 +1204,7 @@ impl Tab {
self.senders
.send_to_background_jobs(BackgroundJob::DisplayPaneError(
vec![active_pane_id],
- "TOO SMALL!".into(),
+ "CAN'T SPLIT!".into(),
))
.with_context(err_context)?;
}
@@ -1285,7 +1489,7 @@ impl Tab {
.with_context(err_context)?;
},
Some(AdjustedInput::CloseThisPane) => {
- self.close_pane(PaneId::Terminal(active_terminal_id), false);
+ self.close_pane(PaneId::Terminal(active_terminal_id), false, None);
should_update_ui = true;
},
None => {},
@@ -1522,19 +1726,35 @@ impl Tab {
selectable_tiled_panes.count() > 0
}
pub fn resize_whole_tab(&mut self, new_screen_size: Size) -> Result<()> {
+ // warning, here we cache resizes rather than sending them to the pty, we do that in
+ // apply_cached_resizes below - beware when bailing on this function early!
+ self.os_api.cache_resizes();
let err_context = || format!("failed to resize whole tab (index {})", self.index);
-
self.floating_panes.resize(new_screen_size);
// we need to do this explicitly because floating_panes.resize does not do this
self.floating_panes
.resize_pty_all_panes(&mut self.os_api)
.with_context(err_context)?;
self.tiled_panes.resize(new_screen_size);
+ if self.auto_layout && !self.swap_layouts.is_floating_damaged() {
+ // we do this only for floating panes, because the constraint system takes care of the
+ // tiled panes
+ self.swap_layouts.set_is_floating_damaged();
+ let _ = self.relayout_floating_panes(None, false, false);
+ }
+ if self.auto_layout && !self.swap_layouts.is_tiled_damaged() && !self.is_fullscreen_active()
+ {
+ self.swap_layouts.set_is_tiled_damaged();
+ let _ = self.relayout_tiled_panes(None, false, false, true);
+ }
self.should_clear_display_before_rendering = true;
+ let _ = self.os_api.apply_cached_resizes();
Ok(())
}
pub fn resize(&mut self, client_id: ClientId, strategy: ResizeStrategy) -> Result<()> {
let err_context = || format!("unable to resize pane");
+ self.swap_layouts.set_is_floating_damaged();
+ self.swap_layouts.set_is_tiled_damaged();
if self.floating_panes.panes_are_visible() {
let successfully_resized = self
.floating_panes
@@ -1691,11 +1911,35 @@ impl Tab {
if self.tiled_panes.fullscreen_is_active() {
return;
}
- self.tiled_panes.move_active_pane(client_id);
+ let search_backwards = false;
+ if self.floating_panes.panes_are_visible() {
+ self.floating_panes
+ .move_active_pane(search_backwards, &mut self.os_api, client_id);
+ } else {
+ self.tiled_panes
+ .move_active_pane(search_backwards, client_id);
+ }
+ }
+ pub fn move_active_pane_backwards(&mut self, client_id: ClientId) {
+ if !self.has_selectable_panes() {
+ return;
+ }
+ if self.tiled_panes.fullscreen_is_active() {
+ return;
+ }
+ let search_backwards = true;
+ if self.floating_panes.panes_are_visible() {
+ self.floating_panes
+ .move_active_pane(search_backwards, &mut self.os_api, client_id);
+ } else {
+ self.tiled_panes
+ .move_active_pane(search_backwards, client_id);
+ }
}
pub fn move_active_pane_down(&mut self, client_id: ClientId) {
if self.floating_panes.panes_are_visible() {
self.floating_panes.move_active_pane_down(client_id);
+ self.swap_layouts.set_is_floating_damaged();
self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" behind
} else {
if !self.has_selectable_panes() {
@@ -1710,6 +1954,7 @@ impl Tab {
pub fn move_active_pane_up(&mut self, client_id: ClientId) {
if self.floating_panes.panes_are_visible() {
self.floating_panes.move_active_pane_up(client_id);
+ self.swap_layouts.set_is_floating_damaged();
self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" behind
} else {
if !self.has_selectable_panes() {
@@ -1724,6 +1969,7 @@ impl Tab {
pub fn move_active_pane_right(&mut self, client_id: ClientId) {
if self.floating_panes.panes_are_visible() {
self.floating_panes.move_active_pane_right(client_id);
+ self.swap_layouts.set_is_floating_damaged();
self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" behind
} else {
if !self.has_selectable_panes() {
@@ -1738,6 +1984,7 @@ impl Tab {
pub fn move_active_pane_left(&mut self, client_id: ClientId) {
if self.floating_panes.panes_are_visible() {
self.floating_panes.move_active_pane_left(client_id);
+ self.swap_layouts.set_is_floating_damaged();
self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" behind
} else {
if !self.has_selectable_panes() {
@@ -1756,7 +2003,7 @@ impl Tab {
self.senders
.send_to_pty(PtyInstruction::ClosePane(pid))
.context("failed to close down to max terminals")?;
- self.close_pane(pid, false);
+ self.close_pane(pid, false, None);
}
}
Ok(())
@@ -1803,6 +2050,7 @@ impl Tab {
&mut self,
id: PaneId,
ignore_suppressed_panes: bool,
+ client_id: Option<ClientId>,
) -> Option<Box<dyn Pane>> {
// we need to ignore suppressed panes when we toggle a pane to be floating/embedded(tiled)
// this is because in that case, while we do use this logic, we're not actually closing the
@@ -1829,6 +2077,15 @@ impl Tab {
}
self.set_force_render();
self.floating_panes.set_force_render();
+ if self.auto_layout
+ && !self.swap_layouts.is_floating_damaged()
+ && self.floating_panes.visible_panes_count() > 0
+ {
+ self.swap_layouts.set_is_floating_damaged();
+ // only relayout if the user is already "in" a layout, otherwise this might be
+ // confusing
+ let _ = self.next_swap_layout(client_id, false);
+ }
closed_pane
} else {
if self.tiled_panes.fullscreen_is_active() {
@@ -1837,6 +2094,17 @@ impl Tab {
let closed_pane = self.tiled_panes.remove_pane(id);
self.set_force_render();
self.tiled_panes.set_force_render();
+ let closed_pane_is_stacked = closed_pane
+ .as_ref()
+ .map(|p| p.position_and_size().is_stacked)
+ .unwrap_or(false);
+ if self.auto_layout && !self.swap_layouts.is_tiled_damaged() && !closed_pane_is_stacked
+ {
+ self.swap_layouts.set_is_tiled_damaged();
+ // only relayout if the user is already "in" a layout, otherwise this might be
+ // confusing
+ let _ = self.next_swap_layout(client_id, false);
+ }
closed_pane
}
}
@@ -1905,7 +2173,7 @@ impl Tab {
if self.floating_panes.panes_are_visible() {
if let Some(active_floating_pane_id) = self.floating_panes.active_pane_id(client_id) {
- self.close_pane(active_floating_pane_id, false);
+ self.close_pane(active_floating_pane_id, false, Some(client_id));
self.senders
.send_to_pty(PtyInstruction::ClosePane(active_floating_pane_id))
.with_context(|| err_context(active_floating_pane_id))?;
@@ -1913,7 +2181,7 @@ impl Tab {
}
}
if let Some(active_pane_id) = self.tiled_panes.get_active_pane_id(client_id) {
- self.close_pane(active_pane_id, false);
+ self.close_pane(active_pane_id, false, Some(client_id));
self.senders
.send_to_pty(PtyInstruction::ClosePane(active_pane_id))
.with_context(|| err_context(active_pane_id))?;
@@ -2212,6 +2480,7 @@ impl Tab {
.floating_panes
.move_pane_with_mouse(*position, search_selectable)
{
+ self.swap_layouts.set_is_floating_damaged();
self.set_force_render();
return Ok(());
}
@@ -2472,6 +2741,7 @@ impl Tab {
.floating_panes
.move_pane_with_mouse(*position_on_screen, search_selectable)
{
+ self.swap_layouts.set_is_floating_damaged();
self.set_force_render();
return Ok(!is_repeated); // we don't need to re-render in this case if the pane did not move
// return;
diff --git a/zellij-server/src/tab/swap_layouts.rs b/zellij-server/src/tab/swap_layouts.rs
new file mode 100644
index 00000000..57085779
--- /dev/null
+++ b/zellij-server/src/tab/swap_layouts.rs
@@ -0,0 +1,284 @@
+use crate::panes::{FloatingPanes, TiledPanes};
+use std::cell::RefCell;
+use std::collections::BTreeMap;
+use std::rc::Rc;
+use zellij_utils::{
+ input::layout::{
+ FloatingPaneLayout, LayoutConstraint, SwapFloatingLayout, SwapTiledLayout, TiledPaneLayout,
+ },
+ pane_size::{PaneGeom, Size},
+};
+
+#[derive(Clone, Debug, Default)]
+pub struct SwapLayouts {
+ swap_tiled_layouts: Vec<SwapTiledLayout>,
+ swap_floating_layouts: Vec<SwapFloatingLayout>,
+ current_floating_layout_position: usize,
+ current_tiled_layout_position: usize,
+ is_floating_damaged: bool,
+ is_tiled_damaged: bool,
+ display_area: Rc<RefCell<Size>>, // includes all panes (including eg. the status bar and tab bar in the default layout)
+}
+
+impl SwapLayouts {
+ pub fn new(
+ swap_layouts: (Vec<SwapTiledLayout>, Vec<SwapFloatingLayout>),
+ display_area: Rc<RefCell<Size>>,
+ ) -> Self {
+ let display_area = display_area.clone();
+ SwapLayouts {
+ swap_tiled_layouts: swap_layouts.0,
+ swap_floating_layouts: swap_layouts.1,
+ is_floating_damaged: false,
+ is_tiled_damaged: false,
+ display_area,
+ ..Default::default()
+ }
+ }
+ pub fn set_base_layout(&mut self, layout: (TiledPaneLayout, Vec<FloatingPaneLayout>)) {
+ let mut base_swap_tiled_layout = BTreeMap::new();
+ let mut base_swap_floating_layout = BTreeMap::new();
+ let tiled_panes_count = layout.0.pane_count();
+ let floating_panes_count = layout.1.len();
+ // we set MaxPanes to the current panes in the layout, because the base layout is not
+ // intended to be progressive - i.e. to have additional panes added to it
+ // we still want to keep it around in case we'd like to swap layouts without adding panes
+ base_swap_tiled_layout.insert(LayoutConstraint::MaxPanes(tiled_panes_count), layout.0);
+ base_swap_floating_layout
+ .insert(LayoutConstraint::MaxPanes(floating_panes_count), layout.1);
+ self.swap_tiled_layouts
+ .insert(0, (base_swap_tiled_layout, Some("BASE".into())));
+ self.swap_floating_layouts
+ .insert(0, (base_swap_floating_layout, Some("BASE".into())));
+ self.current_tiled_layout_position = 0;
+ self.current_floating_layout_position = 0;
+ }
+ pub fn set_is_floating_damaged(&mut self) {
+ self.is_floating_damaged = true;
+ }
+ pub fn set_is_tiled_damaged(&mut self) {
+ self.is_tiled_damaged = true;
+ }
+ pub fn is_floating_damaged(&self) -> bool {
+ self.is_floating_damaged
+ }
+ pub fn is_tiled_damaged(&self) -> bool {
+ self.is_tiled_damaged
+ }
+ pub fn tiled_layout_info(&self) -> (Option<String>, bool) {
+ // (swap_layout_name, is_swap_layout_dirty)
+ match self
+ .swap_tiled_layouts
+ .iter()
+ .nth(self.current_tiled_layout_position)
+ {
+ Some(current_tiled_layout) => (
+ current_tiled_layout.1.clone().or_else(|| {
+ Some(format!(
+ "Layout #{}",
+ self.current_tiled_layout_position + 1
+ ))
+ }),
+ self.is_tiled_damaged,
+ ),
+ None => (None, self.is_tiled_damaged),
+ }
+ }
+ pub fn floating_layout_info(&self) -> (Option<String>, bool) {
+ // (swap_layout_name, is_swap_layout_dirty)
+ match self
+ .swap_floating_layouts
+ .iter()
+ .nth(self.current_floating_layout_position)
+ {
+ Some(current_floating_layout) => (
+ current_floating_layout.1.clone().or_else(|| {
+ Some(format!(
+ "Layout #{}",
+ self.current_floating_layout_position + 1
+ ))
+ }),
+ self.is_floating_damaged,
+ ),
+ None => (None, self.is_floating_damaged),
+ }
+ }
+ pub fn swap_floating_panes(
+ &mut self,
+ floating_panes: &FloatingPanes,
+ search_backwards: bool,
+ ) -> Option<Vec<FloatingPaneLayout>> {
+ if self.swap_floating_layouts.is_empty() {
+ return None;
+ }
+ let initial_position = self.current_floating_layout_position;
+
+ macro_rules! progress_layout {
+ () => {{
+ if search_backwards {
+ if self.current_floating_layout_position == 0 {
+ self.current_floating_layout_position =
+ self.swap_floating_layouts.len().saturating_sub(1);
+ } else {
+ self.current_floating_layout_position -= 1;
+ }
+ } else {
+ self.current_floating_layout_position += 1;
+ }
+ }};
+ }
+
+ if !self.is_floating_damaged
+ && self
+ .swap_floating_layouts
+ .iter()
+ .nth(self.current_floating_layout_position)
+ .is_some()
+ {
+ progress_layout!();
+ }
+ self.is_floating_damaged = false;
+ loop {
+ match self
+ .swap_floating_layouts
+ .iter()
+ .nth(self.current_floating_layout_position)
+ {
+ Some(swap_layout) => {
+ for (constraint, layout) in swap_layout.0.iter() {
+ if self.state_fits_floating_panes_constraint(constraint, floating_panes) {
+ return Some(layout.clone());
+ };
+ }
+ progress_layout!();
+ },
+ None => {
+ self.current_floating_layout_position = 0;
+ },
+ };
+ if self.current_floating_layout_position == initial_position {
+ break;
+ }
+ }
+ None
+ }
+ fn state_fits_tiled_panes_constraint(
+ &self,
+ constraint: &LayoutConstraint,
+ tiled_panes: &TiledPanes,
+ ) -> bool {
+ match constraint {
+ LayoutConstraint::MaxPanes(max_panes) => {
+ tiled_panes.visible_panes_count() <= *max_panes
+ },
+ LayoutConstraint::MinPanes(min_panes) => {
+ tiled_panes.visible_panes_count() >= *min_panes
+ },
+ LayoutConstraint::NoConstraint => true,
+ }
+ }
+ fn state_fits_floating_panes_constraint(
+ &self,
+ constraint: &LayoutConstraint,
+ floating_panes: &FloatingPanes,
+ ) -> bool {
+ match constraint {
+ LayoutConstraint::MaxPanes(max_panes) => {
+ floating_panes.visible_panes_count() <= *max_panes
+ },
+ LayoutConstraint::MinPanes(min_panes) => {
+ floating_panes.visible_panes_count() >= *min_panes
+ },
+ LayoutConstraint::NoConstraint => true,
+ }
+ }
+ pub fn swap_tiled_panes(
+ &mut self,
+ tiled_panes: &TiledPanes,
+ search_backwards: bool,
+ ) -> Option<TiledPaneLayout> {
+ if self.swap_tiled_layouts.is_empty() {
+ return None;
+ }
+
+ macro_rules! progress_layout {
+ () => {{
+ if search_backwards {
+ if self.current_tiled_layout_position == 0 {
+ self.current_tiled_layout_position =
+ self.swap_tiled_layouts.len().saturating_sub(1);
+ } else {
+ self.current_tiled_layout_position -= 1;
+ }
+ } else {
+ self.current_tiled_layout_position += 1;
+ }
+ }};
+ }
+
+ let initial_position = self.current_tiled_layout_position;
+ if !self.is_tiled_damaged
+ && self
+ .swap_tiled_layouts
+ .iter()
+ .nth(self.current_tiled_layout_position)
+ .is_some()
+ {
+ progress_layout!();
+ }
+ self.is_tiled_damaged = false;
+ loop {
+ match self
+ .swap_tiled_layouts
+ .iter()
+ .nth(self.current_tiled_layout_position)
+ {
+ Some(swap_layout) => {
+ for (constraint, layout) in swap_layout.0.iter() {
+ if self.state_fits_tiled_panes_constraint(constraint, tiled_panes) {
+ let display_area = self.display_area.borrow();
+ // TODO: reuse the assets from position_panes_in_space here?
+ let pane_count = tiled_panes.visible_panes_count();
+ let display_area = PaneGeom::from(&*display_area);
+ if layout
+ .position_panes_in_space(&display_area, Some(pane_count))
+ .is_ok()
+ {
+ return Some(layout.clone());
+ }
+ };
+ }
+ progress_layout!();
+ },
+ None => {
+ self.current_tiled_layout_position = 0;
+ },
+ };
+ if self.current_tiled_layout_position == initial_position {
+ break;
+ }
+ }
+ None
+ }
+ pub fn best_effort_tiled_layout(
+ &mut self,
+ tiled_panes: &TiledPanes,
+ ) -> Option<TiledPaneLayout> {
+ for swap_layout in self.swap_tiled_layouts.iter() {
+ for (_constraint, layout) in swap_layout.0.iter() {
+ let display_area = self.display_area.borrow();
+ // TODO: reuse the assets from position_panes_in_space here?
+ let pane_count = tiled_panes.visible_panes_count();
+ let display_area = PaneGeom::from(&*display_area);
+ if layout
+ .position_panes_in_space(&display_area, Some(pane_count))
+ .is_ok()
+ {
+ return Some(layout.clone());
+ }
+ }
+ }
+ log::error!("Could not find layout that would fit on screen!");
+ None
+ }
+}
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_floating_layout_is_included_in_swap_layouts.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_floating_layout_is_included_in_swap_layouts.snap
new file mode 100644
index 00000000..f6e33291
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_floating_layout_is_included_in_swap_layouts.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5472
+expression: snapshot
+---
+00 (C): ┌ tab-bar ────────────────────────────────────────┌ status-bar ──────────────────────────────────────────────┐──────────┐
+01 (C): │I am a tab bar │I am a │ │
+02 (C): │ │status bar │ │
+03 (C): │ │ │ │
+04 (C): │ │ │ │
+05 (C): │ ┌ Pane #3 ──────────│ │ │
+06 (C): │ │ │ │ │
+07 (C): │ │ │ │ │
+08 (C): │ │ │ │ │
+09 (C): └─────────────────────────────│ └──────────────────────────────────────────────────────────┘ │
+10 (C): ┌ command1 ───────────────────│ ┌ command2 ────────────────────────────────────────────────┐ │
+11 (C): │ │ │ │ │
+12 (C): │ │ │ │ │
+13 (C): │ │ │ │ │
+14 (C): │ Waiting to ru└───────────────────│ Waiting to run: command2 │ │
+15 (C): │ │ │ │
+16 (C): │ <ENTER> to run, <Ctrl-c> to exit │ <ENTER> to run, <Ctrl-c> to exit │ │
+17 (C): │ │ │ │
+18 (C): │ │ │ │
+19 (C): └─────────────────────────────────────────────────└──────────────────────────────────────────────────────────┘──────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_layout_is_included_in_swap_layouts.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_layout_is_included_in_swap_layouts.snap
new file mode 100644
index 00000000..5fbf2847
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_layout_is_included_in_swap_layouts.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4762
+expression: snapshot
+---
+00 (C): I am a tab bar
+01 (C): ┌ command2 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐┌ command1 ────────────────────────────┐
+02 (C): │ ││ ││ │
+03 (C): │ ││ ││ │
+04 (C): │ ││ ││ │
+05 (C): │ ││ ││ │
+06 (C): │ ││ ││ │
+07 (C): │ ││ ││ │
+08 (C): │ Waiting to run: command2 ││ ││ Waiting to run: command1 │
+09 (C): │ ││ ││ │
+10 (C): │ <ENTER> to run, <Ctrl-c> to exit ││ ││ <ENTER> to run, <Ctrl-c> to exit │
+11 (C): │ ││ ││ │
+12 (C): │ ││ ││ │
+13 (C): │ ││ ││ │
+14 (C): │ ││ ││ │
+15 (C): │ ││ ││ │
+16 (C): │ ││ ││ │
+17 (C): └───────────────────────────────────────┘└──────────────────────────────────────┘└──────────────────────────────────────┘
+18 (C): I am a
+19 (C): status bar
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_horizontally.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_horizontally.snap
new file mode 100644
index 00000000..f4322702
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_horizontally.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3955
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ────────────────────────────────────────────────────────┐┌ Pane #2 ───────────────────────────────────────────┐
+01 (C): │ │┌ Pane #3 ───────────────────────────────────────────┐
+02 (C): │ │┌ Pane #4 ───────────────────────────────────────────┐
+03 (C): │ │┌ Pane #5 ───────────────────────────────────────────┐
+04 (C): │ │┌ Pane #6 ───────────────────────────────────────────┐
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └─────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_non_directionally.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_non_directionally.snap
new file mode 100644
index 00000000..997af6c2
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_non_directionally.snap
@@ -0,0 +1,46 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4062
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+13 (C): ┌ Pane #2 ────────────────────────────────────────────────────────┐┌ Pane #4 ───────────────────────────────────────────┐
+14 (C): │ │┌ Pane #5 ───────────────────────────────────────────┐
+15 (C): │ │┌ Pane #6 ───────────────────────────────────────────┐
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): │ ││ │
+20 (C): │ ││ │
+21 (C): │ ││ │
+22 (C): │ ││ │
+23 (C): │ ││ │
+24 (C): │ ││ │
+25 (C): │ ││ │
+26 (C): │ ││ │
+27 (C): └─────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────────┘
+28 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+29 (C): │ │
+30 (C): │ │
+31 (C): │ │
+32 (C): │ │
+33 (C): │ │
+34 (C): │ │
+35 (C): │ │
+36 (C): │ │
+37 (C): │ │
+38 (C): │ │
+39 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_vertically.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_vertically.snap
new file mode 100644
index 00000000..b800c634
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_vertically.snap
@@ -0,0 +1,46 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4047
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+13 (C): ┌ Pane #2 ──────────────────────────────────────────────────┐┌ Pane #4 ─────────────────────────────────────────────────┐
+14 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+15 (C): │ │┌ Pane #6 ─────────────────────────────────────────────────┐
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): │ ││ │
+20 (C): │ ││ │
+21 (C): │ ││ │
+22 (C): │ ││ │
+23 (C): │ ││ │
+24 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+25 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+26 (C): │ │
+27 (C): │ │
+28 (C): │ │
+29 (C): │ │
+30 (C): │ │
+31 (C): │ │
+32 (C): │ │
+33 (C): │ │
+34 (C): │ │
+35 (C): │ │
+36 (C): │ │
+37 (C): │ │
+38 (C): │ │
+39 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_horizontally.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_horizontally.snap
new file mode 100644
index 00000000..ecee6a70
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_horizontally.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3716
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ───────────────────────────────────────────┐┌ Pane #2 ────────────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #3 ────────────────────────────────────────────────────────┐
+02 (C): │ │┌ Pane #4 ────────────────────────────────────────────────────────┐
+03 (C): │ │┌ Pane #5 ────────────────────────────────────────────────────────┐
+04 (C): │ │┌ Pane #6 ────────────────────────────────────────────────────────┐
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └────────────────────────────────────────────────────┘└─────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_non_directionally.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_non_directionally.snap
new file mode 100644
index 00000000..bcd3b4ee
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_non_directionally.snap
@@ -0,0 +1,46 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3823
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+13 (C): ┌ Pane #2 ───────────────────────────────────────────┐┌ Pane #4 ────────────────────────────────────────────────────────┐
+14 (C): │ │┌ Pane #5 ────────────────────────────────────────────────────────┐
+15 (C): │ │┌ Pane #6 ────────────────────────────────────────────────────────┐
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): │ ││ │
+20 (C): │ ││ │
+21 (C): │ ││ │
+22 (C): │ ││ │
+23 (C): │ ││ │
+24 (C): │ ││ │
+25 (C): │ ││ │
+26 (C): │ ││ │
+27 (C): └────────────────────────────────────────────────────┘└─────────────────────────────────────────────────────────────────┘
+28 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+29 (C): │ │
+30 (C): │ │
+31 (C): │ │
+32 (C): │ │
+33 (C): │ │
+34 (C): │ │
+35 (C): │ │
+36 (C): │ │
+37 (C): │ │
+38 (C): │ │
+39 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_vertically.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_vertically.snap
new file mode 100644
index 00000000..b5dea0aa
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_vertically.snap
@@ -0,0 +1,46 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3807
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+13 (C): ┌ Pane #2 ──────────────────────────────────────────────────┐┌ Pane #4 ─────────────────────────────────────────────────┐
+14 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+15 (C): │ │┌ Pane #6 ─────────────────────────────────────────────────┐
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): │ ││ │
+20 (C): │ ││ │
+21 (C): │ ││ │
+22 (C): │ ││ │
+23 (C): │ ││ │
+24 (C): │ ││ │
+25 (C): │ ││ │
+26 (C): │ ││ │
+27 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+28 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+29 (C): │ │
+30 (C): │ │
+31 (C): │ │
+32 (C): │ │
+33 (C): │ │
+34 (C): │ │
+35 (C): │ │
+36 (C): │ │
+37 (C): │ │
+38 (C): │ │
+39 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_between_multiple_layouts.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_between_multiple_layouts.snap
new file mode 100644
index 00000000..b7f08c8a
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_between_multiple_layouts.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3064
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ─────────────────────────────────────────────────┐┌ Pane #2 ──────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └──────────────────────────────────────────────────────────┘└───────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_floating_layout_at_runtime.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_floating_layout_at_runtime.snap
new file mode 100644
index 00000000..04fa9400
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_floating_layout_at_runtime.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3022
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): ┌ Pane #2 ─────────────────────────────────────────────────┐ ┌ Pane #3 ─────────────────────────────────────────────────┐
+06 (C): │ │ │ │
+07 (C): │ │ │ │
+08 (C): │ │ │ │
+09 (C): │ │ │ │
+10 (C): │ │ │ │
+11 (C): │ │ │ │
+12 (C): │ │ │ │
+13 (C): │ │ │ │
+14 (C): └──────────────────────────────────────────────────────────┘ └──────────────────────────────────────────────────────────┘
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_tiled_layout_at_runtime.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_tiled_layout_at_runtime.snap
new file mode 100644
index 00000000..e14c889a
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_tiled_layout_at_runtime.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 2977
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+10 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+11 (C): │ │
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__cannot_decrease_stack_size_beyond_minimum_height.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__cannot_decrease_stack_size_beyond_minimum_height.snap
new file mode 100644
index 00000000..8416d6e0
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__cannot_decrease_stack_size_beyond_minimum_height.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4346
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+02 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+03 (C): │ │┌ Pane #6 ─────────────────────────────────────────────────┐
+04 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+05 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_main_stacked_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_main_stacked_pane.snap
new file mode 100644
index 00000000..1260736f
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_main_stacked_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3536
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_main_stacked_pane_in_mid_stack.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_main_stacked_pane_in_mid_stack.snap
new file mode 100644
index 00000000..071b2413
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_main_stacked_pane_in_mid_stack.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3590
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+02 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ │└──────────────────────────────────────────────────────────┘
+19 (C): └───────────────────────────────────────────────────────────┘└ Pane #6 ─────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_one_liner_stacked_pane_above_main_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_one_liner_stacked_pane_above_main_pane.snap
new file mode 100644
index 00000000..17d9500e
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_one_liner_stacked_pane_above_main_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3699
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ │└──────────────────────────────────────────────────────────┘
+18 (C): │ │└ Pane #5 ─────────────────────────────────────────────────┘
+19 (C): └───────────────────────────────────────────────────────────┘└ Pane #6 ─────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_one_liner_stacked_pane_below_main_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_one_liner_stacked_pane_below_main_pane.snap
new file mode 100644
index 00000000..fffc3a7d
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_one_liner_stacked_pane_below_main_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3645
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ │└──────────────────────────────────────────────────────────┘
+18 (C): │ │└ Pane #5 ─────────────────────────────────────────────────┘
+19 (C): └───────────────────────────────────────────────────────────┘└ Pane #6 ─────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_pane_near_stacked_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_pane_near_stacked_panes.snap
new file mode 100644
index 00000000..f9d93989
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_pane_near_stacked_panes.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4574
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+02 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+03 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_stacked_pane_with_previously_focused_other_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_stacked_pane_with_previously_focused_other_pane.snap
new file mode 100644
index 00000000..b065d0bc
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_stacked_pane_with_previously_focused_other_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4517
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ │└──────────────────────────────────────────────────────────┘
+09 (C): └───────────────────────────────────────────────────────────┘└ Pane #6 ─────────────────────────────────────────────────┘
+10 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+11 (C): │ │
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__decreasing_size_of_whole_tab_treats_stacked_panes_properly.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__decreasing_size_of_whole_tab_treats_stacked_panes_properly.snap
new file mode 100644
index 00000000..913206c0
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__decreasing_size_of_whole_tab_treats_stacked_panes_properly.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4195
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ───────────────────────────────────────┐┌ Pane #2 ───────────────────────────────────────┐
+01 (C): │ │┌ Pane #3 ───────────────────────────────────────┐
+02 (C): │ │┌ Pane #4 ───────────────────────────────────────┐
+03 (C): │ │┌ Pane #5 ───────────────────────────────────────┐
+04 (C): │ │┌ Pane #6 ───────────────────────────────────────┐
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): └────────────────────────────────────────────────┘└────────────────────────────────────────────────┘
+10 (C):
+11 (C):
+12 (C):
+13 (C):
+14 (C):
+15 (C):
+16 (C):
+17 (C):
+18 (C):
+19 (C):
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_layout_with_plugins_and_commands_swaped_properly.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_layout_with_plugins_and_commands_swaped_properly.snap
new file mode 100644
index 00000000..11b9b669
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_layout_with_plugins_and_commands_swaped_properly.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5402
+expression: snapshot
+---
+00 (C): ┌ status-bar ──────────────────────────────────────────────┐─────────────────────────────────────────────────┐──────────┐
+01 (C): │I am a │b bar │ │
+02 (C): │status bar │ │ │
+03 (C): │ │ │ │
+04 (C): │ │ │ │
+05 (C): │ │ │ │
+06 (C): │ │ │ │
+07 (C): │ │ │ │
+08 (C): │ │ │ │
+09 (C): └──────────────────────────────────────────────────────────┘─────────────────────────────────────────────────┘ │
+10 (C): ┌ command2 ───────────────────│ ┌ command1 ────────────────────────────────────────────────┐ │
+11 (C): │ │ │ │ │
+12 (C): │ │ │ │ │
+13 (C): │ │ │ │ │
+14 (C): │ Waiting to ru└───────────────────│ Waiting to run: command1 │ │
+15 (C): │ │ │ │
+16 (C): │ <ENTER> to run, <Ctrl-c> to exit │ <ENTER> to run, <Ctrl-c> to exit │ │
+17 (C): │ │ │ │
+18 (C): │ │ │ │
+19 (C): └─────────────────────────────────────────────────└──────────────────────────────────────────────────────────┘──────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_next_pane_expands_stacked_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_next_pane_expands_stacked_panes.snap
new file mode 100644
index 00000000..fec3d753
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_next_pane_expands_stacked_panes.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4628
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ │└──────────────────────────────────────────────────────────┘
+07 (C): │ │└ Pane #4 ─────────────────────────────────────────────────┘
+08 (C): │ │└ Pane #5 ─────────────────────────────────────────────────┘
+09 (C): └───────────────────────────────────────────────────────────┘└ Pane #6 ─────────────────────────────────────────────────┘
+10 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+11 (C): │ │
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_stacked_pane_over_flexible_pane_with_the_mouse.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_stacked_pane_over_flexible_pane_with_the_mouse.snap
new file mode 100644
index 00000000..77530c7c
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_stacked_pane_over_flexible_pane_with_the_mouse.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4399
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ │└──────────────────────────────────────────────────────────┘
+08 (C): │ │└ Pane #5 ─────────────────────────────────────────────────┘
+09 (C): └───────────────────────────────────────────────────────────┘└ Pane #6 ─────────────────────────────────────────────────┘
+10 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+11 (C): │ │
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_stacked_pane_under_flexible_pane_with_the_mouse.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_stacked_pane_under_flexible_pane_with_the_mouse.snap
new file mode 100644
index 00000000..41100f1e
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_stacked_pane_under_flexible_pane_with_the_mouse.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4454
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+02 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+03 (C): │ │┌ Pane #6 ─────────────────────────────────────────────────┐
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+10 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+11 (C): │ │
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_into_main_pane_in_stack_horizontally_does_not_break_stack.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_into_main_pane_in_stack_horizontally_does_not_break_stack.snap
new file mode 100644
index 00000000..417fe7cd
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_into_main_pane_in_stack_horizontally_does_not_break_stack.snap
@@ -0,0 +1,46 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4178
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+13 (C): ┌ Pane #2 ────────────────────────────────────────────────────────┐┌ Pane #4 ───────────────────────────────────────────┐
+14 (C): │ │┌ Pane #6 ───────────────────────────────────────────┐
+15 (C): │ │┌ Pane #7 ───────────────────────────────────────────┐
+16 (C): │ │┌ Pane #8 ───────────────────────────────────────────┐
+17 (C): │ │┌ Pane #9 ───────────────────────────────────────────┐
+18 (C): │ │┌ Pane #10 ──────────────────────────────────────────┐
+19 (C): └─────────────────────────────────────────────────────────────────┘┌ Pane #11 ──────────────────────────────────────────┐
+20 (C): ┌ Pane #3 ────────────────────────────────────────────────────────┐│ │
+21 (C): │ ││ │
+22 (C): │ ││ │
+23 (C): │ ││ │
+24 (C): │ ││ │
+25 (C): │ ││ │
+26 (C): └─────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────────┘
+27 (C): ┌ Pane #5 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+28 (C): │ │
+29 (C): │ │
+30 (C): │ │
+31 (C): │ │
+32 (C): │ │
+33 (C): │ │
+34 (C): │ │
+35 (C): │ │
+36 (C): │ │
+37 (C): │ │
+38 (C): │ │
+39 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_of_main_pane_in_stack_horizontally_does_not_break_stack.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_of_main_pane_in_stack_horizontally_does_not_break_stack.snap
new file mode 100644
index 00000000..530bc567
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_of_main_pane_in_stack_horizontally_does_not_break_stack.snap
@@ -0,0 +1,46 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3942
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+13 (C): ┌ Pane #2 ───────────────────────────────────────────┐┌ Pane #4 ────────────────────────────────────────────────────────┐
+14 (C): │ │┌ Pane #6 ────────────────────────────────────────────────────────┐
+15 (C): │ │┌ Pane #7 ────────────────────────────────────────────────────────┐
+16 (C): │ │┌ Pane #8 ────────────────────────────────────────────────────────┐
+17 (C): │ │┌ Pane #9 ────────────────────────────────────────────────────────┐
+18 (C): │ │┌ Pane #10 ───────────────────────────────────────────────────────┐
+19 (C): └────────────────────────────────────────────────────┘┌ Pane #11 ───────────────────────────────────────────────────────┐
+20 (C): ┌ Pane #3 ───────────────────────────────────────────┐┌ Pane #12 ───────────────────────────────────────────────────────┐
+21 (C): │ ││ │
+22 (C): │ ││ │
+23 (C): │ ││ │
+24 (C): │ ││ │
+25 (C): │ ││ │
+26 (C): └────────────────────────────────────────────────────┘└─────────────────────────────────────────────────────────────────┘
+27 (C): ┌ Pane #5 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+28 (C): │ │
+29 (C): │ │
+30 (C): │ │
+31 (C): │ │
+32 (C): │ │
+33 (C): │ │
+34 (C): │ │
+35 (C): │ │
+36 (C): │ │
+37 (C): │ │
+38 (C): │ │
+39 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_of_whole_tab_treats_stacked_panes_properly.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_of_whole_tab_treats_stacked_panes_properly.snap
new file mode 100644
index 00000000..df202642
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_of_whole_tab_treats_stacked_panes_properly.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4253
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+02 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+03 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+04 (C): │ │┌ Pane #6 ─────────────────────────────────────────────────┐
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__layout_with_plugins_and_commands_swaped_properly.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__layout_with_plugins_and_commands_swaped_properly.snap
new file mode 100644
index 00000000..6be12af6
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__layout_with_plugins_and_commands_swaped_properly.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4689
+expression: snapshot
+---
+00 (C): I am a
+01 (C): status bar
+02 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+03 (C): │ │
+04 (C): │ Waiting to run: command2 │
+05 (C): │ │
+06 (C): │ <ENTER> to run, <Ctrl-c> to exit │
+07 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+08 (C): ┌ command1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+09 (C): │ │
+10 (C): │ Waiting to run: command1 │
+11 (C): │ │
+12 (C): │ <ENTER> to run, <Ctrl-c> to exit │
+13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+14 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+19 (C): I am a tab bar
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_down_into_stacked_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_down_into_stacked_panes.snap
new file mode 100644
index 00000000..9fee9b1e
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_down_into_stacked_panes.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3492
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #6 ─────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+07 (C): ┌ Pane #2 ──────────────────────────────────────────────────┐┌ Pane #4 ─────────────────────────────────────────────────┐
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ │└──────────────────────────────────────────────────────────┘
+13 (C): └───────────────────────────────────────────────────────────┘└ Pane #5 ─────────────────────────────────────────────────┘
+14 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_down_with_stacked_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_down_with_stacked_panes.snap
new file mode 100644
index 00000000..1dfa52c7
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_down_with_stacked_panes.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3269
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+02 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_left_into_stacked_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_left_into_stacked_panes.snap
new file mode 100644
index 00000000..6a0d0d7e
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_left_into_stacked_panes.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3378
+expression: snapshot
+---
+00 (C): ┌ Pane #3 ──────────────────────────────────────────────────┐┌ Pane #7 ─────────────────────────────────────────────────┐
+01 (C): ┌ Pane #2 ──────────────────────────────────────────────────┐│ │
+02 (C): ┌ Pane #4 ──────────────────────────────────────────────────┐│ │
+03 (C): ┌ Pane #5 ──────────────────────────────────────────────────┐│ │
+04 (C): ┌ Pane #6 ──────────────────────────────────────────────────┐│ │
+05 (C): ┌ Pane #8 ──────────────────────────────────────────────────┐│ │
+06 (C): ┌ Pane #9 ──────────────────────────────────────────────────┐│ │
+07 (C): ┌ Pane #10 ─────────────────────────────────────────────────┐│ │
+08 (C): ┌ Pane #11 ─────────────────────────────────────────────────┐│ │
+09 (C): ┌ Pane #12 ─────────────────────────────────────────────────┐└──────────────────────────────────────────────────────────┘
+10 (C): ┌ Pane #13 ─────────────────────────────────────────────────┐┌ Pane #15 ────────────────────────────────────────────────┐
+11 (C): ┌ Pane #14 ─────────────────────────────────────────────────┐│ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_right_into_stacked_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_right_into_stacked_panes.snap
new file mode 100644
index 00000000..3acd26d8
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_right_into_stacked_panes.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3324
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+02 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+03 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+04 (C): │ │┌ Pane #6 ─────────────────────────────────────────────────┐
+05 (C): │ │┌ Pane #7 ─────────────────────────────────────────────────┐
+06 (C): │ │┌ Pane #8 ─────────────────────────────────────────────────┐
+07 (C): │ │┌ Pane #9 ─────────────────────────────────────────────────┐
+08 (C): │ │┌ Pane #10 ────────────────────────────────────────────────┐
+09 (C): └───────────────────────────────────────────────────────────┘┌ Pane #11 ────────────────────────────────────────────────┐
+10 (C): ┌ Pane #14 ─────────────────────────────────────────────────┐┌ Pane #12 ────────────────────────────────────────────────┐
+11 (C): │ │┌ Pane #13 ────────────────────────────────────────────────┐
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_up_into_stacked_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_up_into_stacked_panes.snap
new file mode 100644
index 00000000..e8e3dd7c
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_up_into_stacked_panes.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3434
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+07 (C): ┌ Pane #2 ──────────────────────────────────────────────────┐┌ Pane #4 ─────────────────────────────────────────────────┐
+08 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+14 (C): ┌ Pane #3 ──────────────────────────────────────────────────┐┌ Pane #6 ─────────────────────────────────────────────────┐
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_up_with_stacked_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_up_with_stacked_panes.snap
new file mode 100644
index 00000000..c5d5de95
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_up_with_stacked_panes.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3222
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ │└──────────────────────────────────────────────────────────┘
+19 (C): └───────────────────────────────────────────────────────────┘└ Pane #4 ─────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_with_stacked_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_with_stacked_panes.snap
new file mode 100644
index 00000000..254e671a
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_with_stacked_panes.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3185
+expression: snapshot
+---
+00 (C): ┌ Pane #4 ─────────────────────────────────────────────────┐┌ Pane #1 ──────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #2 ──────────────────────────────────────────────────┐
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ │└───────────────────────────────────────────────────────────┘
+19 (C): └──────────────────────────────────────────────────────────┘┌ Pane #3 ──────────────────────────────────────────────────┐
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-2.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-2.snap
new file mode 100644
index 00000000..cdef4812
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-2.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5799
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ ┌ Pane #2 ────────────────────────────────────────────┐ ┌ Pane #3 ────────────────────────────────────────────┐ │
+06 (C): │ │ │ │ │ │
+07 (C): │ │ │ │ │ │
+08 (C): │ │ │ │ │ │
+09 (C): │ │ │ │ │ │
+10 (C): │ │ │ │ │ │
+11 (C): │ │ │ │ │ │
+12 (C): │ │ │ │ │ │
+13 (C): │ │ │ │ │ │
+14 (C): │ └─────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────┘ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-3.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-3.snap
new file mode 100644
index 00000000..b5c19c92
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-3.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5799
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ ┌ Pane #3 ────────────────────────────────────────────┐ ┌ Pane #2 ────────────────────────────────────────────┐ │
+02 (C): │ │ │ │ │ │
+03 (C): │ │ │ │ │ │
+04 (C): │ │ │ │ │ │
+05 (C): │ │ │ │ │ │
+06 (C): │ │ │ │ │ │
+07 (C): │ │ │ │ │ │
+08 (C): │ │ │ │ │ │
+09 (C): │ │ │ │ │ │
+10 (C): │ └─────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────┘ │
+11 (C): │ ┌ Pane #4 ────────────────────────────────────────────┐ │
+12 (C): │ │ │ │
+13 (C): │ │ │ │
+14 (C): │ │ │ │
+15 (C): │ │ │ │
+16 (C): │ │ │ │
+17 (C): │ │ │ │
+18 (C): │ │ │ │
+19 (C): └─────────────────────────────└─────────────────────────────────────────────────────┘───────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout.snap
new file mode 100644
index 00000000..d6c84185
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5799
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐
+11 (C): │ │ │
+12 (C): │ │ │
+13 (C): │ │ │
+14 (C): │ │ │
+15 (C): │ │ │
+16 (C): │ │ │
+17 (C): │ │ │
+18 (C): │ │ │
+19 (C): └────────────────────────────────────────────────────────────└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-2.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-2.snap
new file mode 100644
index 00000000..241910dc
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-2.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5099
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ │└──────────────────────────────────────────────────────────┘
+10 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-3.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-3.snap
new file mode 100644
index 00000000..764303eb
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-3.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5099
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ │└──────────────────────────────────────────────────────────┘
+07 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ │└──────────────────────────────────────────────────────────┘
+14 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-4.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-4.snap
new file mode 100644
index 00000000..2e426650
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-4.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5099
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ │└──────────────────────────────────────────────────────────┘
+05 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ │└──────────────────────────────────────────────────────────┘
+10 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ │└──────────────────────────────────────────────────────────┘
+15 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-5.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-5.snap
new file mode 100644
index 00000000..469f2b26
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-5.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5099
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ │└──────────────────────────────────────────────────────────┘
+05 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+10 (C): ┌ Pane #6 ──────────────────────────────────────────────────┐┌ Pane #4 ─────────────────────────────────────────────────┐
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ │└──────────────────────────────────────────────────────────┘
+15 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-6.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-6.snap
new file mode 100644
index 00000000..caf0b98a
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-6.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5099
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ │└──────────────────────────────────────────────────────────┘
+05 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+06 (C): └───────────────────────────────────────────────────────────┘│ │
+07 (C): ┌ Pane #6 ──────────────────────────────────────────────────┐│ │
+08 (C): │ ││ │
+09 (C): │ │└──────────────────────────────────────────────────────────┘
+10 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): └───────────────────────────────────────────────────────────┘│ │
+14 (C): ┌ Pane #7 ──────────────────────────────────────────────────┐└──────────────────────────────────────────────────────────┘
+15 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-7.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-7.snap
new file mode 100644
index 00000000..8956fb0f
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-7.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5099
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+05 (C): ┌ Pane #6 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+10 (C): ┌ Pane #7 ──────────────────────────────────────────────────┐┌ Pane #4 ─────────────────────────────────────────────────┐
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+15 (C): ┌ Pane #8 ──────────────────────────────────────────────────┐┌ Pane #5 ─────────────────────────────────────────────────┐
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout.snap
new file mode 100644
index 00000000..71021120
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5097
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_tab_with_floating_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_tab_with_floating_panes.snap
index e90a13dc..da14ad29 100644
--- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_tab_with_floating_panes.snap
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_tab_with_floating_panes.snap
@@ -1,6 +1,6 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
-assertion_line: 1371
+assertion_line: 1544
expression: snapshot
---
00 (C): ┌ Pane #1 ────────────────────┌ ┌ ┌ Pane #4 ─────────────────────────────────── SCROLL: 0/1 ┐─────┐
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap
index d4e106aa..2a886db7 100644
--- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap
@@ -1,6 +1,6 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
-assertion_line: 1801
+assertion_line: 2220
expression: snapshot
---
00 (C): ┌ Pane #1 ────────────────────┌ EDITING SCROLLBACK ──────────────────────────────────────┐─────────┐
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically.snap
index e6f1786c..cfa37b74 100644
--- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically.snap
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically.snap
@@ -1,6 +1,6 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
-assertion_line: 1421
+assertion_line: 1594
expression: snapshot
---
00 (C): ┌ Pane #1 ────────────────────┌ ┌ ┌ Pane #4 ── 0 ┐
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_back.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_back.snap
index a005424f..a7c0f582 100644
--- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_back.snap
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_back.snap
@@ -1,6 +1,6 @@
---
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
-assertion_line: 1475
+assertion_line: 1648
expression: snapshot
---
00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__stacked_panes_can_become_fullscreen.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__stacked_panes_can_become_fullscreen.snap
new file mode 100644
index 00000000..746d110e
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__stacked_panes_can_become_fullscreen.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4667
+expression: snapshot
+---
+00 (C): ┌ Pane #5 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_command_panes_absent_from_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_command_panes_absent_from_existing_layout.snap
new file mode 100644
index 00000000..6bdd963e
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_command_panes_absent_from_existing_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5541
+expression: snapshot
+---
+00 (C): ┌ Pane #2 ─────────────────────────────────────────────────┐────────────────────────────────────────────────────────────┐
+01 (C): │ │ │
+02 (C): │ │ │
+03 (C): │ │ │
+04 (C): │ │ │
+05 (C): │ ┌ status-bar ──────────────────────────────────────────────┐ │
+06 (C): │ │I am a │ │
+07 (C): │ │status bar │─┐ │
+08 (C): │ │ │ │ │
+09 (C): └─────────────────────────────│ │───┐ │
+10 (C): │ ┌ Pane #3 ──────────│ │ │ │
+11 (C): │ │ │ │ │ │
+12 (C): │ │ │ │ │ │
+13 (C): │ │ │ │ │ │
+14 (C): │ │ └──────────────────────────────────────────────────────────┘ │ │
+15 (C): │ │ │ │ │ │
+16 (C): │ │ └─│ │ │
+17 (C): │ │ │ │ │
+18 (C): │ │ └──────────────────────────────────────────────────────────┘ │
+19 (C): └─────────└──────────────────────────────────────────────────────────┘──────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_plugin_panes_absent_from_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_plugin_panes_absent_from_existing_layout.snap
new file mode 100644
index 00000000..2f06d931
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_plugin_panes_absent_from_existing_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5672
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │
+06 (C): │ │ │ │
+07 (C): │ │ ┌ Pane #3 ─────────────────────────────────────────────────┐ │
+08 (C): │ │ │ │ │
+09 (C): │ │ │ ┌ Pane #4 ─────────────────────────────────────────────────┐ │
+10 (C): │ │ │ │ │ │
+11 (C): │ │ │ │ │ │
+12 (C): │ │ │ │ │ │
+13 (C): │ │ │ │ │ │
+14 (C): │ └─│ │ │ │
+15 (C): │ │ │ │ │
+16 (C): │ └─│ │ │
+17 (C): │ │ │ │
+18 (C): │ └──────────────────────────────────────────────────────────┘ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_command_panes_present_in_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_command_panes_present_in_existing_layout.snap
new file mode 100644
index 00000000..29553797
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_command_panes_present_in_existing_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5614
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ ┌ command2 ────────────────────────────┐ │
+03 (C): │ │ │ │
+04 (C): │ │ ┌ tab-bar ─────────────────────────────┐ │
+05 (C): │ │ │I am a tab bar ┌ status-bar ──────────────────────────────────────────────┐ │
+06 (C): │ │ │ │I am a │ │
+07 (C): │ └─│ │status bar │─┐ │
+08 (C): │ │ │ │ │ │
+09 (C): │ └─────────────────────────│ │───┐ │
+10 (C): │ │ │ │ │
+11 (C): │ │ │ │ │
+12 (C): │ │ │ │ │
+13 (C): │ │ │ │ │
+14 (C): │ └──────────────────────────────────────────────────────────┘ │ │
+15 (C): │ │ │ <ENTER> to run, <Ctrl-c> to exit │ │
+16 (C): │ └─│ │ │
+17 (C): │ │ │ │
+18 (C): │ └──────────────────────────────────────────────────────────┘ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_plugin_panes_present_in_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_plugin_panes_present_in_existing_layout.snap
new file mode 100644
index 00000000..e6baccbe
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_plugin_panes_present_in_existing_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5734
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │
+06 (C): │ │ │ │
+07 (C): │ │ ┌ tab-bar ─────────────────────────────────────────────────┐ │
+08 (C): │ │ │I am a tab bar │ │
+09 (C): │ │ │ ┌ status-bar ──────────────────────────────────────────────┐ │
+10 (C): │ │ │ │I am a │ │
+11 (C): │ │ │ │status bar │ │
+12 (C): │ │ │ │ │ │
+13 (C): │ │ │ │ │ │
+14 (C): │ └─│ │ │ │
+15 (C): │ │ │ │ │
+16 (C): │ └─│ │ │
+17 (C): │ │ │ │
+18 (C): │ └──────────────────────────────────────────────────────────┘ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_including_command_panes_absent_from_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_including_command_panes_absent_from_existing_layout.snap
new file mode 100644
index 00000000..5b7bd24e
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_including_command_panes_absent_from_existing_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4831
+expression: snapshot
+---
+00 (C): I am a
+01 (C): status bar
+02 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+08 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): │ │
+13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+14 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+19 (C): I am a tab bar
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_including_plugin_panes_absent_from_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_including_plugin_panes_absent_from_existing_layout.snap
new file mode 100644
index 00000000..df1a8e09
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_including_plugin_panes_absent_from_existing_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4966
+expression: snapshot
+---
+00 (C):
+01 (C):
+02 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+11 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_command_panes_present_in_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_command_panes_present_in_existing_layout.snap
new file mode 100644
index 00000000..dd0cbbd7
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_command_panes_present_in_existing_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 4904
+expression: snapshot
+---
+00 (C): I am a
+01 (C): status bar
+02 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+08 (C): ┌ command1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+09 (C): │ │
+10 (C): │ Waiting to run: command1 │
+11 (C): │ │
+12 (C): │ <ENTER> to run, <Ctrl-c> to exit │
+13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+14 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+15 (C): │ Waiting to run: command2 │
+16 (C): │ │
+17 (C): │ <ENTER> to run, <Ctrl-c> to exit │
+18 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+19 (C): I am a tab bar
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_plugin_panes_present_in_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_plugin_panes_present_in_existing_layout.snap
new file mode 100644
index 00000000..258ea58b
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_plugin_panes_present_in_existing_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5035
+expression: snapshot
+---
+00 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+02 (C): ┌ command1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+03 (C): │ │
+04 (C): │ Waiting to run: command1 │
+05 (C): │ │
+06 (C): │ <ENTER> to run, <Ctrl-c> to exit │
+07 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+08 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+09 (C): │ │
+10 (C): │ Waiting to run: command2 │
+11 (C): │ │
+12 (C): │ <ENTER> to run, <Ctrl-c> to exit │
+13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+14 (C): ┌ status-bar ───────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+15 (C): │I am a │
+16 (C): │status bar │
+17 (C): │ │
+18 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+19 (C): ┌ tab-bar ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_tiled_layout_with_stacked_children.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_tiled_layout_with_stacked_children.snap
new file mode 100644
index 00000000..4a51d490
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_tiled_layout_with_stacked_children.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3176
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐
+02 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_tiled_layout_with_stacked_children_and_no_pane_frames.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_tiled_layout_with_stacked_children_and_no_pane_frames.snap
new file mode 100644
index 00000000..7174f10a
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_tiled_layout_with_stacked_children_and_no_pane_frames.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3204
+expression: snapshot
+---
+00 (C): ├─ Pane #2 ─────────────────────────────────────────────────
+01 (C): ├─ Pane #3 ─────────────────────────────────────────────────
+02 (C): ├─ Pane #4 ─────────────────────────────────────────────────
+03 (C): │
+04 (C): │
+05 (C): │
+06 (C): │
+07 (C): │
+08 (C): │
+09 (C): │
+10 (C): │
+11 (C): │
+12 (C): │
+13 (C): │
+14 (C): │
+15 (C): │
+16 (C): │
+17 (C): │
+18 (C): │
+19 (C): │
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swapping_layouts_after_resize_snaps_to_current_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swapping_layouts_after_resize_snaps_to_current_layout.snap
new file mode 100644
index 00000000..4322a975
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swapping_layouts_after_resize_snaps_to_current_layout.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 3132
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
+01 (C): │ ││ │
+02 (C): │ ││ │
+03 (C): │ ││ │
+04 (C): │ ││ │
+05 (C): │ ││ │
+06 (C): │ ││ │
+07 (C): │ ││ │
+08 (C): │ ││ │
+09 (C): │ ││ │
+10 (C): │ ││ │
+11 (C): │ ││ │
+12 (C): │ ││ │
+13 (C): │ ││ │
+14 (C): │ ││ │
+15 (C): │ ││ │
+16 (C): │ ││ │
+17 (C): │ ││ │
+18 (C): │ ││ │
+19 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_floating_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_floating_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap
new file mode 100644
index 00000000..331e678b
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_floating_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 6028
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ ┌ Pane #3 ─────────────────────────────────────────────────┐ │
+06 (C): │ │ │ │
+07 (C): │ │ │─┐ │
+08 (C): │ │ │ │ │
+09 (C): │ │ │ │ │
+10 (C): │ │ │ │ │
+11 (C): │ │ │ │ │
+12 (C): │ │ │ │ │
+13 (C): │ │ │ │ │
+14 (C): │ └──────────────────────────────────────────────────────────┘ │ │
+15 (C): │ │ │ │
+16 (C): │ └──────────────────────────────────────────────────────────┘ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap
new file mode 100644
index 00000000..8f548b1d
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5333
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+10 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+11 (C): │ │
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_resizing_whole_tab_with_auto_layout_and_floating_panes_the_layout_is_maintained.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_resizing_whole_tab_with_auto_layout_and_floating_panes_the_layout_is_maintained.snap
new file mode 100644
index 00000000..26bcb978
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_resizing_whole_tab_with_auto_layout_and_floating_panes_the_layout_is_maintained.snap
@@ -0,0 +1,36 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 6079
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ ┌ Pane #2 ────────────────────────────────────────────────────────────────┐ │
+09 (C): │ │ │ │
+10 (C): │ │ ┌ Pane #3 ────────────────────────────────────────────────────────────────┐ │
+11 (C): │ │ │ │ │
+12 (C): │ │ │ ┌ Pane #4 ────────────────────────────────────────────────────────────────┐ │
+13 (C): │ │ │ │ │ │
+14 (C): │ │ │ │ │ │
+15 (C): │ │ │ │ │ │
+16 (C): │ │ │ │ │ │
+17 (C): │ │ │ │ │ │
+18 (C): │ │ │ │ │ │
+19 (C): │ │ │ │ │ │
+20 (C): │ │ │ │ │ │
+21 (C): │ │ │ │ │ │
+22 (C): │ └─│ │ │ │
+23 (C): │ │ │ │ │
+24 (C): │ └─│ │ │
+25 (C): │ │ │ │
+26 (C): │ └─────────────────────────────────────────────────────────────────────────┘ │
+27 (C): │ │
+28 (C): │ │
+29 (C): └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap
new file mode 100644
index 00000000..985cb317
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5859
+expression: snapshot
+---
+00 (C): ┌ Pane #2 ─────────────────────────────────────────────────┐────────────────────────────────────────────────────────────┐
+01 (C): │ │ │
+02 (C): │ │ │
+03 (C): │ │ │
+04 (C): │ │ │
+05 (C): │ ┌ Pane #3 ─────────────────────────────────────────────────┐ │
+06 (C): │ │ │ │
+07 (C): │ │ ┌ Pane #4 ─────────────────────────────────────────────────┐ │
+08 (C): │ │ │ │ │
+09 (C): └─────────────────────────────│ │ │ │
+10 (C): │ │ │ │ │
+11 (C): │ │ │ │ │
+12 (C): │ │ │ │ │
+13 (C): │ │ │ │ │
+14 (C): │ └─│ │ │
+15 (C): │ │ │ │
+16 (C): │ └──────────────────────────────────────────────────────────┘ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_an_undamaged_state_pane_focuses_on_focused_node.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_an_undamaged_state_pane_focuses_on_focused_node.snap
new file mode 100644
index 00000000..c42856cd
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_an_undamaged_state_pane_focuses_on_focused_node.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5915
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ ┌ Pane #4 ─────────────────────────────────────────────────┐ │
+06 (C): │ │ │ │
+07 (C): │ │ │─┐ │
+08 (C): │ │ │ │ │
+09 (C): │ │ │ │─┐ │
+10 (C): │ │ │ │ │ │
+11 (C): │ │ │ │ │ │
+12 (C): │ │ │ │ │ │
+13 (C): │ │ │ │ │ │
+14 (C): │ └──────────────────────────────────────────────────────────┘ │ │ │
+15 (C): │ │ │ │ │
+16 (C): │ └──────────────────────────────────────────────────────────┘ │ │
+17 (C): │ │ │ │
+18 (C): │ └──────────────────────────────────────────────────────────┘ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_an_undamaged_state_with_no_focus_node_pane_focuses_on_deepest_node.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_an_undamaged_state_with_no_focus_node_pane_focuses_on_deepest_node.snap
new file mode 100644
index 00000000..36c93e27
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_an_undamaged_state_with_no_focus_node_pane_focuses_on_deepest_node.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5970
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ ┌ Pane #4 ─────────────────────────────────────────────────┐ │
+06 (C): │ │ │ │
+07 (C): │ │ │─┐ │
+08 (C): │ │ │ │ │
+09 (C): │ │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │
+10 (C): │ │ │ │ │
+11 (C): │ │ │ │ │
+12 (C): │ │ │ │ │
+13 (C): │ │ │ │ │
+14 (C): │ └───│ │ │
+15 (C): │ │ │ │ │
+16 (C): │ └─│ │ │
+17 (C): │ │ │ │
+18 (C): │ └──────────────────────────────────────────────────────────┘ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap
new file mode 100644
index 00000000..7124c336
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5160
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+07 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): │ │
+13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+14 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_an_undamaged_state_pane_focuses_on_focused_node.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_an_undamaged_state_pane_focuses_on_focused_node.snap
new file mode 100644
index 00000000..ba1a4e3f
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_an_undamaged_state_pane_focuses_on_focused_node.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5216
+expression: snapshot
+---
+00 (C): ┌ Pane #2 ──────────────────────────────┐┌ Pane #1 ─────────────────────────────┐┌ Pane #3 ─────────────────────────────┐
+01 (C): │ ││ ││ │
+02 (C): │ ││ ││ │
+03 (C): │ ││ ││ │
+04 (C): │ ││ ││ │
+05 (C): │ ││ ││ │
+06 (C): │ ││ ││ │
+07 (C): │ ││ ││ │
+08 (C): │ ││ ││ │
+09 (C): │ ││ ││ │
+10 (C): │ ││ ││ │
+11 (C): │ ││ ││ │
+12 (C): │ ││ ││ │
+13 (C): │ ││ ││ │
+14 (C): │ ││ ││ │
+15 (C): │ ││ ││ │
+16 (C): │ ││ ││ │
+17 (C): │ ││ ││ │
+18 (C): │ ││ ││ │
+19 (C): └───────────────────────────────────────┘└──────────────────────────────────────┘└──────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_an_undamaged_state_with_no_focus_node_pane_focuses_on_deepest_node.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_an_undamaged_state_with_no_focus_node_pane_focuses_on_deepest_node.snap
new file mode 100644
index 00000000..d5f33377
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_tiled_layouts_in_an_undamaged_state_with_no_focus_node_pane_focuses_on_deepest_node.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 5274
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────┐┌ Pane #3 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐
+01 (C): │ ││ ││ │
+02 (C): │ ││ ││ │
+03 (C): │ ││ ││ │
+04 (C): │ ││ ││ │
+05 (C): │ ││ ││ │
+06 (C): │ ││ ││ │
+07 (C): │ ││ ││ │
+08 (C): │ ││ ││ │
+09 (C): │ ││ ││ │
+10 (C): │ ││ ││ │
+11 (C): │ ││ ││ │
+12 (C): │ ││ ││ │
+13 (C): │ ││ ││ │
+14 (C): │ ││ ││ │
+15 (C): │ ││ ││ │
+16 (C): │ ││ ││ │
+17 (C): │ ││ ││ │
+18 (C): │ ││ ││ │
+19 (C): └───────────────────────────────────────┘└──────────────────────────────────────┘└──────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs
index 63bfa3f3..3defa1e6 100644
--- a/zellij-server/src/tab/unit/tab_integration_tests.rs
+++ b/zellij-server/src/tab/unit/tab_integration_tests.rs
@@ -6,6 +6,7 @@ use crate::Mutex;
use crate::{
os_input_output::{AsyncReader, Pid, ServerOsApi},
panes::PaneId,
+ plugins::PluginInstruction,
thread_bus::ThreadSenders,
ClientId,
};
@@ -16,7 +17,11 @@ use zellij_utils::data::Resize;
use zellij_utils::data::ResizeStrategy;
use zellij_utils::envs::set_session_name;
use zellij_utils::errors::{prelude::*, ErrorContext};
-use zellij_utils::input::layout::{Layout, PaneLayout};
+use zellij_utils::input::layout::{
+ FloatingPaneLayout, Layout, RunPluginLocation, SwapFloatingLayout, SwapTiledLayout,
+ TiledPaneLayout,
+};
+use zellij_utils::input::plugins::PluginTag;
use zellij_utils::ipc::IpcReceiverWithContext;
use zellij_utils::pane_size::{Size, SizeInPixels};
use zellij_utils::position::Position;
@@ -197,6 +202,7 @@ fn create_new_tab(size: Size, default_mode: ModeInfo) -> Tab {
let mode_info = default_mode;
let style = Style::default();
let draw_pane_frames = true;
+ let auto_layout = true;
let client_id = 1;
let session_is_mirrored = true;
let mut connected_clients = HashSet::new();
@@ -220,15 +226,17 @@ fn create_new_tab(size: Size, default_mode: ModeInfo) -> Tab {
style,
mode_info,
draw_pane_frames,
+ auto_layout,
connected_clients,
session_is_mirrored,
client_id,
copy_options,
terminal_emulator_colors,
terminal_emulator_color_codes,
+ (vec![], vec![]),
);
tab.apply_layout(
- PaneLayout::default(),
+ TiledPaneLayout::default(),
vec![],
vec![(1, None)],
vec![],
@@ -239,6 +247,88 @@ fn create_new_tab(size: Size, default_mode: ModeInfo) -> Tab {
tab
}
+fn create_new_tab_with_swap_layouts(
+ size: Size,
+ default_mode: ModeInfo,
+ swap_layouts: (Vec<SwapTiledLayout>, Vec<SwapFloatingLayout>),
+ base_layout_and_ids: Option<(
+ TiledPaneLayout,
+ Vec<FloatingPaneLayout>,
+ Vec<(u32, Option<RunCommand>)>,
+ Vec<(u32, Option<RunCommand>)>,
+ HashMap<RunPluginLocation, Vec<u32>>,
+ )>,
+ draw_pane_frames: bool,
+) -> Tab {
+ set_session_name("test".into());
+ let index = 0;
+ let position = 0;
+ let name = String::new();
+ let os_api = Box::new(FakeInputOutput::default());
+ let mut senders = ThreadSenders::default().silently_fail_on_send();
+ let (mock_plugin_sender, _mock_plugin_receiver): ChannelWithContext<PluginInstruction> =
+ channels::unbounded();
+ senders.replace_to_plugin(SenderWithContext::new(mock_plugin_sender));
+ let max_panes = None;
+ let mode_info = default_mode;
+ let style = Style::default();
+ let auto_layout = true;
+ let client_id = 1;
+ let session_is_mirrored = true;
+ let mut connected_clients = HashSet::new();
+ connected_clients.insert(client_id);
+ let connected_clients = Rc::new(RefCell::new(connected_clients));
+ let character_cell_info = Rc::new(RefCell::new(None));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let copy_options = CopyOptions::default();
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let mut tab = Tab::new(
+ index,
+ position,
+ name,
+ size,
+ character_cell_info,
+ sixel_image_store,
+ os_api,
+ senders,
+ max_panes,
+ style,
+ mode_info,
+ draw_pane_frames,
+ auto_layout,
+ connected_clients,
+ session_is_mirrored,
+ client_id,
+ copy_options,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
+ swap_layouts,
+ );
+ let (
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ ) = base_layout_and_ids.unwrap_or_default();
+ let new_terminal_ids = if new_terminal_ids.is_empty() {
+ vec![(1, None)]
+ } else {
+ new_terminal_ids
+ };
+ tab.apply_layout(
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ client_id,
+ )
+ .unwrap();
+ tab
+}
+
fn create_new_tab_with_os_api(
size: Size,
default_mode: ModeInfo,
@@ -254,6 +344,7 @@ fn create_new_tab_with_os_api(
let mode_info = default_mode;
let style = Style::default();
let draw_pane_frames = true;
+ let auto_layout = true;
let client_id = 1;
let session_is_mirrored = true;
let mut connected_clients = HashSet::new();
@@ -277,15 +368,17 @@ fn create_new_tab_with_os_api(
style,
mode_info,
draw_pane_frames,
+ auto_layout,
connected_clients,
session_is_mirrored,
client_id,
copy_options,
terminal_emulator_colors,
terminal_emulator_color_codes,
+ (vec![], vec![]), // swap layouts
);
tab.apply_layout(
- PaneLayout::default(),
+ TiledPaneLayout::default(),
vec![],
vec![(1, None)],
vec![],
@@ -307,6 +400,7 @@ fn create_new_tab_with_layout(size: Size, default_mode: ModeInfo, layout: &str)
let mode_info = default_mode;
let style = Style::default();
let draw_pane_frames = true;
+ let auto_layout = true;
let client_id = 1;
let session_is_mirrored = true;
let mut connected_clients = HashSet::new();
@@ -317,7 +411,7 @@ fn create_new_tab_with_layout(size: Size, default_mode: ModeInfo, layout: &str)
let copy_options = CopyOptions::default();
let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
- let layout = Layout::from_str(layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_str(layout, "layout_file_name".into(), None, None).unwrap();
let (tab_layout, floating_panes_layout) = layout.new_tab();
let mut tab = Tab::new(
index,
@@ -332,12 +426,14 @@ fn create_new_tab_with_layout(size: Size, default_mode: ModeInfo, layout: &str)
style,
mode_info,
draw_pane_frames,
+ auto_layout,
connected_clients,
session_is_mirrored,
client_id,
copy_options,
terminal_emulator_colors,
terminal_emulator_color_codes,
+ (vec![], vec![]), // swap layouts
);
let pane_ids = tab_layout
.extract_run_instructions()
@@ -378,6 +474,7 @@ fn create_new_tab_with_mock_pty_writer(
let mode_info = default_mode;
let style = Style::default();
let draw_pane_frames = true;
+ let auto_layout = true;
let client_id = 1;
let session_is_mirrored = true;
let mut connected_clients = HashSet::new();
@@ -401,15 +498,17 @@ fn create_new_tab_with_mock_pty_writer(
style,
mode_info,
draw_pane_frames,
+ auto_layout,
connected_clients,
session_is_mirrored,
client_id,
copy_options,
terminal_emulator_colors,
terminal_emulator_color_codes,
+ (vec![], vec![]), // swap layouts
);
tab.apply_layout(
- PaneLayout::default(),
+ TiledPaneLayout::default(),
vec![],
vec![(1, None)],
vec![],
@@ -436,6 +535,7 @@ fn create_new_tab_with_sixel_support(
let mode_info = ModeInfo::default();
let style = Style::default();
let draw_pane_frames = true;
+ let auto_layout = true;
let client_id = 1;
let session_is_mirrored = true;
let mut connected_clients = HashSet::new();
@@ -461,15 +561,17 @@ fn create_new_tab_with_sixel_support(
style,
mode_info,
draw_pane_frames,
+ auto_layout,
connected_clients,
session_is_mirrored,
client_id,
copy_options,
terminal_emulator_colors,
terminal_emulator_color_codes,
+ (vec![], vec![]), // swap layouts
);
tab.apply_layout(
- PaneLayout::default(),
+ TiledPaneLayout::default(),
vec![],
vec![(1, None)],
vec![],
@@ -609,7 +711,7 @@ fn new_floating_pane() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -637,10 +739,10 @@ fn floating_panes_persist_across_toggles() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
// here we send bytes to the pane when it's not visible to make sure they're still handled and
// we see them once we toggle the panes back
tab.handle_pty_bytes(
@@ -648,7 +750,7 @@ fn floating_panes_persist_across_toggles() {
Vec::from("\n\n\n I am scratch terminal".as_bytes()),
)
.unwrap();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.render(&mut output, None).unwrap();
let snapshot = take_snapshot(
output.serialize().unwrap().get(&client_id).unwrap(),
@@ -669,7 +771,7 @@ fn toggle_floating_panes_off() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -677,7 +779,7 @@ fn toggle_floating_panes_off() {
Vec::from("\n\n\n I am scratch terminal".as_bytes()),
)
.unwrap();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.render(&mut output, None).unwrap();
let snapshot = take_snapshot(
output.serialize().unwrap().get(&client_id).unwrap(),
@@ -698,7 +800,7 @@ fn toggle_floating_panes_on() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -706,8 +808,8 @@ fn toggle_floating_panes_on() {
Vec::from("\n\n\n I am scratch terminal".as_bytes()),
)
.unwrap();
- tab.toggle_floating_panes(client_id, None).unwrap();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.render(&mut output, None).unwrap();
let snapshot = take_snapshot(
output.serialize().unwrap().get(&client_id).unwrap(),
@@ -732,7 +834,7 @@ fn five_new_floating_panes() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -776,7 +878,7 @@ fn increase_floating_pane_size() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id_1 = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -806,7 +908,7 @@ fn decrease_floating_pane_size() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id_1 = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -836,7 +938,7 @@ fn resize_floating_pane_left() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id_1 = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -869,7 +971,7 @@ fn resize_floating_pane_right() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id_1 = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -902,7 +1004,7 @@ fn resize_floating_pane_up() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id_1 = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -935,7 +1037,7 @@ fn resize_floating_pane_down() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id_1 = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -972,7 +1074,7 @@ fn move_floating_pane_focus_left() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1027,7 +1129,7 @@ fn move_floating_pane_focus_right() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1083,7 +1185,7 @@ fn move_floating_pane_focus_up() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1138,7 +1240,7 @@ fn move_floating_pane_focus_down() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1194,7 +1296,7 @@ fn move_floating_pane_focus_with_mouse() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1252,7 +1354,7 @@ fn move_pane_focus_with_mouse_to_non_floating_pane() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1310,7 +1412,7 @@ fn drag_pane_with_mouse() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1368,7 +1470,7 @@ fn mark_text_inside_floating_pane() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1434,7 +1536,7 @@ fn resize_tab_with_floating_panes() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1488,7 +1590,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically() {
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1538,7 +1640,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_b
let new_pane_id_4 = PaneId::Terminal(5);
let new_pane_id_5 = PaneId::Terminal(6);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -1589,7 +1691,7 @@ fn embed_floating_pane() {
let mut tab = create_new_tab(size, ModeInfo::default());
let new_pane_id = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -1647,7 +1749,7 @@ fn embed_floating_pane_without_pane_frames() {
let new_pane_id = PaneId::Terminal(2);
let mut output = Output::default();
tab.set_pane_frames(false);
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
tab.handle_pty_bytes(
@@ -1865,7 +1967,7 @@ fn move_floating_pane_with_sixel_image() {
})));
let mut output = Output::new(sixel_image_store.clone(), character_cell_size);
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
let fixture = read_fixture("sixel-image-500px.six");
@@ -1903,7 +2005,7 @@ fn floating_pane_above_sixel_image() {
})));
let mut output = Output::new(sixel_image_store.clone(), character_cell_size);
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
let fixture = read_fixture("sixel-image-500px.six");
@@ -1960,7 +2062,7 @@ fn suppress_floating_pane() {
let editor_pane_id = PaneId::Terminal(3);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
tab.suppress_active_pane(editor_pane_id, client_id).unwrap();
@@ -1991,7 +2093,7 @@ fn close_suppressing_tiled_pane() {
.unwrap();
tab.handle_pty_bytes(1, Vec::from("\n\n\nI am the original pane".as_bytes()))
.unwrap();
- tab.close_pane(new_pane_id, false);
+ tab.close_pane(new_pane_id, false, None);
tab.render(&mut output, None).unwrap();
let snapshot = take_snapshot(
output.serialize().unwrap().get(&client_id).unwrap(),
@@ -2014,7 +2116,7 @@ fn close_suppressing_floating_pane() {
let editor_pane_id = PaneId::Terminal(3);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
tab.suppress_active_pane(editor_pane_id, client_id).unwrap();
@@ -2022,7 +2124,7 @@ fn close_suppressing_floating_pane() {
.unwrap();
tab.handle_pty_bytes(2, Vec::from("\n\n\nI am the original pane".as_bytes()))
.unwrap();
- tab.close_pane(editor_pane_id, false);
+ tab.close_pane(editor_pane_id, false, None);
tab.render(&mut output, None).unwrap();
let snapshot = take_snapshot(
output.serialize().unwrap().get(&client_id).unwrap(),
@@ -2049,7 +2151,7 @@ fn suppress_tiled_pane_float_it_and_close() {
tab.handle_pty_bytes(1, Vec::from("\n\n\nI am the original pane".as_bytes()))
.unwrap();
tab.toggle_pane_embed_or_floating(client_id).unwrap();
- tab.close_pane(new_pane_id, false);
+ tab.close_pane(new_pane_id, false, None);
tab.render(&mut output, None).unwrap();
let snapshot = take_snapshot(
output.serialize().unwrap().get(&client_id).unwrap(),
@@ -2072,7 +2174,7 @@ fn suppress_floating_pane_embed_it_and_close_it() {
let editor_pane_id = PaneId::Terminal(3);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
tab.suppress_active_pane(editor_pane_id, client_id).unwrap();
@@ -2081,7 +2183,7 @@ fn suppress_floating_pane_embed_it_and_close_it() {
tab.handle_pty_bytes(2, Vec::from("\n\n\nI am the original pane".as_bytes()))
.unwrap();
tab.toggle_pane_embed_or_floating(client_id).unwrap();
- tab.close_pane(editor_pane_id, false);
+ tab.close_pane(editor_pane_id, false, None);
tab.render(&mut output, None).unwrap();
let snapshot = take_snapshot(
output.serialize().unwrap().get(&client_id).unwrap(),
@@ -2132,7 +2234,7 @@ fn resize_whole_tab_while_floting_pane_is_suppressed() {
let editor_pane_id = PaneId::Terminal(3);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
tab.suppress_active_pane(editor_pane_id, client_id).unwrap();
@@ -2233,7 +2335,7 @@ fn enter_search_floating_pane() {
let mut tab = create_new_tab(size, mode_info);
let new_pane_id = PaneId::Terminal(2);
let mut output = Output::default();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id, None, None, Some(client_id))
.unwrap();
@@ -2773,7 +2875,7 @@ fn move_floating_pane_focus_sends_tty_csi_event() {
let new_pane_id_1 = PaneId::Terminal(2);
let new_pane_id_2 = PaneId::Terminal(3);
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -2816,12 +2918,12 @@ fn toggle_floating_panes_on_sends_tty_csi_event() {
let new_pane_id_1 = PaneId::Terminal(2);
let new_pane_id_2 = PaneId::Terminal(3);
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
.unwrap();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.handle_pty_bytes(
1,
// subscribe to focus events
@@ -2840,7 +2942,7 @@ fn toggle_floating_panes_on_sends_tty_csi_event() {
Vec::from("\u{1b}[?1004h".as_bytes()),
)
.unwrap();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
assert_snapshot!(format!("{:?}", *tty_stdin_bytes.lock().unwrap()));
}
@@ -2860,7 +2962,7 @@ fn toggle_floating_panes_off_sends_tty_csi_event() {
let new_pane_id_1 = PaneId::Terminal(2);
let new_pane_id_2 = PaneId::Terminal(3);
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
tab.new_pane(new_pane_id_1, None, None, Some(client_id))
.unwrap();
tab.new_pane(new_pane_id_2, None, None, Some(client_id))
@@ -2883,6 +2985,3867 @@ fn toggle_floating_panes_off_sends_tty_csi_event() {
Vec::from("\u{1b}[?1004h".as_bytes()),
)
.unwrap();
- tab.toggle_floating_panes(client_id, None).unwrap();
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
assert_snapshot!(format!("{:?}", *tty_stdin_bytes.lock().unwrap()));
}
+
+#[test]
+fn can_swap_tiled_layout_at_runtime() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab max_panes=2 split_direction="vertical" {
+ pane
+ pane
+ }
+ }
+ swap_tiled_layout {
+ tab max_panes=2 {
+ pane
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn can_swap_floating_layout_at_runtime() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes max_panes=2 {
+ pane
+ pane
+ }
+ }
+ swap_floating_layout {
+ floating_panes max_panes=2 {
+ pane {
+ x "0%"
+ }
+ pane {
+ x "100%"
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+
+ tab.toggle_floating_panes(Some(client_id), None).unwrap();
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swapping_layouts_after_resize_snaps_to_current_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane
+ pane
+ }
+ }
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane
+ pane
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.resize(client_id, ResizeStrategy::new(Resize::Increase, None))
+ .unwrap();
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swap_tiled_layout_with_stacked_children() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swap_tiled_layout_with_stacked_children_and_no_pane_frames() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ false,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn move_focus_up_with_stacked_panes() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_right(client_id);
+ tab.move_focus_up(client_id);
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn move_focus_down_with_stacked_panes() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_right(client_id);
+ tab.move_focus_up(client_id);
+ tab.move_focus_down(client_id);
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn move_focus_right_into_stacked_panes() {
+ // here we make sure that when we focus right into a stack,
+ // we will always focus on the "main" pane of the stack
+ // and not on one of its folds
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ for i in 0..12 {
+ let new_pane_id = i + 2;
+ tab.new_pane(PaneId::Terminal(new_pane_id), None, None, Some(client_id))
+ .unwrap();
+ }
+ tab.move_focus_left(client_id);
+ tab.horizontal_split(PaneId::Terminal(16), None, client_id)
+ .unwrap();
+
+ tab.move_focus_up(client_id);
+ tab.move_focus_right(client_id);
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((62, 12)),
+ "cursor coordinates moved to the main pane of the stack",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn move_focus_left_into_stacked_panes() {
+ // here we make sure that when we focus left into a stack,
+ // we will always focus on the "main" pane of the stack
+ // and not on one of its folds
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane { children stacked=true; }
+ pane focus=true
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ for i in 0..13 {
+ let new_pane_id = i + 2;
+ tab.new_pane(PaneId::Terminal(new_pane_id), None, None, Some(client_id))
+ .unwrap();
+ }
+ tab.move_focus_right(client_id);
+ tab.horizontal_split(PaneId::Terminal(1), None, client_id)
+ .unwrap();
+
+ tab.move_focus_up(client_id);
+ tab.move_focus_left(client_id);
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((1, 12)),
+ "cursor coordinates moved to the main pane of the stack",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn move_focus_up_into_stacked_panes() {
+ // here we make sure that when we focus up into a stack,
+ // the main pane will become the lowest pane and the sizes
+ // in the stack will be adjusted accordingly
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ for i in 0..4 {
+ let new_pane_id = i + 3;
+ tab.new_pane(PaneId::Terminal(new_pane_id), None, None, Some(client_id))
+ .unwrap();
+ }
+ tab.move_focus_right(client_id);
+ tab.move_focus_up(client_id);
+ tab.move_focus_left(client_id);
+ tab.move_focus_down(client_id);
+ tab.vertical_split(PaneId::Terminal(7), None, client_id)
+ .unwrap();
+
+ tab.move_focus_up(client_id);
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((62, 9)),
+ "cursor coordinates moved to the main pane of the stack",
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn move_focus_down_into_stacked_panes() {
+ // here we make sure that when we focus down into a stack,
+ // the main pane will become the highest pane and the sizes
+ // in the stack will be adjusted accordingly
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ for i in 0..4 {
+ let new_pane_id = i + 3;
+ tab.new_pane(PaneId::Terminal(new_pane_id), None, None, Some(client_id))
+ .unwrap();
+ }
+ tab.move_focus_left(client_id);
+ tab.move_focus_up(client_id);
+ tab.vertical_split(PaneId::Terminal(7), None, client_id)
+ .unwrap();
+
+ tab.move_focus_down(client_id);
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((62, 8)),
+ "cursor coordinates moved to the main pane of the stack",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn close_main_stacked_pane() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.close_pane(new_pane_id_2, false, None);
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn close_main_stacked_pane_in_mid_stack() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_right(client_id);
+ tab.move_focus_up(client_id);
+ tab.move_focus_up(client_id);
+ tab.close_pane(new_pane_id_3, false, None);
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn close_one_liner_stacked_pane_below_main_pane() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_left(client_id);
+ tab.move_focus_right(client_id);
+ tab.move_focus_up(client_id);
+ tab.move_focus_up(client_id);
+ tab.close_pane(new_pane_id_2, false, None);
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn close_one_liner_stacked_pane_above_main_pane() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_right(client_id);
+ tab.move_focus_up(client_id);
+ tab.move_focus_up(client_id);
+ tab.close_pane(new_pane_id_1, false, None);
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn can_increase_size_of_main_pane_in_stack_horizontally() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_right(client_id);
+ tab.resize(
+ client_id,
+ ResizeStrategy::new(Resize::Increase, Some(Direction::Left)),
+ )
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn can_increase_size_of_main_pane_in_stack_vertically() {
+ let size = Size {
+ cols: 121,
+ rows: 40,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_right(client_id);
+ tab.resize(
+ client_id,
+ ResizeStrategy::new(Resize::Increase, Some(Direction::Down)),
+ )
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn can_increase_size_of_main_pane_in_stack_non_directionally() {
+ let size = Size {
+ cols: 121,
+ rows: 40,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_right(client_id);
+ tab.resize(client_id, ResizeStrategy::new(Resize::Increase, None))
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn increasing_size_of_main_pane_in_stack_horizontally_does_not_break_stack() {
+ // here we test a situation where we're increasing the size of the main pane in a stack
+ // while adjacent to this main pane there's another pane perfectly aligned to it
+ // if the pane weren't a member of the stack, we would increase into that adjacent pane
+ // now, we increase all of the stack also into the panes above said pane
+ let size = Size {
+ cols: 121,
+ rows: 40,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane
+ pane split_direction="vertical" {
+ pane {
+ pane focus=true
+ pane
+ }
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+ let new_pane_id_6 = PaneId::Terminal(7);
+ let new_pane_id_7 = PaneId::Terminal(8);
+ let new_pane_id_8 = PaneId::Terminal(9);
+ let new_pane_id_9 = PaneId::Terminal(10);
+ let new_pane_id_10 = PaneId::Terminal(11);
+ let new_pane_id_11 = PaneId::Terminal(12);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_6, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_7, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_8, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_9, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_10, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_11, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_right(client_id);
+ tab.resize(
+ client_id,
+ ResizeStrategy::new(Resize::Increase, Some(Direction::Left)),
+ )
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn can_increase_size_into_pane_stack_horizontally() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.resize(
+ client_id,
+ ResizeStrategy::new(Resize::Increase, Some(Direction::Right)),
+ )
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn can_increase_size_into_pane_stack_vertically() {
+ let size = Size {
+ cols: 121,
+ rows: 40,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_right(client_id);
+ tab.move_focus_down(client_id);
+ tab.resize(
+ client_id,
+ ResizeStrategy::new(Resize::Increase, Some(Direction::Up)),
+ )
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn can_increase_size_into_pane_stack_non_directionally() {
+ let size = Size {
+ cols: 121,
+ rows: 40,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_left(client_id);
+ tab.resize(client_id, ResizeStrategy::new(Resize::Increase, None))
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn increasing_size_into_main_pane_in_stack_horizontally_does_not_break_stack() {
+ // here we test a situation where we're increasing the size of the main pane in a stack
+ // while adjacent to this main pane there's another pane perfectly aligned to it
+ // if the pane weren't a member of the stack, we would increase into that adjacent pane
+ // now, we increase all of the stack also into the panes above said pane
+ let size = Size {
+ cols: 121,
+ rows: 40,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane
+ pane split_direction="vertical" {
+ pane {
+ pane focus=true
+ pane
+ }
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+ let new_pane_id_6 = PaneId::Terminal(7);
+ let new_pane_id_7 = PaneId::Terminal(8);
+ let new_pane_id_8 = PaneId::Terminal(9);
+ let new_pane_id_9 = PaneId::Terminal(10);
+ let new_pane_id_10 = PaneId::Terminal(11);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_6, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_7, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_8, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_9, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_10, None, None, Some(client_id))
+ .unwrap();
+ tab.resize(
+ client_id,
+ ResizeStrategy::new(Resize::Increase, Some(Direction::Right)),
+ )
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn decreasing_size_of_whole_tab_treats_stacked_panes_properly() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.resize_whole_tab(Size {
+ cols: 100,
+ rows: 10,
+ });
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn increasing_size_of_whole_tab_treats_stacked_panes_properly() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.resize_whole_tab(Size {
+ cols: 100,
+ rows: 10,
+ });
+ tab.resize_whole_tab(Size {
+ cols: 121,
+ rows: 20,
+ });
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn cannot_decrease_stack_size_beyond_minimum_height() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_down(client_id);
+ for _ in 0..6 {
+ tab.resize(
+ client_id,
+ ResizeStrategy::new(Resize::Increase, Some(Direction::Up)),
+ )
+ .unwrap();
+ }
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn focus_stacked_pane_over_flexible_pane_with_the_mouse() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.handle_left_click(&Position::new(1, 71), client_id)
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn focus_stacked_pane_under_flexible_pane_with_the_mouse() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.handle_left_click(&Position::new(1, 71), client_id)
+ .unwrap();
+ tab.handle_left_click(&Position::new(9, 71), client_id)
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn close_stacked_pane_with_previously_focused_other_pane() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.handle_left_click(&Position::new(2, 71), client_id)
+ .unwrap();
+ tab.handle_left_click(&Position::new(1, 71), client_id)
+ .unwrap();
+ tab.close_pane(PaneId::Terminal(4), false, None);
+ tab.render(&mut output, None).unwrap();
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((62, 2)),
+ "cursor coordinates moved to the main pane of the stack",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn close_pane_near_stacked_panes() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane
+ pane { children stacked=true; }
+ }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.close_pane(PaneId::Terminal(6), false, None);
+ tab.render(&mut output, None).unwrap();
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((62, 4)),
+ "cursor coordinates moved to the main pane of the stack",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn focus_next_pane_expands_stacked_panes() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_left(client_id);
+ tab.focus_next_pane(client_id);
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn stacked_panes_can_become_fullscreen() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ pane
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ None,
+ true,
+ );
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+
+ tab.new_pane(new_pane_id_1, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_2, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_3, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_4, None, None, Some(client_id))
+ .unwrap();
+ tab.new_pane(new_pane_id_5, None, None, Some(client_id))
+ .unwrap();
+ tab.move_focus_up(client_id);
+ tab.toggle_active_pane_fullscreen(client_id);
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn layout_with_plugins_and_commands_swaped_properly() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ pane split_direction="vertical" {
+ pane command="command1"
+ pane
+ pane command="command2"
+ }
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ }
+ "#;
+ // this swap layout changes both the split direction of the two command panes and the location
+ // of the plugins - we want to make sure that they are all placed properly and not switched
+ // around
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ pane command="command2"
+ pane command="command1"
+ pane
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let mut command_1 = RunCommand::default();
+ command_1.command = PathBuf::from("command1");
+ let mut command_2 = RunCommand::default();
+ command_2.command = PathBuf::from("command2");
+ let new_terminal_ids = vec![(1, Some(command_1)), (2, None), (3, Some(command_2))];
+ let new_floating_terminal_ids = vec![];
+ let mut new_plugin_ids = HashMap::new();
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ vec![1],
+ );
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("status-bar")),
+ vec![2],
+ );
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let _ = tab.handle_plugin_bytes(1, 1, "I am a tab bar".as_bytes().to_vec());
+ let _ = tab.handle_plugin_bytes(2, 1, "I am a\n\rstatus bar".as_bytes().to_vec());
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn base_layout_is_included_in_swap_layouts() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ pane split_direction="vertical" {
+ pane command="command1"
+ pane
+ pane command="command2"
+ }
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ }
+ "#;
+ // this swap layout changes both the split direction of the two command panes and the location
+ // of the plugins - we want to make sure that they are all placed properly and not switched
+ // around
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ pane command="command2"
+ pane command="command1"
+ pane
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let mut command_1 = RunCommand::default();
+ command_1.command = PathBuf::from("command1");
+ let mut command_2 = RunCommand::default();
+ command_2.command = PathBuf::from("command2");
+ let new_terminal_ids = vec![(1, Some(command_1)), (2, None), (3, Some(command_2))];
+ let new_floating_terminal_ids = vec![];
+ let mut new_plugin_ids = HashMap::new();
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ vec![1],
+ );
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("status-bar")),
+ vec![2],
+ );
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let _ = tab.handle_plugin_bytes(1, 1, "I am a tab bar".as_bytes().to_vec());
+ let _ = tab.handle_plugin_bytes(2, 1, "I am a\n\rstatus bar".as_bytes().to_vec());
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.previous_swap_layout(Some(client_id)).unwrap(); // move back to the base layout
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swap_layouts_including_command_panes_absent_from_existing_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ pane split_direction="vertical" {
+ pane
+ pane
+ pane
+ }
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ }
+ "#;
+ // this swap layout changes both the split direction of the two command panes and the location
+ // of the plugins - we want to make sure that they are all placed properly and not switched
+ // around
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ pane command="command2"
+ pane command="command1"
+ pane
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_floating_terminal_ids = vec![];
+ let mut new_plugin_ids = HashMap::new();
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ vec![1],
+ );
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("status-bar")),
+ vec![2],
+ );
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let _ = tab.handle_plugin_bytes(1, 1, "I am a tab bar".as_bytes().to_vec());
+ let _ = tab.handle_plugin_bytes(2, 1, "I am a\n\rstatus bar".as_bytes().to_vec());
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swap_layouts_not_including_command_panes_present_in_existing_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ pane split_direction="vertical" {
+ pane command="command1"
+ pane
+ pane command="command2"
+ }
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ }
+ "#;
+ // this swap layout changes both the split direction of the two command panes and the location
+ // of the plugins - we want to make sure that they are all placed properly and not switched
+ // around
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ pane
+ pane
+ pane
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let mut command_1 = RunCommand::default();
+ command_1.command = PathBuf::from("command1");
+ let mut command_2 = RunCommand::default();
+ command_2.command = PathBuf::from("command2");
+ let new_terminal_ids = vec![(1, Some(command_1)), (2, None), (3, Some(command_2))];
+ let new_floating_terminal_ids = vec![];
+ let mut new_plugin_ids = HashMap::new();
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ vec![1],
+ );
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("status-bar")),
+ vec![2],
+ );
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let _ = tab.handle_plugin_bytes(1, 1, "I am a tab bar".as_bytes().to_vec());
+ let _ = tab.handle_plugin_bytes(2, 1, "I am a\n\rstatus bar".as_bytes().to_vec());
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swap_layouts_including_plugin_panes_absent_from_existing_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ pane size=2 borderless=true
+ pane split_direction="vertical" {
+ pane
+ pane
+ pane
+ }
+ pane size=1 borderless=true
+ }
+ "#;
+ // this swap layout changes both the split direction of the two command panes and the location
+ // of the plugins - we want to make sure that they are all placed properly and not switched
+ // around
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ pane
+ pane
+ pane
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_floating_terminal_ids = vec![];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swap_layouts_not_including_plugin_panes_present_in_existing_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ pane split_direction="vertical" {
+ pane command="command1"
+ pane
+ pane command="command2"
+ }
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ }
+ "#;
+ // this swap layout changes both the split direction of the two command panes and the location
+ // of the plugins - we want to make sure that they are all placed properly and not switched
+ // around
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane size=2
+ pane
+ pane
+ pane
+ pane size=1
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let mut command_1 = RunCommand::default();
+ command_1.command = PathBuf::from("command1");
+ let mut command_2 = RunCommand::default();
+ command_2.command = PathBuf::from("command2");
+ let new_terminal_ids = vec![(1, Some(command_1)), (2, None), (3, Some(command_2))];
+ let new_floating_terminal_ids = vec![];
+ let mut new_plugin_ids = HashMap::new();
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ vec![1],
+ );
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("status-bar")),
+ vec![2],
+ );
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let _ = tab.handle_plugin_bytes(1, 1, "I am a tab bar".as_bytes().to_vec());
+ let _ = tab.handle_plugin_bytes(2, 1, "I am a\n\rstatus bar".as_bytes().to_vec());
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn new_pane_in_auto_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab max_panes=5 {
+ pane split_direction="vertical" {
+ pane
+ pane { children; }
+ }
+ }
+ tab max_panes=8 {
+ pane split_direction="vertical" {
+ pane { children; }
+ pane { pane; pane; pane; pane; }
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_floating_terminal_ids = vec![];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+
+ let mut expected_cursor_coordinates = vec![
+ (62, 1),
+ (62, 11),
+ (62, 15),
+ (62, 16),
+ (1, 11),
+ (1, 15),
+ (1, 16),
+ ];
+ for i in 0..7 {
+ let new_pane_id = i + 2;
+ tab.new_pane(PaneId::Terminal(new_pane_id), None, None, Some(client_id))
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ let (expected_x, expected_y) = expected_cursor_coordinates.remove(0);
+ assert_eq!(
+ cursor_coordinates,
+ Some((expected_x, expected_y)),
+ "cursor coordinates moved to the new pane",
+ );
+ assert_snapshot!(snapshot);
+ }
+}
+
+#[test]
+fn when_swapping_tiled_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ pane
+ pane
+ pane
+ }
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane
+ pane
+ pane
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_floating_terminal_ids = vec![];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ tab.move_focus_down(client_id);
+ tab.resize(
+ client_id,
+ ResizeStrategy::new(Resize::Increase, Some(Direction::Down)),
+ )
+ .unwrap();
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((1, 8)),
+ "cursor coordinates moved to the new pane",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn when_swapping_tiled_layouts_in_an_undamaged_state_pane_focuses_on_focused_node() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ pane
+ pane
+ pane
+ }
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane
+ pane
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_floating_terminal_ids = vec![];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ tab.move_focus_down(client_id);
+ tab.next_swap_layout(Some(client_id), true).unwrap();
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((1, 1)),
+ "cursor coordinates moved to the new pane",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn when_swapping_tiled_layouts_in_an_undamaged_state_with_no_focus_node_pane_focuses_on_deepest_node(
+) {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ pane
+ pane
+ pane
+ }
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane
+ pane
+ pane
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_floating_terminal_ids = vec![];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ tab.move_focus_down(client_id);
+ tab.next_swap_layout(Some(client_id), true).unwrap();
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((82, 1)),
+ "cursor coordinates moved to the new pane",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn when_closing_a_pane_in_auto_layout_the_focus_goes_to_last_focused_pane() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ pane
+ pane
+ pane
+ }
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_tiled_layout {
+ tab {
+ pane split_direction="vertical" {
+ pane
+ pane
+ pane
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_floating_terminal_ids = vec![];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ tab.move_focus_down(client_id);
+ tab.move_focus_down(client_id);
+ tab.close_pane(PaneId::Terminal(3), false, Some(client_id));
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((1, 11)),
+ "cursor coordinates moved to the new pane",
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn floating_layout_with_plugins_and_commands_swaped_properly() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane x=0 y=0 {
+ plugin location="zellij:tab-bar"
+ }
+ pane x=0 y=10 command="command1"
+ pane
+ pane x=50 y=10 command="command2"
+ pane x=50 y=0 {
+ plugin location="zellij:status-bar"
+ }
+ }
+ }
+ "#;
+ // this swap layout swaps between the location of the plugins and the commands
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes {
+ pane x=0 y=0 {
+ plugin location="zellij:status-bar"
+ }
+ pane x=0 y=10 command="command2"
+ pane
+ pane x=50 y=10 command="command1"
+ pane x=50 y=0 {
+ plugin location="zellij:tab-bar"
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let mut command_1 = RunCommand::default();
+ command_1.command = PathBuf::from("command1");
+ let mut command_2 = RunCommand::default();
+ command_2.command = PathBuf::from("command2");
+ let new_floating_terminal_ids = vec![(1, Some(command_1)), (2, None), (3, Some(command_2))];
+ let new_terminal_ids = vec![(4, None)];
+ let mut new_plugin_ids = HashMap::new();
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ vec![1],
+ );
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("status-bar")),
+ vec![2],
+ );
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let _ = tab.handle_plugin_bytes(1, 1, "I am a tab bar".as_bytes().to_vec());
+ let _ = tab.handle_plugin_bytes(2, 1, "I am a\n\rstatus bar".as_bytes().to_vec());
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn base_floating_layout_is_included_in_swap_layouts() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane x=0 y=0 {
+ plugin location="zellij:tab-bar"
+ }
+ pane x=0 y=10 command="command1"
+ pane
+ pane x=50 y=10 command="command2"
+ pane x=50 y=0 {
+ plugin location="zellij:status-bar"
+ }
+ }
+ }
+ "#;
+ // this swap layout swaps between the location of the plugins and the commands
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes {
+ pane x=0 y=0 {
+ plugin location="zellij:status-bar"
+ }
+ pane x=0 y=10 command="command2"
+ pane
+ pane x=50 y=10 command="command1"
+ pane x=50 y=0 {
+ plugin location="zellij:tab-bar"
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let mut command_1 = RunCommand::default();
+ command_1.command = PathBuf::from("command1");
+ let mut command_2 = RunCommand::default();
+ command_2.command = PathBuf::from("command2");
+ let new_floating_terminal_ids = vec![(1, Some(command_1)), (2, None), (3, Some(command_2))];
+ let new_terminal_ids = vec![(4, None)];
+ let mut new_plugin_ids = HashMap::new();
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ vec![1],
+ );
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("status-bar")),
+ vec![2],
+ );
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let _ = tab.handle_plugin_bytes(1, 1, "I am a tab bar".as_bytes().to_vec());
+ let _ = tab.handle_plugin_bytes(2, 1, "I am a\n\rstatus bar".as_bytes().to_vec());
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.previous_swap_layout(Some(client_id)).unwrap(); // move back to the base layout
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swap_floating_layouts_including_command_panes_absent_from_existing_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane {
+ plugin location="zellij:tab-bar"
+ }
+ pane
+ pane
+ pane
+ pane {
+ plugin location="zellij:status-bar"
+ }
+ }
+ }
+ "#;
+ // this swap layout changes both the split direction of the two command panes and the location
+ // of the plugins - we want to make sure that they are all placed properly and not switched
+ // around
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes {
+ pane {
+ plugin location="zellij:status-bar"
+ }
+ pane x=0 y=0 command="command1"
+ pane x=10 y=10 command="command2"
+ pane
+ pane {
+ plugin location="zellij:tab-bar"
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_floating_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_terminal_ids = vec![(4, None)];
+ let mut new_plugin_ids = HashMap::new();
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ vec![1],
+ );
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("status-bar")),
+ vec![2],
+ );
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let _ = tab.handle_plugin_bytes(1, 1, "I am a tab bar".as_bytes().to_vec());
+ let _ = tab.handle_plugin_bytes(2, 1, "I am a\n\rstatus bar".as_bytes().to_vec());
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swap_floating_layouts_not_including_command_panes_present_in_existing_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane {
+ plugin location="zellij:tab-bar"
+ }
+ pane command="command1"
+ pane
+ pane command="command2"
+ pane {
+ plugin location="zellij:status-bar"
+ }
+ }
+ }
+ "#;
+ // this swap layout changes both the split direction of the two command panes and the location
+ // of the plugins - we want to make sure that they are all placed properly and not switched
+ // around
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes {
+ pane {
+ plugin location="zellij:status-bar"
+ }
+ pane
+ pane
+ pane
+ pane {
+ plugin location="zellij:tab-bar"
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let mut command_1 = RunCommand::default();
+ command_1.command = PathBuf::from("command1");
+ let mut command_2 = RunCommand::default();
+ command_2.command = PathBuf::from("command2");
+ let new_floating_terminal_ids = vec![(1, Some(command_1)), (2, None), (3, Some(command_2))];
+ let new_terminal_ids = vec![(4, None)];
+ let mut new_plugin_ids = HashMap::new();
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ vec![1],
+ );
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("status-bar")),
+ vec![2],
+ );
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let _ = tab.handle_plugin_bytes(1, 1, "I am a tab bar".as_bytes().to_vec());
+ let _ = tab.handle_plugin_bytes(2, 1, "I am a\n\rstatus bar".as_bytes().to_vec());
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swap_floating_layouts_including_plugin_panes_absent_from_existing_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane
+ pane
+ pane
+ }
+ }
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes {
+ pane {
+ plugin location="zellij:status-bar"
+ }
+ pane
+ pane {
+ plugin location="zellij:tab-bar"
+ }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_floating_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_terminal_ids = vec![(4, None)];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn swap_floating_layouts_not_including_plugin_panes_present_in_existing_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane {
+ plugin location="zellij:tab-bar"
+ }
+ pane
+ pane {
+ plugin location="zellij:status-bar"
+ }
+ }
+ }
+ "#;
+ // this swap layout changes both the split direction of the two command panes and the location
+ // of the plugins - we want to make sure that they are all placed properly and not switched
+ // around
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes {
+ pane
+ pane
+ pane
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let mut command_1 = RunCommand::default();
+ command_1.command = PathBuf::from("command1");
+ let mut command_2 = RunCommand::default();
+ command_2.command = PathBuf::from("command2");
+ let new_floating_terminal_ids = vec![(1, Some(command_1)), (2, None), (3, Some(command_2))];
+ let new_terminal_ids = vec![(4, None)];
+ let mut new_plugin_ids = HashMap::new();
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ vec![1],
+ );
+ new_plugin_ids.insert(
+ RunPluginLocation::Zellij(PluginTag::new("status-bar")),
+ vec![2],
+ );
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let _ = tab.handle_plugin_bytes(1, 1, "I am a tab bar".as_bytes().to_vec());
+ let _ = tab.handle_plugin_bytes(2, 1, "I am a\n\rstatus bar".as_bytes().to_vec());
+ tab.next_swap_layout(Some(client_id), false).unwrap();
+ tab.render(&mut output, None).unwrap();
+ let snapshot = take_snapshot(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn new_floating_pane_in_auto_layout() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout name="spread" {
+ floating_panes max_panes=1 {
+ pane {y "50%"; x "50%"; }
+ }
+ floating_panes max_panes=2 {
+ pane { x "1%"; y "25%"; width "45%"; }
+ pane { x "50%"; y "25%"; width "45%"; }
+ }
+ floating_panes max_panes=3 {
+ pane focus=true { y "55%"; width "45%"; height "45%"; }
+ pane { x "1%"; y "1%"; width "45%"; }
+ pane { x "50%"; y "1%"; width "45%"; }
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_terminal_ids = vec![(1, None)];
+ let new_floating_terminal_ids = vec![];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+
+ let mut expected_cursor_coordinates = vec![(62, 11), (62, 6), (31, 12)];
+ for i in 0..3 {
+ let new_pane_id = i + 2;
+ let should_float = true;
+ tab.new_pane(
+ PaneId::Terminal(new_pane_id),
+ None,
+ Some(should_float),
+ Some(client_id),
+ )
+ .unwrap();
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ let (expected_x, expected_y) = expected_cursor_coordinates.remove(0);
+ assert_eq!(
+ cursor_coordinates,
+ Some((expected_x, expected_y)),
+ "cursor coordinates moved to the new pane",
+ );
+ assert_snapshot!(snapshot);
+ }
+}
+
+#[test]
+fn when_swapping_floating_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane x=0 y=0
+ pane
+ pane
+ }
+ }
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes {
+ pane
+ pane
+ pane
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_floating_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_terminal_ids = vec![(4, None)];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ tab.resize(
+ client_id,
+ ResizeStrategy::new(Resize::Increase, Some(Direction::Down)),
+ )
+ .unwrap();
+ tab.next_swap_layout(Some(client_id), true).unwrap();
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((33, 8)),
+ "cursor coordinates moved to the new pane",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn when_swapping_floating_layouts_in_an_undamaged_state_pane_focuses_on_focused_node() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane x=0 y=0
+ pane
+ pane
+ }
+ }
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes {
+ pane focus=true
+ pane
+ pane
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_floating_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_terminal_ids = vec![(4, None)];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ tab.next_swap_layout(Some(client_id), true).unwrap();
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((31, 6)),
+ "cursor coordinates moved to the new pane",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn when_swapping_floating_layouts_in_an_undamaged_state_with_no_focus_node_pane_focuses_on_deepest_node(
+) {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane focus=true
+ pane
+ pane
+ }
+ }
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes {
+ pane
+ pane
+ pane
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_floating_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_terminal_ids = vec![(4, None)];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ tab.next_swap_layout(Some(client_id), true).unwrap();
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((35, 10)),
+ "cursor coordinates moved to the new pane",
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn when_closing_a_floating_pane_in_auto_layout_the_focus_goes_to_last_focused_pane() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane
+ pane
+ pane
+ }
+ }
+ "#;
+ let swap_layouts = r#"
+ layout {
+ swap_floating_layout {
+ floating_panes {
+ pane
+ pane
+ pane
+ }
+ }
+ }
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_floating_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_terminal_ids = vec![(4, None)];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ tab.move_focus_up(client_id);
+ tab.move_focus_up(client_id);
+ tab.close_pane(PaneId::Terminal(1), false, Some(client_id));
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((31, 6)),
+ "cursor coordinates moved to the new pane",
+ );
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn when_resizing_whole_tab_with_auto_layout_and_floating_panes_the_layout_is_maintained() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let mut output = Output::default();
+ let base_layout = r#"
+ layout {
+ floating_panes {
+ pane
+ pane
+ pane
+ }
+ }
+ "#;
+ let swap_layouts = r#"
+ layout
+ "#;
+ let (base_layout, base_floating_layout) =
+ Layout::from_kdl(base_layout, "file_name.kdl".into(), None, None)
+ .unwrap()
+ .template
+ .unwrap();
+
+ let new_floating_terminal_ids = vec![(1, None), (2, None), (3, None)];
+ let new_terminal_ids = vec![(4, None)];
+ let new_plugin_ids = HashMap::new();
+
+ let swap_layout = Layout::from_kdl(swap_layouts, "file_name.kdl".into(), None, None).unwrap();
+ let swap_tiled_layouts = swap_layout.swap_tiled_layouts.clone();
+ let swap_floating_layouts = swap_layout.swap_floating_layouts.clone();
+ let mut tab = create_new_tab_with_swap_layouts(
+ size,
+ ModeInfo::default(),
+ (swap_tiled_layouts, swap_floating_layouts),
+ Some((
+ base_layout,
+ base_floating_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ )),
+ true,
+ );
+ let new_size = Size {
+ cols: 150,
+ rows: 30,
+ };
+ tab.resize_whole_tab(new_size);
+ tab.render(&mut output, None).unwrap();
+
+ let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position(
+ output.serialize().unwrap().get(&client_id).unwrap(),
+ new_size.rows,
+ new_size.cols,
+ Palette::default(),
+ );
+ assert_eq!(
+ cursor_coordinates,
+ Some((43, 13)),
+ "cursor coordinates moved to the new pane",
+ );
+ assert_snapshot!(snapshot);
+}
diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs
index 1a87e2e1..8fbf6649 100644
--- a/zellij-server/src/tab/unit/tab_tests.rs
+++ b/zellij-server/src/tab/unit/tab_tests.rs
@@ -10,7 +10,7 @@ use crate::{
use std::path::PathBuf;
use zellij_utils::data::{Direction, Resize, ResizeStrategy};
use zellij_utils::errors::prelude::*;
-use zellij_utils::input::layout::{PaneLayout, SplitDirection, SplitSize};
+use zellij_utils::input::layout::{SplitDirection, SplitSize, TiledPaneLayout};
use zellij_utils::ipc::IpcReceiverWithContext;
use zellij_utils::pane_size::{Size, SizeInPixels};
@@ -146,6 +146,7 @@ fn create_new_tab(size: Size) -> Tab {
let mode_info = ModeInfo::default();
let style = Style::default();
let draw_pane_frames = true;
+ let auto_layout = true;
let client_id = 1;
let session_is_mirrored = true;
let mut connected_clients = HashSet::new();
@@ -169,15 +170,17 @@ fn create_new_tab(size: Size) -> Tab {
style,
mode_info,
draw_pane_frames,
+ auto_layout,
connected_clients,
session_is_mirrored,
client_id,
copy_options,
terminal_emulator_colors,
terminal_emulator_color_codes,
+ (vec![], vec![]), // swap layouts
);
tab.apply_layout(
- PaneLayout::default(),
+ TiledPaneLayout::default(),
vec![],
vec![(1, None)],
vec![],
@@ -188,7 +191,7 @@ fn create_new_tab(size: Size) -> Tab {
tab
}
-fn create_new_tab_with_layout(size: Size, layout: PaneLayout) -> Tab {
+fn create_new_tab_with_layout(size: Size, layout: TiledPaneLayout) -> Tab {
let index = 0;
let position = 0;
let name = String::new();
@@ -198,6 +201,7 @@ fn create_new_tab_with_layout(size: Size, layout: PaneLayout) -> Tab {
let mode_info = ModeInfo::default();
let style = Style::default();
let draw_pane_frames = true;
+ let auto_layout = true;
let client_id = 1;
let session_is_mirrored = true;
let mut connected_clients = HashSet::new();
@@ -221,12 +225,14 @@ fn create_new_tab_with_layout(size: Size, layout: PaneLayout) -> Tab {
style,
mode_info,
draw_pane_frames,
+ auto_layout,
connected_clients,
session_is_mirrored,
client_id,
copy_options,
terminal_emulator_colors,
terminal_emulator_color_codes,
+ (vec![], vec![]), // swap layouts
);
let mut new_terminal_ids = vec![];
for i in 0..layout.extract_run_instructions().len() {
@@ -257,6 +263,7 @@ fn create_new_tab_with_cell_size(
let mode_info = ModeInfo::default();
let style = Style::default();
let draw_pane_frames = true;
+ let auto_layout = true;
let client_id = 1;
let session_is_mirrored = true;
let mut connected_clients = HashSet::new();
@@ -279,15 +286,17 @@ fn create_new_tab_with_cell_size(
style,
mode_info,
draw_pane_frames,
+ auto_layout,
connected_clients,
session_is_mirrored,
client_id,
copy_options,
terminal_emulator_colors,
terminal_emulator_color_codes,
+ (vec![], vec![]), // swap layouts
);
tab.apply_layout(
- PaneLayout::default(),
+ TiledPaneLayout::default(),
vec![],
vec![(1, None)],
vec![],
@@ -738,11 +747,11 @@ pub fn cannot_split_largest_pane_when_there_is_no_room() {
#[test]
pub fn cannot_split_panes_vertically_when_active_pane_has_fixed_columns() {
let size = Size { cols: 50, rows: 20 };
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- let mut fixed_child = PaneLayout::default();
+ let mut fixed_child = TiledPaneLayout::default();
fixed_child.split_size = Some(SplitSize::Fixed(30));
- initial_layout.children = vec![fixed_child, PaneLayout::default()];
+ initial_layout.children = vec![fixed_child, TiledPaneLayout::default()];
let mut tab = create_new_tab_with_layout(size, initial_layout);
tab.vertical_split(PaneId::Terminal(3), None, 1).unwrap();
assert_eq!(tab.tiled_panes.panes.len(), 2, "Tab still has two panes");
@@ -751,11 +760,11 @@ pub fn cannot_split_panes_vertically_when_active_pane_has_fixed_columns() {
#[test]
pub fn cannot_split_panes_horizontally_when_active_pane_has_fixed_rows() {
let size = Size { cols: 50, rows: 20 };
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Horizontal;
- let mut fixed_child = PaneLayout::default();
+ let mut fixed_child = TiledPaneLayout::default();
fixed_child.split_size = Some(SplitSize::Fixed(12));
- initial_layout.children = vec![fixed_child, PaneLayout::default()];
+ initial_layout.children = vec![fixed_child, TiledPaneLayout::default()];
let mut tab = create_new_tab_with_layout(size, initial_layout);
tab.horizontal_split(PaneId::Terminal(3), None, 1).unwrap();
assert_eq!(tab.tiled_panes.panes.len(), 2, "Tab still has two panes");
@@ -5948,11 +5957,11 @@ pub fn cannot_resize_down_when_pane_has_fixed_rows() {
rows: 20,
};
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Horizontal;
- let mut fixed_child = PaneLayout::default();
+ let mut fixed_child = TiledPaneLayout::default();
fixed_child.split_size = Some(SplitSize::Fixed(10));
- initial_layout.children = vec![fixed_child, PaneLayout::default()];
+ initial_layout.children = vec![fixed_child, TiledPaneLayout::default()];
let mut tab = create_new_tab_with_layout(size, initial_layout);
tab_resize_down(&mut tab, 1);
@@ -5994,11 +6003,11 @@ pub fn cannot_resize_down_when_pane_below_has_fixed_rows() {
rows: 20,
};
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Horizontal;
- let mut fixed_child = PaneLayout::default();
+ let mut fixed_child = TiledPaneLayout::default();
fixed_child.split_size = Some(SplitSize::Fixed(10));
- initial_layout.children = vec![PaneLayout::default(), fixed_child];
+ initial_layout.children = vec![TiledPaneLayout::default(), fixed_child];
let mut tab = create_new_tab_with_layout(size, initial_layout);
tab_resize_down(&mut tab, 1);
@@ -6040,11 +6049,11 @@ pub fn cannot_resize_up_when_pane_below_has_fixed_rows() {
rows: 20,
};
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Horizontal;
- let mut fixed_child = PaneLayout::default();
+ let mut fixed_child = TiledPaneLayout::default();
fixed_child.split_size = Some(SplitSize::Fixed(10));
- initial_layout.children = vec![PaneLayout::default(), fixed_child];
+ initial_layout.children = vec![TiledPaneLayout::default(), fixed_child];
let mut tab = create_new_tab_with_layout(size, initial_layout);
tab_resize_up(&mut tab, 1);
@@ -11371,11 +11380,11 @@ pub fn cannot_resize_right_when_pane_has_fixed_columns() {
rows: 20,
};
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- let mut fixed_child = PaneLayout::default();
+ let mut fixed_child = TiledPaneLayout::default();
fixed_child.split_size = Some(SplitSize::Fixed(60));
- initial_layout.children = vec![fixed_child, PaneLayout::default()];
+ initial_layout.children = vec![fixed_child, TiledPaneLayout::default()];
let mut tab = create_new_tab_with_layout(size, initial_layout);
tab_resize_down(&mut tab, 1);
@@ -14377,7 +14386,7 @@ fn correctly_resize_frameless_panes_on_pane_close() {
tab.new_pane(PaneId::Terminal(2), None, None, Some(1))
.unwrap();
- tab.close_pane(PaneId::Terminal(2), true);
+ tab.close_pane(PaneId::Terminal(2), true, None);
// the size should be the same after adding and then removing a pane
let pane = tab.tiled_panes.panes.get(&PaneId::Terminal(1)).unwrap();
diff --git a/zellij-server/src/thread_bus.rs b/zellij-server/src/thread_bus.rs
index 7f831d6b..3247ecf4 100644
--- a/zellij-server/src/thread_bus.rs
+++ b/zellij-server/src/thread_bus.rs
@@ -143,6 +143,12 @@ impl ThreadSenders {
// this is mostly used for the tests, see struct
self.to_pty_writer.replace(new_pty_writer);
}
+
+ #[allow(unused)]
+ pub fn replace_to_plugin(&mut self, new_to_plugin: SenderWithContext<PluginInstruction>) {
+ // this is mostly used for the tests, see struct
+ self.to_plugin.replace(new_to_plugin);
+ }
}
/// A container for a receiver, OS input and the senders to a given thread
diff --git a/zellij-server/src/ui/boundaries.rs b/zellij-server/src/ui/boundaries.rs
index 2ba3e67e..29b614c1 100644
--- a/zellij-server/src/ui/boundaries.rs
+++ b/zellij-server/src/ui/boundaries.rs
@@ -436,6 +436,7 @@ pub struct Boundaries {
pub boundary_characters: HashMap<Coordinates, BoundarySymbol>,
}
+#[allow(clippy::if_same_then_else)]
impl Boundaries {
pub fn new(viewport: Viewport) -> Self {
Boundaries {
@@ -444,6 +445,7 @@ impl Boundaries {
}
}
pub fn add_rect(&mut self, rect: &dyn Pane, color: Option<PaletteColor>) {
+ let pane_is_stacked = rect.current_geom().is_stacked;
if !self.is_fully_inside_screen(rect) {
return;
}
@@ -456,8 +458,11 @@ impl Boundaries {
let coordinates = Coordinates::new(boundary_x_coords, row);
let symbol_to_add = if row == first_row_coordinates && row != self.viewport.y {
BoundarySymbol::new(boundary_type::TOP_LEFT).color(color)
+ } else if row == first_row_coordinates && pane_is_stacked {
+ BoundarySymbol::new(boundary_type::TOP_LEFT).color(color)
} else if row == last_row_coordinates - 1
&& row != self.viewport.y + self.viewport.rows - 1
+ && !pane_is_stacked
{
BoundarySymbol::new(boundary_type::BOTTOM_LEFT).color(color)
} else {
@@ -471,7 +476,7 @@ impl Boundaries {
self.boundary_characters.insert(coordinates, next_symbol);
}
}
- if rect.y() > self.viewport.y {
+ if rect.y() > self.viewport.y && !pane_is_stacked {
// top boundary
let boundary_y_coords = rect.y() - 1;
let first_col_coordinates = self.rect_bottom_boundary_col_start(rect);
@@ -504,6 +509,7 @@ impl Boundaries {
BoundarySymbol::new(boundary_type::TOP_RIGHT).color(color)
} else if row == last_row_coordinates - 1
&& row != self.viewport.y + self.viewport.rows - 1
+ && !pane_is_stacked
{
BoundarySymbol::new(boundary_type::BOTTOM_RIGHT).color(color)
} else {
@@ -517,7 +523,7 @@ impl Boundaries {
self.boundary_characters.insert(coordinates, next_symbol);
}
}
- if self.rect_bottom_boundary_is_before_screen_edge(rect) {
+ if self.rect_bottom_boundary_is_before_screen_edge(rect) && !pane_is_stacked {
// bottom boundary
let boundary_y_coords = rect.bottom_boundary_y_coords() - 1;
let first_col_coordinates = self.rect_bottom_boundary_col_start(rect);
@@ -570,8 +576,10 @@ impl Boundaries {
rect.y() + rect.rows() < self.viewport.y + self.viewport.rows
}
fn rect_right_boundary_row_start(&self, rect: &dyn Pane) -> usize {
+ let pane_is_stacked = rect.current_geom().is_stacked;
+ let horizontal_frame_offset = if pane_is_stacked { 0 } else { 1 };
if rect.y() > self.viewport.y {
- rect.y() - 1
+ rect.y() - horizontal_frame_offset
} else {
self.viewport.y
}
diff --git a/zellij-server/src/ui/pane_boundaries_frame.rs b/zellij-server/src/ui/pane_boundaries_frame.rs
index 537a80c4..61ec7a4b 100644
--- a/zellij-server/src/ui/pane_boundaries_frame.rs
+++ b/zellij-server/src/ui/pane_boundaries_frame.rs
@@ -75,6 +75,9 @@ pub struct FrameParams {
pub style: Style,
pub color: Option<PaletteColor>,
pub other_cursors_exist_in_session: bool,
+ pub pane_is_stacked_under: bool,
+ pub pane_is_stacked_over: bool,
+ pub should_draw_pane_frames: bool,
}
#[derive(Default, PartialEq)]
@@ -90,6 +93,9 @@ pub struct PaneFrame {
pub other_focused_clients: Vec<ClientId>,
exit_status: Option<ExitStatus>,
is_first_run: bool,
+ pane_is_stacked_over: bool,
+ pane_is_stacked_under: bool,
+ should_draw_pane_frames: bool,
}
impl PaneFrame {
@@ -111,6 +117,9 @@ impl PaneFrame {
other_cursors_exist_in_session: frame_params.other_cursors_exist_in_session,
exit_status: None,
is_first_run: false,
+ pane_is_stacked_over: frame_params.pane_is_stacked_over,
+ pane_is_stacked_under: frame_params.pane_is_stacked_under,
+ should_draw_pane_frames: frame_params.should_draw_pane_frames,
}
}
pub fn add_exit_status(&mut self, exit_status: Option<i32>) {
@@ -130,6 +139,17 @@ impl PaneFrame {
background_color(" ", color.map(|c| c.0))
}
fn get_corner(&self, corner: &'static str) -> &'static str {
+ let corner = if !self.should_draw_pane_frames
+ && (corner == boundary_type::TOP_LEFT || corner == boundary_type::TOP_RIGHT)
+ {
+ boundary_type::HORIZONTAL
+ } else if self.pane_is_stacked_under && corner == boundary_type::TOP_RIGHT {
+ boundary_type::BOTTOM_RIGHT
+ } else if self.pane_is_stacked_under && corner == boundary_type::TOP_LEFT {
+ boundary_type::BOTTOM_LEFT
+ } else {
+ corner
+ };
if self.style.rounded_corners {
match corner {
boundary_type::TOP_RIGHT => boundary_type::TOP_RIGHT_ROUND,
@@ -323,6 +343,13 @@ impl PaneFrame {
self.render_my_and_others_focus(max_length)
} else if !self.other_focused_clients.is_empty() {
self.render_other_focused_users(max_length)
+ } else if self.pane_is_stacked_under || self.pane_is_stacked_over {
+ let (first_part, first_part_len) = self.first_exited_held_title_part_full();
+ if first_part_len <= max_length {
+ Some((first_part, first_part_len))
+ } else {
+ None
+ }
} else {
None
}
@@ -617,6 +644,14 @@ impl PaneFrame {
.or_else(|| Some(self.title_line_without_middle()))
.with_context(|| format!("failed to render title '{}'", self.title))
}
+ fn render_one_line_title(&self) -> Result<Vec<TerminalCharacter>> {
+ let total_title_length = self.geom.cols.saturating_sub(2); // 2 for the left and right corners
+
+ self.render_title_middle(total_title_length)
+ .map(|(middle, middle_length)| self.title_line_with_middle(middle, &middle_length))
+ .or_else(|| Some(self.title_line_without_middle()))
+ .with_context(|| format!("failed to render title '{}'", self.title))
+ }
fn render_held_undertitle(&self) -> Result<Vec<TerminalCharacter>> {
let max_undertitle_length = self.geom.cols.saturating_sub(2); // 2 for the left and right corners
let (mut first_part, first_part_len) = self.first_exited_held_title_part_full();
@@ -678,55 +713,69 @@ impl PaneFrame {
pub fn render(&self) -> Result<(Vec<CharacterChunk>, Option<String>)> {
let err_context = || "failed to render pane frame";
let mut character_chunks = vec![];
- for row in 0..self.geom.rows {
- if row == 0 {
- // top row
- let title = self.render_title().with_context(err_context)?;
- let x = self.geom.x;
- let y = self.geom.y + row;
- character_chunks.push(CharacterChunk::new(title, x, y));
- } else if row == self.geom.rows - 1 {
- // bottom row
- if self.exit_status.is_some() || self.is_first_run {
+ if self.geom.rows == 1 || !self.should_draw_pane_frames {
+ // we do this explicitly when not drawing pane frames because this should only happen
+ // if this is a stacked pane with pane frames off (and it doesn't necessarily have only
+ // 1 row because it could also be a flexible stacked pane)
+ // in this case we should always draw the pane title line, and only the title line
+ let one_line_title = self.render_one_line_title().with_context(err_context)?;
+ character_chunks.push(CharacterChunk::new(
+ one_line_title,
+ self.geom.x,
+ self.geom.y,
+ ));
+ } else {
+ for row in 0..self.geom.rows {
+ if row == 0 {
+ // top row
+ let title = self.render_title().with_context(err_context)?;
let x = self.geom.x;
let y = self.geom.y + row;
- character_chunks.push(CharacterChunk::new(
- self.render_held_undertitle().with_context(err_context)?,
- x,
- y,
- ));
- } else {
- let mut bottom_row = vec![];
- for col in 0..self.geom.cols {
- let boundary = if col == 0 {
- // bottom left corner
- self.get_corner(boundary_type::BOTTOM_LEFT)
- } else if col == self.geom.cols - 1 {
- // bottom right corner
- self.get_corner(boundary_type::BOTTOM_RIGHT)
- } else {
- boundary_type::HORIZONTAL
- };
+ character_chunks.push(CharacterChunk::new(title, x, y));
+ } else if row == self.geom.rows - 1 {
+ // bottom row
+ if self.exit_status.is_some() || self.is_first_run {
+ let x = self.geom.x;
+ let y = self.geom.y + row;
+ character_chunks.push(CharacterChunk::new(
+ self.render_held_undertitle().with_context(err_context)?,
+ x,
+ y,
+ ));
+ } else {
+ let mut bottom_row = vec![];
+ for col in 0..self.geom.cols {
+ let boundary = if col == 0 {
+ // bottom left corner
+ self.get_corner(boundary_type::BOTTOM_LEFT)
+ } else if col == self.geom.cols - 1 {
+ // bottom right corner
+ self.get_corner(boundary_type::BOTTOM_RIGHT)
+ } else {
+ boundary_type::HORIZONTAL
+ };
- let mut boundary_character = foreground_color(boundary, self.color);
- bottom_row.append(&mut boundary_character);
+ let mut boundary_character = foreground_color(boundary, self.color);
+ bottom_row.append(&mut boundary_character);
+ }
+ let x = self.geom.x;
+ let y = self.geom.y + row;
+ character_chunks.push(CharacterChunk::new(bottom_row, x, y));
}
+ } else {
+ let boundary_character_left =
+ foreground_color(boundary_type::VERTICAL, self.color);
+ let boundary_character_right =
+ foreground_color(boundary_type::VERTICAL, self.color);
+
let x = self.geom.x;
let y = self.geom.y + row;
- character_chunks.push(CharacterChunk::new(bottom_row, x, y));
- }
- } else {
- let boundary_character_left = foreground_color(boundary_type::VERTICAL, self.color);
- let boundary_character_right =
- foreground_color(boundary_type::VERTICAL, self.color);
-
- let x = self.geom.x;
- let y = self.geom.y + row;
- character_chunks.push(CharacterChunk::new(boundary_character_left, x, y));
+ character_chunks.push(CharacterChunk::new(boundary_character_left, x, y));
- let x = (self.geom.x + self.geom.cols).saturating_sub(1);
- let y = self.geom.y + row;
- character_chunks.push(CharacterChunk::new(boundary_character_right, x, y));
+ let x = (self.geom.x + self.geom.cols).saturating_sub(1);
+ let y = self.geom.y + row;
+ character_chunks.push(CharacterChunk::new(boundary_character_right, x, y));
+ }
}
}
Ok((character_chunks, None))
diff --git a/zellij-server/src/ui/pane_contents_and_ui.rs b/zellij-server/src/ui/pane_contents_and_ui.rs
index 7f718d0b..72f0b804 100644
--- a/zellij-server/src/ui/pane_contents_and_ui.rs
+++ b/zellij-server/src/ui/pane_contents_and_ui.rs
@@ -16,6 +16,9 @@ pub struct PaneContentsAndUi<'a> {
focused_clients: Vec<ClientId>,
multiple_users_exist_in_session: bool,
z_index: Option<usize>,
+ pane_is_stacked_under: bool,
+ pane_is_stacked_over: bool,
+ should_draw_pane_frames: bool,
}
impl<'a> PaneContentsAndUi<'a> {
@@ -26,6 +29,9 @@ impl<'a> PaneContentsAndUi<'a> {
active_panes: &HashMap<ClientId, PaneId>,
multiple_users_exist_in_session: bool,
z_index: Option<usize>,
+ pane_is_stacked_under: bool,
+ pane_is_stacked_over: bool,
+ should_draw_pane_frames: bool,
) -> Self {
let mut focused_clients: Vec<ClientId> = active_panes
.iter()
@@ -40,6 +46,9 @@ impl<'a> PaneContentsAndUi<'a> {
focused_clients,
multiple_users_exist_in_session,
z_index,
+ pane_is_stacked_under,
+ pane_is_stacked_over,
+ should_draw_pane_frames,
}
}
pub fn render_pane_contents_to_multiple_clients(
@@ -194,6 +203,9 @@ impl<'a> PaneContentsAndUi<'a> {
style: self.style,
color: frame_color,
other_cursors_exist_in_session: false,
+ pane_is_stacked_over: self.pane_is_stacked_over,
+ pane_is_stacked_under: self.pane_is_stacked_under,
+ should_draw_pane_frames: self.should_draw_pane_frames,
}
} else {
FrameParams {
@@ -203,6 +215,9 @@ impl<'a> PaneContentsAndUi<'a> {
style: self.style,
color: frame_color,
other_cursors_exist_in_session: self.multiple_users_exist_in_session,
+ pane_is_stacked_over: self.pane_is_stacked_over,
+ pane_is_stacked_under: self.pane_is_stacked_under,
+ should_draw_pane_frames: self.should_draw_pane_frames,
}
};
diff --git a/zellij-server/src/unit/os_input_output_tests.rs b/zellij-server/src/unit/os_input_output_tests.rs
index 58dbf777..7e651083 100644
--- a/zellij-server/src/unit/os_input_output_tests.rs
+++ b/zellij-server/src/unit/os_input_output_tests.rs
@@ -39,6 +39,7 @@ fn get_cwd() {
orig_termios: Arc::new(Mutex::new(test_termios)),
client_senders: Arc::default(),
terminal_id_to_raw_fd: Arc::default(),
+ cached_resizes: Arc::default(),
};
let pid = nix::unistd::getpid();
diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs
index 7b1be55e..616989d1 100644
--- a/zellij-server/src/unit/screen_tests.rs
+++ b/zellij-server/src/unit/screen_tests.rs
@@ -14,7 +14,7 @@ use zellij_utils::data::Resize;
use zellij_utils::errors::{prelude::*, ErrorContext};
use zellij_utils::input::actions::Action;
use zellij_utils::input::command::{RunCommand, TerminalAction};
-use zellij_utils::input::layout::{PaneLayout, SplitDirection};
+use zellij_utils::input::layout::{Layout, SplitDirection, TiledPaneLayout};
use zellij_utils::input::options::Options;
use zellij_utils::ipc::IpcReceiverWithContext;
use zellij_utils::pane_size::{Size, SizeInPixels};
@@ -220,6 +220,7 @@ fn create_new_screen(size: Size) -> Screen {
let mut mode_info = ModeInfo::default();
mode_info.session_name = Some("zellij-test".into());
let draw_pane_frames = false;
+ let auto_layout = true;
let session_is_mirrored = true;
let copy_options = CopyOptions::default();
@@ -229,6 +230,7 @@ fn create_new_screen(size: Size) -> Screen {
max_panes,
mode_info,
draw_pane_frames,
+ auto_layout,
session_is_mirrored,
copy_options,
);
@@ -257,7 +259,7 @@ struct MockScreen {
}
impl MockScreen {
- pub fn run(&mut self, initial_layout: Option<PaneLayout>) -> std::thread::JoinHandle<()> {
+ pub fn run(&mut self, initial_layout: Option<TiledPaneLayout>) -> std::thread::JoinHandle<()> {
let config_options = self.config_options.clone();
let client_attributes = self.client_attributes.clone();
let screen_bus = Bus::new(
@@ -299,6 +301,7 @@ impl MockScreen {
Some(pane_layout.clone()),
vec![], // floating_panes_layout
tab_name,
+ (vec![], vec![]), // swap layouts
self.main_client_id,
));
let _ = self.to_screen.send(ScreenInstruction::ApplyLayout(
@@ -313,7 +316,7 @@ impl MockScreen {
self.last_opened_tab_index = Some(tab_index);
screen_thread
}
- pub fn new_tab(&mut self, tab_layout: PaneLayout) {
+ pub fn new_tab(&mut self, tab_layout: TiledPaneLayout) {
let pane_count = tab_layout.extract_run_instructions().len();
let mut pane_ids = vec![];
let plugin_ids = HashMap::new();
@@ -328,6 +331,7 @@ impl MockScreen {
Some(tab_layout.clone()),
vec![], // floating_panes_layout
tab_name,
+ (vec![], vec![]), // swap layouts
self.main_client_id,
));
let _ = self.to_screen.send(ScreenInstruction::ApplyLayout(
@@ -353,6 +357,7 @@ impl MockScreen {
}
pub fn clone_session_metadata(&self) -> SessionMetaData {
// hack that only clones the clonable parts of SessionMetaData
+ let layout = Box::new(Layout::default()); // this is not actually correct!!
SessionMetaData {
senders: self.session_metadata.senders.clone(),
capabilities: self.session_metadata.capabilities.clone(),
@@ -363,6 +368,7 @@ impl MockScreen {
plugin_thread: None,
pty_writer_thread: None,
background_jobs_thread: None,
+ layout,
}
}
}
@@ -399,6 +405,7 @@ impl MockScreen {
arrow_fonts: Default::default(),
};
+ let layout = Box::new(Layout::default()); // this is not actually correct!!
let session_metadata = SessionMetaData {
senders: ThreadSenders {
to_screen: Some(to_screen.clone()),
@@ -417,6 +424,7 @@ impl MockScreen {
plugin_thread: None,
pty_writer_thread: None,
background_jobs_thread: None,
+ layout,
};
let os_input = FakeInputOutput::default();
@@ -474,10 +482,12 @@ fn new_tab(screen: &mut Screen, pid: u32, tab_index: usize) {
let client_id = 1;
let new_terminal_ids = vec![(pid, None)];
let new_plugin_ids = HashMap::new();
- screen.new_tab(tab_index, client_id).expect("TEST");
+ screen
+ .new_tab(tab_index, (vec![], vec![]), client_id)
+ .expect("TEST");
screen
.apply_layout(
- PaneLayout::default(),
+ TiledPaneLayout::default(),
vec![], // floating panes layout
new_terminal_ids,
vec![], // new floating terminal ids
@@ -1039,9 +1049,9 @@ pub fn send_cli_write_action_to_screen() {
pub fn send_cli_resize_action_to_screen() {
let size = Size { cols: 80, rows: 20 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1078,9 +1088,9 @@ pub fn send_cli_resize_action_to_screen() {
pub fn send_cli_focus_next_pane_action() {
let size = Size { cols: 80, rows: 20 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1116,9 +1126,9 @@ pub fn send_cli_focus_next_pane_action() {
pub fn send_cli_focus_previous_pane_action() {
let size = Size { cols: 80, rows: 20 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1154,9 +1164,9 @@ pub fn send_cli_focus_previous_pane_action() {
pub fn send_cli_move_focus_pane_action() {
let size = Size { cols: 80, rows: 20 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1194,9 +1204,9 @@ pub fn send_cli_move_focus_pane_action() {
pub fn send_cli_move_focus_or_tab_pane_action() {
let size = Size { cols: 80, rows: 20 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1234,9 +1244,9 @@ pub fn send_cli_move_focus_or_tab_pane_action() {
pub fn send_cli_move_pane_action() {
let size = Size { cols: 80, rows: 20 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1248,7 +1258,7 @@ pub fn send_cli_move_pane_action() {
server_receiver
);
let cli_action = CliAction::MovePane {
- direction: Direction::Right,
+ direction: Some(Direction::Right),
};
send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
@@ -1268,9 +1278,9 @@ pub fn send_cli_move_pane_action() {
pub fn send_cli_dump_screen_action() {
let size = Size { cols: 80, rows: 20 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1302,9 +1312,9 @@ pub fn send_cli_dump_screen_action() {
pub fn send_cli_edit_scrollback_action() {
let size = Size { cols: 80, rows: 20 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1350,9 +1360,9 @@ pub fn send_cli_edit_scrollback_action() {
pub fn send_cli_scroll_up_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1404,9 +1414,9 @@ pub fn send_cli_scroll_up_action() {
pub fn send_cli_scroll_down_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1484,9 +1494,9 @@ pub fn send_cli_scroll_down_action() {
pub fn send_cli_scroll_to_bottom_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1558,9 +1568,9 @@ pub fn send_cli_scroll_to_bottom_action() {
pub fn send_cli_scroll_to_top_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1605,9 +1615,9 @@ pub fn send_cli_scroll_to_top_action() {
pub fn send_cli_page_scroll_up_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1651,9 +1661,9 @@ pub fn send_cli_page_scroll_up_action() {
pub fn send_cli_page_scroll_down_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1714,9 +1724,9 @@ pub fn send_cli_page_scroll_down_action() {
pub fn send_cli_half_page_scroll_up_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1760,9 +1770,9 @@ pub fn send_cli_half_page_scroll_up_action() {
pub fn send_cli_half_page_scroll_down_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1823,9 +1833,9 @@ pub fn send_cli_half_page_scroll_down_action() {
pub fn send_cli_toggle_full_screen_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1860,9 +1870,9 @@ pub fn send_cli_toggle_full_screen_action() {
pub fn send_cli_toggle_pane_frames_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -1903,9 +1913,9 @@ pub fn send_cli_toggle_active_tab_sync_action() {
let mut mock_screen = MockScreen::new(size);
let pty_writer_receiver = mock_screen.pty_writer_receiver.take().unwrap();
let session_metadata = mock_screen.clone_session_metadata();
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let screen_thread = mock_screen.run(Some(initial_layout));
let received_pty_instructions = Arc::new(Mutex::new(vec![]));
let pty_writer_thread = log_actions_in_thread!(
@@ -1944,9 +1954,9 @@ pub fn send_cli_new_pane_action_with_default_parameters() {
let mut mock_screen = MockScreen::new(size);
let pty_receiver = mock_screen.pty_receiver.take().unwrap();
let session_metadata = mock_screen.clone_session_metadata();
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let screen_thread = mock_screen.run(Some(initial_layout));
let received_pty_instructions = Arc::new(Mutex::new(vec![]));
let pty_thread = log_actions_in_thread!(
@@ -1984,9 +1994,9 @@ pub fn send_cli_new_pane_action_with_split_direction() {
let mut mock_screen = MockScreen::new(size);
let pty_receiver = mock_screen.pty_receiver.take().unwrap();
let session_metadata = mock_screen.clone_session_metadata();
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let screen_thread = mock_screen.run(Some(initial_layout));
let received_pty_instructions = Arc::new(Mutex::new(vec![]));
let pty_thread = log_actions_in_thread!(
@@ -2024,9 +2034,9 @@ pub fn send_cli_new_pane_action_with_command_and_cwd() {
let mut mock_screen = MockScreen::new(size);
let pty_receiver = mock_screen.pty_receiver.take().unwrap();
let session_metadata = mock_screen.clone_session_metadata();
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let screen_thread = mock_screen.run(Some(initial_layout));
let received_pty_instructions = Arc::new(Mutex::new(vec![]));
let pty_thread = log_actions_in_thread!(
@@ -2064,9 +2074,9 @@ pub fn send_cli_edit_action_with_default_parameters() {
let mut mock_screen = MockScreen::new(size);
let pty_receiver = mock_screen.pty_receiver.take().unwrap();
let session_metadata = mock_screen.clone_session_metadata();
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let screen_thread = mock_screen.run(Some(initial_layout));
let received_pty_instructions = Arc::new(Mutex::new(vec![]));
let pty_thread = log_actions_in_thread!(
@@ -2102,9 +2112,9 @@ pub fn send_cli_edit_action_with_line_number() {
let mut mock_screen = MockScreen::new(size);
let pty_receiver = mock_screen.pty_receiver.take().unwrap();
let session_metadata = mock_screen.clone_session_metadata();
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let screen_thread = mock_screen.run(Some(initial_layout));
let received_pty_instructions = Arc::new(Mutex::new(vec![]));
let pty_thread = log_actions_in_thread!(
@@ -2140,9 +2150,9 @@ pub fn send_cli_edit_action_with_split_direction() {
let mut mock_screen = MockScreen::new(size);
let pty_receiver = mock_screen.pty_receiver.take().unwrap();
let session_metadata = mock_screen.clone_session_metadata();
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let screen_thread = mock_screen.run(Some(initial_layout));
let received_pty_instructions = Arc::new(Mutex::new(vec![]));
let pty_thread = log_actions_in_thread!(
@@ -2177,9 +2187,9 @@ pub fn send_cli_switch_mode_action() {
let client_id = 10; // fake client id should not appear in the screen's state
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let screen_thread = mock_screen.run(Some(initial_layout));
let cli_switch_mode = CliAction::SwitchMode {
input_mode: InputMode::Locked,
@@ -2206,9 +2216,9 @@ pub fn send_cli_switch_mode_action() {
pub fn send_cli_toggle_pane_embed_or_float() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -2252,9 +2262,9 @@ pub fn send_cli_toggle_pane_embed_or_float() {
pub fn send_cli_toggle_floating_panes() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -2307,9 +2317,9 @@ pub fn send_cli_toggle_floating_panes() {
pub fn send_cli_close_pane_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -2344,9 +2354,9 @@ pub fn send_cli_close_pane_action() {
pub fn send_cli_new_tab_action_default_params() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -2385,9 +2395,9 @@ pub fn send_cli_new_tab_action_default_params() {
pub fn send_cli_new_tab_action_with_name_and_layout() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_layout));
@@ -2435,12 +2445,12 @@ pub fn send_cli_new_tab_action_with_name_and_layout() {
pub fn send_cli_next_tab_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
- let mut second_tab_layout = PaneLayout::default();
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
+ let mut second_tab_layout = TiledPaneLayout::default();
second_tab_layout.children_split_direction = SplitDirection::Horizontal;
- second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ second_tab_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
mock_screen.new_tab(second_tab_layout);
let session_metadata = mock_screen.clone_session_metadata();
@@ -2476,12 +2486,12 @@ pub fn send_cli_next_tab_action() {
pub fn send_cli_previous_tab_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
- let mut second_tab_layout = PaneLayout::default();
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
+ let mut second_tab_layout = TiledPaneLayout::default();
second_tab_layout.children_split_direction = SplitDirection::Horizontal;
- second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ second_tab_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
mock_screen.new_tab(second_tab_layout);
let session_metadata = mock_screen.clone_session_metadata();
@@ -2517,12 +2527,12 @@ pub fn send_cli_previous_tab_action() {
pub fn send_cli_goto_tab_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
- let mut second_tab_layout = PaneLayout::default();
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
+ let mut second_tab_layout = TiledPaneLayout::default();
second_tab_layout.children_split_direction = SplitDirection::Horizontal;
- second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ second_tab_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
mock_screen.new_tab(second_tab_layout);
let session_metadata = mock_screen.clone_session_metadata();
@@ -2553,12 +2563,12 @@ pub fn send_cli_goto_tab_action() {
pub fn send_cli_close_tab_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
- let mut second_tab_layout = PaneLayout::default();
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
+ let mut second_tab_layout = TiledPaneLayout::default();
second_tab_layout.children_split_direction = SplitDirection::Horizontal;
- second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ second_tab_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
mock_screen.new_tab(second_tab_layout);
let session_metadata = mock_screen.clone_session_metadata();
@@ -2589,12 +2599,12 @@ pub fn send_cli_close_tab_action() {
pub fn send_cli_rename_tab() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
- let mut second_tab_layout = PaneLayout::default();
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
+ let mut second_tab_layout = TiledPaneLayout::default();
second_tab_layout.children_split_direction = SplitDirection::Horizontal;
- second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ second_tab_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
mock_screen.new_tab(second_tab_layout);
let session_metadata = mock_screen.clone_session_metadata();
@@ -2622,12 +2632,12 @@ pub fn send_cli_rename_tab() {
pub fn send_cli_undo_rename_tab() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
- let mut initial_layout = PaneLayout::default();
+ let mut initial_layout = TiledPaneLayout::default();
initial_layout.children_split_direction = SplitDirection::Vertical;
- initial_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
- let mut second_tab_layout = PaneLayout::default();
+ initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
+ let mut second_tab_layout = TiledPaneLayout::default();
second_tab_layout.children_split_direction = SplitDirection::Horizontal;
- second_tab_layout.children = vec![PaneLayout::default(), PaneLayout::default()];
+ second_tab_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
mock_screen.new_tab(second_tab_layout);
let session_metadata = mock_screen.clone_session_metadata();
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_default_params.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_default_params.snap
index 1ad6b84e..12dc9dd3 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_default_params.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_default_params.snap
@@ -1,17 +1,17 @@
---
source: zellij-server/src/./unit/screen_tests.rs
-assertion_line: 2300
+assertion_line: 2304
expression: "format!(\"{:#?}\", new_tab_action)"
---
Some(
NewTab(
None,
Some(
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Vertical,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -20,8 +20,9 @@ Some(
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -30,6 +31,7 @@ Some(
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -37,6 +39,7 @@ Some(
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
),
[],
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap
index 7190eb8d..c4d4f40a 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap
@@ -1,16 +1,16 @@
---
source: zellij-server/src/./unit/screen_tests.rs
-assertion_line: 2350
+assertion_line: 2354
expression: "format!(\"{:#?}\", new_tab_instruction)"
---
NewTab(
None,
Some(
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -23,8 +23,9 @@ NewTab(
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -37,8 +38,9 @@ NewTab(
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -51,6 +53,7 @@ NewTab(
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -58,6 +61,7 @@ NewTab(
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
),
[],
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_tab.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_tab.snap
index fb7239db..957af3cc 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_tab.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_tab.snap
@@ -1,6 +1,6 @@
---
source: zellij-server/src/./unit/screen_tests.rs
-assertion_line: 2534
+assertion_line: 2538
expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
---
[
@@ -29,11 +29,11 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
NewTab(
None,
Some(
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -42,8 +42,9 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -52,6 +53,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -59,6 +61,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
),
[],
@@ -167,6 +170,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
],
),
@@ -176,11 +183,11 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
NewTab(
None,
Some(
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Vertical,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -189,8 +196,9 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -199,6 +207,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -206,6 +215,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
),
[],
@@ -317,6 +327,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
TabInfo {
position: 1,
@@ -327,6 +341,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
],
),
@@ -351,6 +369,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
TabInfo {
position: 1,
@@ -361,6 +383,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
],
),
@@ -385,6 +411,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
TabInfo {
position: 1,
@@ -395,6 +425,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
],
),
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_tab.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_tab.snap
index bda17001..a229be90 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_tab.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_tab.snap
@@ -1,6 +1,6 @@
---
source: zellij-server/src/./unit/screen_tests.rs
-assertion_line: 2577
+assertion_line: 2581
expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
---
[
@@ -29,11 +29,11 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
NewTab(
None,
Some(
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -42,8 +42,9 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -52,6 +53,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -59,6 +61,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
),
[],
@@ -167,6 +170,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
],
),
@@ -176,11 +183,11 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
NewTab(
None,
Some(
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Vertical,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -189,8 +196,9 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -199,6 +207,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -206,6 +215,7 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
),
[],
@@ -317,6 +327,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
TabInfo {
position: 1,
@@ -327,6 +341,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
],
),
@@ -351,6 +369,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
TabInfo {
position: 1,
@@ -361,6 +383,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
],
),
@@ -385,6 +411,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
TabInfo {
position: 1,
@@ -395,6 +425,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
],
),
@@ -430,6 +464,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
TabInfo {
position: 1,
@@ -440,6 +478,10 @@ expression: "format!(\"{:#?}\", * received_plugin_instructions.lock().unwrap())"
is_sync_panes_active: false,
are_floating_panes_visible: false,
other_focused_clients: [],
+ active_swap_layout_name: Some(
+ "BASE",
+ ),
+ is_swap_layout_dirty: false,
},
],
),
diff --git a/zellij-utils/assets/compact-bar.wasm b/zellij-utils/assets/compact-bar.wasm
new file mode 100644
index 00000000..46267f5e
--- /dev/null
+++ b/zellij-utils/assets/compact-bar.wasm
Binary files differ
diff --git a/zellij-utils/assets/config/default.kdl b/zellij-utils/assets/config/default.kdl
index 248b4026..1e8ddd7c 100644
--- a/zellij-utils/assets/config/default.kdl
+++ b/zellij-utils/assets/config/default.kdl
@@ -40,6 +40,7 @@ keybinds {
move {
bind "Ctrl h" { SwitchToMode "Normal"; }
bind "n" "Tab" { MovePane; }
+ bind "p" { MovePaneBackwards; }
bind "h" "Left" { MovePane "Left"; }
bind "j" "Down" { MovePane "Down"; }
bind "k" "Up" { MovePane "Up"; }
@@ -130,6 +131,7 @@ keybinds {
bind "k" { MoveFocus "Up"; SwitchToMode "Normal"; }
bind "o" { FocusNextPane; }
bind "d" { Detach; }
+ bind "Space" { NextSwapLayout; }
bind "x" { CloseFocus; SwitchToMode "Normal"; }
}
shared_except "locked" {
@@ -142,6 +144,8 @@ keybinds {
bind "Alt k" "Alt Up" { MoveFocus "Up"; }
bind "Alt =" "Alt +" { Resize "Increase"; }
bind "Alt -" { Resize "Decrease"; }
+ bind "Alt [" { PreviousSwapLayout; }
+ bind "Alt ]" { NextSwapLayout; }
}
shared_except "normal" "locked" {
bind "Enter" "Esc" { SwitchToMode "Normal"; }
@@ -203,6 +207,13 @@ plugins {
//
// pane_frames true
+// Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible
+// Options:
+// - true (default)
+// - false
+//
+// auto_layout true
+
// Define color themes for Zellij
// For more examples, see: https://github.com/zellij-org/zellij/tree/main/example/themes
// Once these themes are defined, one of them should to be selected in the "theme" section of this file
diff --git a/zellij-utils/assets/layouts/compact.swap.kdl b/zellij-utils/assets/layouts/compact.swap.kdl
new file mode 100644
index 00000000..e38fa210
--- /dev/null
+++ b/zellij-utils/assets/layouts/compact.swap.kdl
@@ -0,0 +1,91 @@
+tab_template name="ui" {
+ children
+ pane size=1 borderless=true {
+ plugin location="zellij:compact-bar"
+ }
+}
+
+swap_tiled_layout name="vertical" {
+ ui max_panes=4 {
+ pane split_direction="vertical" {
+ pane
+ pane { children; }
+ }
+ }
+ ui max_panes=7 {
+ pane split_direction="vertical" {
+ pane { children; }
+ pane { pane; pane; pane; pane; }
+ }
+ }
+ ui max_panes=11 {
+ pane split_direction="vertical" {
+ pane { children; }
+ pane { pane; pane; pane; pane; }
+ pane { pane; pane; pane; pane; }
+ }
+ }
+}
+
+swap_tiled_layout name="horizontal" {
+ ui max_panes=3 {
+ pane
+ pane
+ }
+ ui max_panes=7 {
+ pane {
+ pane split_direction="vertical" { children; }
+ pane split_direction="vertical" { pane; pane; pane; pane; }
+ }
+ }
+ ui max_panes=11 {
+ pane {
+ pane split_direction="vertical" { children; }
+ pane split_direction="vertical" { pane; pane; pane; pane; }
+ pane split_direction="vertical" { pane; pane; pane; pane; }
+ }
+ }
+}
+
+swap_tiled_layout name="stacked" {
+ ui min_panes=4 {
+ pane split_direction="vertical" {
+ pane
+ pane { children stacked=true; }
+ }
+ }
+}
+
+swap_floating_layout name="staggered" {
+ floating_panes
+}
+
+swap_floating_layout name="enlarged" {
+ floating_panes max_panes=10 {
+ pane { x 1; y 1; width "90%"; height "90%"; }
+ pane { x 2; y 2; width "90%"; height "90%"; }
+ pane { x 3; y 3; width "90%"; height "90%"; }
+ pane { x 4; y 4; width "90%"; height "90%"; }
+ pane { x 5; y 5; width "90%"; height "90%"; }
+ pane { x 6; y 6; width "90%"; height "90%"; }
+ pane { x 7; y 7; width "90%"; height "90%"; }
+ pane { x 8; y 8; width "90%"; height "90%"; }
+ pane { x 9; y 9; width "90%"; height "90%"; }
+ pane focus=true { x 10; y 10; width "90%"; height "90%"; }
+ }
+}
+
+swap_floating_layout name="spread" {
+ floating_panes max_panes=1 {
+ pane {y "50%"; x "50%"; }
+ }
+ floating_panes max_panes=2 {
+ pane { x "1%"; y "25%"; width "45%"; }
+ pane { x "50%"; y "25%"; width "45%"; }
+ }
+ floating_panes max_panes=3 {
+ pane focus=true { y "55%"; width "45%"; height "45%"; }
+ pane { x "1%"; y "1%"; width "45%"; }
+ pane { x "50%"; y "1%"; width "45%"; }
+ }
+}
diff --git a/zellij-utils/assets/layouts/default.swap.kdl b/zellij-utils/assets/layouts/default.swap.kdl
new file mode 100644
index 00000000..51e8afed
--- /dev/null
+++ b/zellij-utils/assets/layouts/default.swap.kdl
@@ -0,0 +1,94 @@
+tab_template name="ui" {
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ children
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+}
+
+swap_tiled_layout name="vertical" {
+ ui max_panes=5 {
+ pane split_direction="vertical" {
+ pane
+ pane { children; }
+ }
+ }
+ ui max_panes=8 {
+ pane split_direction="vertical" {
+ pane { children; }
+ pane { pane; pane; pane; pane; }
+ }
+ }
+ ui max_panes=12 {
+ pane split_direction="vertical" {
+ pane { children; }
+ pane { pane; pane; pane; pane; }
+ pane { pane; pane; pane; pane; }
+ }
+ }
+}
+
+swap_tiled_layout name="horizontal" {
+ ui max_panes=5 {
+ pane
+ pane
+ }
+ ui max_panes=8 {
+ pane {
+ pane split_direction="vertical" { children; }
+ pane split_direction="vertical" { pane; pane; pane; pane; }
+ }
+ }
+ ui max_panes=12 {
+ pane {
+ pane split_direction="vertical" { children; }
+ pane split_direction="vertical" { pane; pane; pane; pane; }
+ pane split_direction="vertical" { pane; pane; pane; pane; }
+ }
+ }
+}
+
+swap_tiled_layout name="stacked" {
+ ui min_panes=5 {
+ pane split_direction="vertical" {
+ pane
+ pane { children stacked=true; }
+ }
+ }
+}
+
+swap_floating_layout name="staggered" {
+ floating_panes
+}
+
+swap_floating_layout name="enlarged" {
+ floating_panes max_panes=10 {
+ pane { x 1; y 1; width "90%"; height "90%"; }
+ pane { x 2; y 2; width "90%"; height "90%"; }
+ pane { x 3; y 3; width "90%"; height "90%"; }
+ pane { x 4; y 4; width "90%"; height "90%"; }
+ pane { x 5; y 5; width "90%"; height "90%"; }
+ pane { x 6; y 6; width "90%"; height "90%"; }
+ pane { x 7; y 7; width "90%"; height "90%"; }
+ pane { x 8; y 8; width "90%"; height "90%"; }
+ pane { x 9; y 9; width "90%"; height "90%"; }
+ pane focus=true { x 10; y 10; width "90%"; height "90%"; }
+ }
+}
+
+swap_floating_layout name="spread" {
+ floating_panes max_panes=1 {
+ pane {y "50%"; x "50%"; }
+ }
+ floating_panes max_panes=2 {
+ pane { x "1%"; y "25%"; width "45%"; }
+ pane { x "50%"; y "25%"; width "45%"; }
+ }
+ floating_panes max_panes=3 {
+ pane focus=true { y "55%"; width "45%"; height "45%"; }
+ pane { x "1%"; y "1%"; width "45%"; }
+ pane { x "50%"; y "1%"; width "45%"; }
+ }
+}
diff --git a/zellij-utils/assets/layouts/strider.kdl b/zellij-utils/assets/layouts/strider.kdl
index dbe8d077..57ec01a7 100644
--- a/zellij-utils/assets/layouts/strider.kdl
+++ b/zellij-utils/assets/layouts/strider.kdl
@@ -1,19 +1,14 @@
layout {
- default_tab_template {
- pane size=1 borderless=true {
- plugin location="zellij:tab-bar"
- }
- children
- pane size=2 borderless=true {
- plugin location="zellij:status-bar"
- }
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
}
- tab {
- pane split_direction="Vertical" {
- pane size="20%" {
- plugin location="zellij:strider"
- }
- pane
+ pane split_direction="Vertical" {
+ pane size="20%" {
+ plugin location="zellij:strider"
}
+ pane
+ }
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
}
}
diff --git a/zellij-utils/assets/layouts/strider.swap.kdl b/zellij-utils/assets/layouts/strider.swap.kdl
new file mode 100644
index 00000000..c6df1575
--- /dev/null
+++ b/zellij-utils/assets/layouts/strider.swap.kdl
@@ -0,0 +1,102 @@
+tab_template name="ui" {
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ pane split_direction="Vertical" {
+ pane size="20%" {
+ plugin location="zellij:strider"
+ }
+ pane {
+ children
+ }
+
+ }
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+}
+
+swap_tiled_layout name="vertical" {
+ ui max_panes=6 {
+ pane split_direction="vertical" {
+ pane
+ pane { children; }
+ }
+ }
+ ui max_panes=9 {
+ pane split_direction="vertical" {
+ pane { children; }
+ pane { pane; pane; pane; pane; }
+ }
+ }
+ ui max_panes=13 {
+ pane split_direction="vertical" {
+ pane { children; }
+ pane { pane; pane; pane; pane; }
+ pane { pane; pane; pane; pane; }
+ }
+ }
+}
+
+swap_tiled_layout name="horizontal" {
+ ui max_panes=6 {
+ pane
+ pane
+ }
+ ui max_panes=9 {
+ pane {
+ pane split_direction="vertical" { children; }
+ pane split_direction="vertical" { pane; pane; pane; pane; }
+ }
+ }
+ ui max_panes=13 {
+ pane {
+ pane split_direction="vertical" { children; }
+ pane split_direction="vertical" { pane; pane; pane; pane; }
+ pane split_direction="vertical" { pane; pane; pane; pane; }
+ }
+ }
+}
+
+swap_tiled_layout name="stacked" {
+ ui min_panes=6 {
+ pane split_direction="vertical" {
+ pane focus=true
+ pane { children stacked=true; }
+ }
+ }
+}
+
+swap_floating_layout name="staggered" {
+ floating_panes
+}
+
+swap_floating_layout name="enlarged" {
+ floating_panes max_panes=10 {
+ pane { x 1; y 1; width "90%"; height "90%"; }
+ pane { x 2; y 2; width "90%"; height "90%"; }
+ pane { x 3; y 3; width "90%"; height "90%"; }
+ pane { x 4; y 4; width "90%"; height "90%"; }
+ pane { x 5; y 5; width "90%"; height "90%"; }
+ pane { x 6; y 6; width "90%"; height "90%"; }
+ pane { x 7; y 7; width "90%"; height "90%"; }
+ pane { x 8; y 8; width "90%"; height "90%"; }
+ pane { x 9; y 9; width "90%"; height "90%"; }
+ pane focus=true { x 10; y 10; width "90%"; height "90%"; }
+ }
+}
+
+swap_floating_layout name="spread" {
+ floating_panes max_panes=1 {
+ pane {y "50%"; x "50%"; }
+ }
+ floating_panes max_panes=2 {
+ pane { x "1%"; y "25%"; width "45%"; }
+ pane { x "50%"; y "25%"; width "45%"; }
+ }
+ floating_panes max_panes=3 {
+ pane focus=true { y "55%"; width "45%"; height "45%"; }
+ pane { x "1%"; y "1%"; width "45%"; }
+ pane { x "50%"; y "1%"; width "45%"; }
+ }
+}
diff --git a/zellij-utils/assets/plugins/compact-bar.wasm b/zellij-utils/assets/plugins/compact-bar.wasm
index 46267f5e..3a18eab8 100644
--- a/zellij-utils/assets/plugins/compact-bar.wasm
+++ b/zellij-utils/assets/plugins/compact-bar.wasm
Binary files differ
diff --git a/zellij-utils/assets/plugins/status-bar.wasm b/zellij-utils/assets/plugins/status-bar.wasm
index 5b4f6eb0..3ea5b48a 100644
--- a/zellij-utils/assets/plugins/status-bar.wasm
+++ b/zellij-utils/assets/plugins/status-bar.wasm
Binary files differ
diff --git a/zellij-utils/assets/plugins/strider.wasm b/zellij-utils/assets/plugins/strider.wasm
index 0af68b2f..589bab10 100644
--- a/zellij-utils/assets/plugins/strider.wasm
+++ b/zellij-utils/assets/plugins/strider.wasm
Binary files differ
diff --git a/zellij-utils/assets/plugins/tab-bar.wasm b/zellij-utils/assets/plugins/tab-bar.wasm
index 1166de83..1ebeacd8 100644
--- a/zellij-utils/assets/plugins/tab-bar.wasm
+++ b/zellij-utils/assets/plugins/tab-bar.wasm
Binary files differ
diff --git a/zellij-utils/assets/status-bar.wasm b/zellij-utils/assets/status-bar.wasm
new file mode 100644
index 00000000..5b4f6eb0
--- /dev/null
+++ b/zellij-utils/assets/status-bar.wasm
Binary files differ
diff --git a/zellij-utils/assets/strider.wasm b/zellij-utils/assets/strider.wasm
new file mode 100644
index 00000000..0af68b2f
--- /dev/null
+++ b/zellij-utils/assets/strider.wasm
Binary files differ
diff --git a/zellij-utils/assets/tab-bar.wasm b/zellij-utils/assets/tab-bar.wasm
new file mode 100644
index 00000000..1166de83
--- /dev/null
+++ b/zellij-utils/assets/tab-bar.wasm
Binary files differ
diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs
index 1ef43e27..ea0b8d72 100644
--- a/zellij-utils/src/cli.rs
+++ b/zellij-utils/src/cli.rs
@@ -180,9 +180,13 @@ pub enum Sessions {
#[derive(Debug, Subcommand, Clone, Serialize, Deserialize)]
pub enum CliAction {
/// Write bytes to the terminal.
- Write { bytes: Vec<u8> },
+ Write {
+ bytes: Vec<u8>,
+ },
/// Write characters to the terminal.
- WriteChars { chars: String },
+ WriteChars {
+ chars: String,
+ },
/// [increase|decrease] the focused panes area at the [left|down|up|right] border.
Resize {
resize: Resize,
@@ -193,13 +197,21 @@ pub enum CliAction {
/// Change focus to the previous pane
FocusPreviousPane,
/// Move the focused pane in the specified direction. [right|left|up|down]
- MoveFocus { direction: Direction },
+ MoveFocus {
+ direction: Direction,
+ },
/// Move focus to the pane or tab (if on screen edge) in the specified direction
/// [right|left|up|down]
- MoveFocusOrTab { direction: Direction },
- /// Change the location of the focused pane in the specified direction
+ MoveFocusOrTab {
+ direction: Direction,
+ },
+ /// Change the location of the focused pane in the specified direction or rotate forwrads
/// [right|left|up|down]
- MovePane { direction: Direction },
+ MovePane {
+ direction: Option<Direction>,
+ },
+ /// Rotate the location of the previous pane backwards
+ MovePaneBackwards,
/// Dump the focused pane to a file
DumpScreen {
path: PathBuf,
@@ -296,7 +308,9 @@ pub enum CliAction {
cwd: Option<PathBuf>,
},
/// Switch input mode of all connected clients [locked|pane|tab|resize|move|search|session]
- SwitchMode { input_mode: InputMode },
+ SwitchMode {
+ input_mode: InputMode,
+ },
/// Embed focused pane if floating or float focused pane if embedded
TogglePaneEmbedOrFloating,
/// Toggle the visibility of all fdirectionloating panes in the current Tab, open one if none exist
@@ -304,7 +318,9 @@ pub enum CliAction {
/// Close the focused pane.
ClosePane,
/// Renames the focused pane
- RenamePane { name: String },
+ RenamePane {
+ name: String,
+ },
/// Remove a previously set pane name
UndoRenamePane,
/// Go to the next tab.
@@ -314,7 +330,9 @@ pub enum CliAction {
/// Close the current tab.
CloseTab,
/// Go to tab with index [index]
- GoToTab { index: u32 },
+ GoToTab {
+ index: u32,
+ },
/// Go to tab with name [name]
GoToTabName {
name: String,
@@ -323,7 +341,9 @@ pub enum CliAction {
create: bool,
},
/// Renames the focused pane
- RenameTab { name: String },
+ RenameTab {
+ name: String,
+ },
/// Remove a previously set tab name
UndoRenameTab,
/// Create a new tab, optionally with a specified tab layout and name
@@ -340,4 +360,6 @@ pub enum CliAction {
#[clap(short, long, value_parser, requires("layout"))]
cwd: Option<PathBuf>,
},
+ PreviousSwapLayout,
+ NextSwapLayout,
}
diff --git a/zellij-utils/src/data.rs b/zellij-utils/src/data.rs
index a0f255da..f5c4828e 100644
--- a/zellij-utils/src/data.rs
+++ b/zellij-utils/src/data.rs
@@ -686,6 +686,8 @@ pub struct TabInfo {
pub is_sync_panes_active: bool,
pub are_floating_panes_visible: bool,
pub other_focused_clients: Vec<ClientId>,
+ pub active_swap_layout_name: Option<String>,
+ pub is_swap_layout_dirty: bool,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs
index a7986de8..3493f84b 100644
--- a/zellij-utils/src/errors.rs
+++ b/zellij-utils/src/errors.rs
@@ -249,6 +249,7 @@ pub enum ScreenContext {
MoveFocusRight,
MoveFocusRightOrNextTab,
MovePane,
+ MovePaneBackwards,
MovePaneDown,
MovePaneUp,
MovePaneRight,
@@ -320,6 +321,8 @@ pub enum ScreenContext {
SearchToggleWrap,
AddRedPaneFrameColorOverride,
ClearPaneFrameColorOverride,
+ PreviousSwapLayout,
+ NextSwapLayout,
}
/// Stack call representations corresponding to the different types of [`PtyInstruction`]s.
diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs
index 7db0e4f3..a4f4b74f 100644
--- a/zellij-utils/src/input/actions.rs
+++ b/zellij-utils/src/input/actions.rs
@@ -1,7 +1,9 @@
//! Definition of the actions that can be bound to keys.
use super::command::RunCommandAction;
-use super::layout::{FloatingPanesLayout, Layout, PaneLayout};
+use super::layout::{
+ FloatingPaneLayout, Layout, SwapFloatingLayout, SwapTiledLayout, TiledPaneLayout,
+};
use crate::cli::CliAction;
use crate::data::InputMode;
use crate::data::{Direction, Resize};
@@ -115,6 +117,7 @@ pub enum Action {
/// If there is no pane in the direction, move to previous/next Tab.
MoveFocusOrTab(Direction),
MovePane(Option<Direction>),
+ MovePaneBackwards,
/// Dumps the screen to a file
DumpScreen(String, bool),
/// Scroll up in focus pane.
@@ -164,7 +167,13 @@ pub enum Action {
PaneNameInput(Vec<u8>),
UndoRenamePane,
/// Create a new tab, optionally with a specified tab layout.
- NewTab(Option<PaneLayout>, Vec<FloatingPanesLayout>, Option<String>), // the String is the tab name
+ NewTab(
+ Option<TiledPaneLayout>,
+ Vec<FloatingPaneLayout>,
+ Option<Vec<SwapTiledLayout>>,
+ Option<Vec<SwapFloatingLayout>>,
+ Option<String>,
+ ), // the String is the tab name
/// Do nothing.
NoOp,
/// Go to the next tab.
@@ -205,13 +214,15 @@ pub enum Action {
/// Toggle case sensitivity of search
SearchToggleOption(SearchOption),
ToggleMouseMode,
+ PreviousSwapLayout,
+ NextSwapLayout,
}
impl Action {
/// Checks that two Action are match except their mutable attributes.
pub fn shallow_eq(&self, other_action: &Action) -> bool {
match (self, other_action) {
- (Action::NewTab(_, _, _), Action::NewTab(_, _, _)) => true,
+ (Action::NewTab(..), Action::NewTab(..)) => true,
_ => self == other_action,
}
}
@@ -228,7 +239,8 @@ impl Action {
CliAction::FocusPreviousPane => Ok(vec![Action::FocusPreviousPane]),
CliAction::MoveFocus { direction } => Ok(vec![Action::MoveFocus(direction)]),
CliAction::MoveFocusOrTab { direction } => Ok(vec![Action::MoveFocusOrTab(direction)]),
- CliAction::MovePane { direction } => Ok(vec![Action::MovePane(Some(direction))]),
+ CliAction::MovePane { direction } => Ok(vec![Action::MovePane(direction)]),
+ CliAction::MovePaneBackwards => Ok(vec![Action::MovePaneBackwards]),
CliAction::DumpScreen { path, full } => Ok(vec![Action::DumpScreen(
path.as_os_str().to_string_lossy().into(),
full,
@@ -342,10 +354,10 @@ impl Action {
.map(|cwd| current_dir.join(cwd))
.or_else(|| Some(current_dir));
if let Some(layout_path) = layout {
- let (path_to_raw_layout, raw_layout) =
+ let (path_to_raw_layout, raw_layout, swap_layouts) =
Layout::stringified_from_path_or_default(Some(&layout_path), None)
.map_err(|e| format!("Failed to load layout: {}", e))?;
- let layout = Layout::from_str(&raw_layout, path_to_raw_layout, cwd).map_err(|e| {
+ let layout = Layout::from_str(&raw_layout, path_to_raw_layout, swap_layouts.as_ref().map(|(f, p)| (f.as_str(), p.as_str())), cwd).map_err(|e| {
let stringified_error = match e {
ConfigError::KdlError(kdl_error) => {
let error = kdl_error.add_src(layout_path.as_path().as_os_str().to_string_lossy().to_string(), String::from(raw_layout));
@@ -381,26 +393,52 @@ impl Action {
if tabs.len() > 1 {
return Err(format!("Tab layout cannot itself have tabs"));
} else if !tabs.is_empty() {
+ let swap_tiled_layouts = if layout.swap_tiled_layouts.is_empty() {
+ None
+ } else {
+ Some(layout.swap_tiled_layouts.clone())
+ };
+ let swap_floating_layouts = if layout.swap_floating_layouts.is_empty() {
+ None
+ } else {
+ Some(layout.swap_floating_layouts.clone())
+ };
let (tab_name, layout, floating_panes_layout) =
tabs.drain(..).next().unwrap();
let name = tab_name.or(name);
Ok(vec![Action::NewTab(
Some(layout),
floating_panes_layout,
+ swap_tiled_layouts,
+ swap_floating_layouts,
name,
)])
} else {
+ let swap_tiled_layouts = if layout.swap_tiled_layouts.is_empty() {
+ None
+ } else {
+ Some(layout.swap_tiled_layouts.clone())
+ };
+ let swap_floating_layouts = if layout.swap_floating_layouts.is_empty() {
+ None
+ } else {
+ Some(layout.swap_floating_layouts.clone())
+ };
let (layout, floating_panes_layout) = layout.new_tab();
Ok(vec![Action::NewTab(
Some(layout),
floating_panes_layout,
+ swap_tiled_layouts,
+ swap_floating_layouts,
name,
)])
}
} else {
- Ok(vec![Action::NewTab(None, vec![], name)])
+ Ok(vec![Action::NewTab(None, vec![], None, None, name)])
}
},
+ CliAction::PreviousSwapLayout => Ok(vec![Action::PreviousSwapLayout]),
+ CliAction::NextSwapLayout => Ok(vec![Action::NextSwapLayout]),
}
}
}
diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs
index eaa2e395..a0d61b24 100644
--- a/zellij-utils/src/input/layout.rs
+++ b/zellij-utils/src/input/layout.rs
@@ -22,6 +22,7 @@ use std::str::FromStr;
use super::plugins::{PluginTag, PluginsConfigError};
use serde::{Deserialize, Serialize};
+use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::vec::Vec;
use std::{
@@ -169,6 +170,21 @@ impl Run {
}
}
}
+ pub fn is_same_category(first: &Option<Run>, second: &Option<Run>) -> bool {
+ match (first, second) {
+ (Some(Run::Plugin(..)), Some(Run::Plugin(..))) => true,
+ (Some(Run::Command(..)), Some(Run::Command(..))) => true,
+ (Some(Run::EditFile(..)), Some(Run::EditFile(..))) => true,
+ (Some(Run::Cwd(..)), Some(Run::Cwd(..))) => true,
+ _ => false,
+ }
+ }
+ pub fn is_terminal(run: &Option<Run>) -> bool {
+ match run {
+ Some(Run::Command(..)) | Some(Run::EditFile(..)) | Some(Run::Cwd(..)) | None => true,
+ _ => false,
+ }
+ }
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
@@ -211,12 +227,27 @@ impl fmt::Display for RunPluginLocation {
}
}
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
+pub enum LayoutConstraint {
+ MaxPanes(usize),
+ MinPanes(usize),
+ NoConstraint,
+}
+
+pub type SwapTiledLayout = (BTreeMap<LayoutConstraint, TiledPaneLayout>, Option<String>); // Option<String> is the swap layout name
+pub type SwapFloatingLayout = (
+ BTreeMap<LayoutConstraint, Vec<FloatingPaneLayout>>,
+ Option<String>,
+); // Option<String> is the swap layout name
+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
pub struct Layout {
- pub tabs: Vec<(Option<String>, PaneLayout, Vec<FloatingPanesLayout>)>,
+ pub tabs: Vec<(Option<String>, TiledPaneLayout, Vec<FloatingPaneLayout>)>,
pub focused_tab_index: Option<usize>,
- pub template: Option<PaneLayout>,
- pub floating_panes_template: Vec<FloatingPanesLayout>,
+ pub template: Option<(TiledPaneLayout, Vec<FloatingPaneLayout>)>,
+ pub swap_layouts: Vec<(TiledPaneLayout, Vec<FloatingPaneLayout>)>,
+ pub swap_tiled_layouts: Vec<SwapTiledLayout>,
+ pub swap_floating_layouts: Vec<SwapFloatingLayout>,
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
@@ -270,8 +301,7 @@ impl FromStr for PercentOrFixed {
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
-pub struct FloatingPanesLayout {
- // TODO: change name to singular
+pub struct FloatingPaneLayout {
pub name: Option<String>,
pub height: Option<PercentOrFixed>,
pub width: Option<PercentOrFixed>,
@@ -281,7 +311,7 @@ pub struct FloatingPanesLayout {
pub focus: Option<bool>,
}
-impl FloatingPanesLayout {
+impl FloatingPaneLayout {
pub fn add_cwd_to_layout(&mut self, cwd: &PathBuf) {
match self.run.as_mut() {
Some(run) => run.add_cwd(cwd),
@@ -292,9 +322,9 @@ impl FloatingPanesLayout {
}
}
-impl From<&PaneLayout> for FloatingPanesLayout {
- fn from(pane_layout: &PaneLayout) -> Self {
- FloatingPanesLayout {
+impl From<&TiledPaneLayout> for FloatingPaneLayout {
+ fn from(pane_layout: &TiledPaneLayout) -> Self {
+ FloatingPaneLayout {
name: pane_layout.name.clone(),
run: pane_layout.run.clone(),
focus: pane_layout.focus,
@@ -304,21 +334,22 @@ impl From<&PaneLayout> for FloatingPanesLayout {
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
-pub struct PaneLayout {
+pub struct TiledPaneLayout {
pub children_split_direction: SplitDirection,
pub name: Option<String>,
- pub children: Vec<PaneLayout>,
+ pub children: Vec<TiledPaneLayout>,
pub split_size: Option<SplitSize>,
pub run: Option<Run>,
pub borderless: bool,
pub focus: Option<bool>,
pub external_children_index: Option<usize>,
+ pub children_are_stacked: bool,
}
-impl PaneLayout {
+impl TiledPaneLayout {
pub fn insert_children_layout(
&mut self,
- children_layout: &mut PaneLayout,
+ children_layout: &mut TiledPaneLayout,
) -> Result<bool, ConfigError> {
// returns true if successfully inserted and false otherwise
match self.external_children_index {
@@ -338,6 +369,30 @@ impl PaneLayout {
},
}
}
+ pub fn insert_children_nodes(
+ &mut self,
+ children_nodes: &mut Vec<TiledPaneLayout>,
+ ) -> Result<bool, ConfigError> {
+ // returns true if successfully inserted and false otherwise
+ match self.external_children_index {
+ Some(external_children_index) => {
+ children_nodes.reverse();
+ for child_node in children_nodes.drain(..) {
+ self.children.insert(external_children_index, child_node);
+ }
+ self.external_children_index = None;
+ Ok(true)
+ },
+ None => {
+ for pane in self.children.iter_mut() {
+ if pane.insert_children_nodes(children_nodes)? {
+ return Ok(true);
+ }
+ }
+ Ok(false)
+ },
+ }
+ }
pub fn children_block_count(&self) -> usize {
let mut count = 0;
if self.external_children_index.is_some() {
@@ -348,11 +403,50 @@ impl PaneLayout {
}
count
}
+ pub fn pane_count(&self) -> usize {
+ if self.children.is_empty() {
+ 1 // self
+ } else {
+ let mut pane_count = 0;
+ for child in &self.children {
+ pane_count += child.pane_count();
+ }
+ pane_count
+ }
+ }
pub fn position_panes_in_space(
&self,
space: &PaneGeom,
- ) -> Result<Vec<(PaneLayout, PaneGeom)>, &'static str> {
- let layouts = split_space(space, self, space);
+ max_panes: Option<usize>,
+ ) -> Result<Vec<(TiledPaneLayout, PaneGeom)>, &'static str> {
+ let layouts = match max_panes {
+ Some(max_panes) => {
+ let mut layout_to_split = self.clone();
+ let pane_count_in_layout = layout_to_split.pane_count();
+ if max_panes > pane_count_in_layout {
+ // the + 1 here is because this was previously an "actual" pane and will now
+ // become just a container, so we need to account for it too
+ // TODO: make sure this works when the `children` node has sibling nodes,
+ // because we really should support that
+ let children_count = (max_panes - pane_count_in_layout) + 1;
+ let mut extra_children = vec![TiledPaneLayout::default(); children_count];
+ if !layout_to_split.has_focused_node() {
+ if let Some(last_child) = extra_children.last_mut() {
+ last_child.focus = Some(true);
+ }
+ }
+ let _ = layout_to_split.insert_children_nodes(&mut extra_children);
+ } else {
+ layout_to_split.truncate(max_panes);
+ }
+ if !layout_to_split.has_focused_node() {
+ layout_to_split.focus_deepest_pane();
+ }
+
+ split_space(space, &layout_to_split, space)?
+ },
+ None => split_space(space, self, space)?,
+ };
for (_pane_layout, pane_geom) in layouts.iter() {
if !pane_geom.is_at_least_minimum_size() {
return Err("No room on screen for this layout!");
@@ -374,8 +468,8 @@ impl PaneLayout {
run_instructions
}
pub fn with_one_pane() -> Self {
- let mut default_layout = PaneLayout::default();
- default_layout.children = vec![PaneLayout::default()];
+ let mut default_layout = TiledPaneLayout::default();
+ default_layout.children = vec![TiledPaneLayout::default()];
default_layout
}
pub fn add_cwd_to_layout(&mut self, cwd: &PathBuf) {
@@ -389,6 +483,79 @@ impl PaneLayout {
child.add_cwd_to_layout(cwd);
}
}
+ pub fn deepest_depth(&self) -> usize {
+ let mut deepest_child_depth = 0;
+ for child in self.children.iter() {
+ let child_deepest_depth = child.deepest_depth();
+ if child_deepest_depth > deepest_child_depth {
+ deepest_child_depth = child_deepest_depth;
+ }
+ }
+ deepest_child_depth + 1
+ }
+ pub fn focus_deepest_pane(&mut self) {
+ let mut deepest_child_index = None;
+ let mut deepest_path = 0;
+ for (i, child) in self.children.iter().enumerate() {
+ let child_deepest_path = child.deepest_depth();
+ if child_deepest_path >= deepest_path {
+ deepest_path = child_deepest_path;
+ deepest_child_index = Some(i)
+ }
+ }
+ match deepest_child_index {
+ Some(deepest_child_index) => {
+ if let Some(child) = self.children.get_mut(deepest_child_index) {
+ child.focus_deepest_pane();
+ }
+ },
+ None => {
+ self.focus = Some(true);
+ },
+ }
+ }
+ pub fn truncate(&mut self, max_panes: usize) -> usize {
+ // returns remaining children length
+ // if max_panes is 1, it means there's only enough panes for this node,
+ // if max_panes is 0, this is probably the root layout being called with 0 max panes
+ if max_panes <= 1 {
+ self.children.clear();
+ } else if max_panes <= self.children.len() {
+ self.children.truncate(max_panes);
+ self.children.iter_mut().for_each(|l| l.children.clear());
+ } else {
+ let mut remaining_panes = max_panes
+ - self
+ .children
+ .iter()
+ .filter(|c| c.children.is_empty())
+ .count();
+ for child in self.children.iter_mut() {
+ if remaining_panes > 1 && child.children.len() > 0 {
+ remaining_panes =
+ remaining_panes.saturating_sub(child.truncate(remaining_panes));
+ } else {
+ child.children.clear();
+ }
+ }
+ }
+ if self.children.len() > 0 {
+ self.children.len()
+ } else {
+ 1 // just me
+ }
+ }
+ pub fn has_focused_node(&self) -> bool {
+ if self.focus.map(|f| f).unwrap_or(false) {
+ return true;
+ };
+ for child in &self.children {
+ if child.has_focused_node() {
+ return true;
+ }
+ }
+ false
+ }
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
@@ -429,8 +596,8 @@ impl Layout {
pub fn stringified_from_path_or_default(
layout_path: Option<&PathBuf>,
layout_dir: Option<PathBuf>,
- ) -> Result<(String, String), ConfigError> {
- // (path_to_layout as String, stringified_layout)
+ ) -> Result<(String, String, Option<(String, String)>), ConfigError> {
+ // (path_to_layout as String, stringified_layout, Option<path_to_swap_layout as String, stringified_swap_layout>)
match layout_path {
Some(layout_path) => {
// The way we determine where to look for the layout is similar to
@@ -455,24 +622,32 @@ impl Layout {
layout_dir: Option<PathBuf>,
config: Config,
) -> Result<(Layout, Config), ConfigError> {
- let (path_to_raw_layout, raw_layout) =
+ let (path_to_raw_layout, raw_layout, raw_swap_layouts) =
Layout::stringified_from_path_or_default(layout_path, layout_dir)?;
- let layout = Layout::from_kdl(&raw_layout, path_to_raw_layout, None)?;
+ let layout = Layout::from_kdl(
+ &raw_layout,
+ path_to_raw_layout,
+ raw_swap_layouts
+ .as_ref()
+ .map(|(r, f)| (r.as_str(), f.as_str())),
+ None,
+ )?;
let config = Config::from_kdl(&raw_layout, Some(config))?; // this merges the two config, with
Ok((layout, config))
}
pub fn from_str(
raw: &str,
path_to_raw_layout: String,
+ swap_layouts: Option<(&str, &str)>, // Option<path_to_swap_layout, stringified_swap_layout>
cwd: Option<PathBuf>,
) -> Result<Layout, ConfigError> {
- Layout::from_kdl(raw, path_to_raw_layout, cwd)
+ Layout::from_kdl(raw, path_to_raw_layout, swap_layouts, cwd)
}
pub fn stringified_from_dir(
layout: &PathBuf,
layout_dir: Option<&PathBuf>,
- ) -> Result<(String, String), ConfigError> {
- // (path_to_layout as String, stringified_layout)
+ ) -> Result<(String, String, Option<(String, String)>), ConfigError> {
+ // (path_to_layout as String, stringified_layout, Option<path_to_swap_layout as String, stringified_swap_layout>)
match layout_dir {
Some(dir) => {
let layout_path = &dir.join(layout);
@@ -485,18 +660,28 @@ impl Layout {
None => Layout::stringified_from_default_assets(layout),
}
}
- pub fn stringified_from_path(layout_path: &Path) -> Result<(String, String), ConfigError> {
- // (path_to_layout as String, stringified_layout)
+ pub fn stringified_from_path(
+ layout_path: &Path,
+ ) -> Result<(String, String, Option<(String, String)>), ConfigError> {
+ // (path_to_layout as String, stringified_layout, Option<path_to_swap_layout as String, stringified_swap_layout>)
let mut layout_file = File::open(&layout_path)
.or_else(|_| File::open(&layout_path.with_extension("kdl")))
.map_err(|e| ConfigError::IoPath(e, layout_path.into()))?;
+ let swap_layout_and_path = Layout::swap_layout_and_path(&layout_path);
+
let mut kdl_layout = String::new();
layout_file.read_to_string(&mut kdl_layout)?;
- Ok((layout_path.as_os_str().to_string_lossy().into(), kdl_layout))
+ Ok((
+ layout_path.as_os_str().to_string_lossy().into(),
+ kdl_layout,
+ swap_layout_and_path,
+ ))
}
- pub fn stringified_from_default_assets(path: &Path) -> Result<(String, String), ConfigError> {
- // (path_to_layout as String, stringified_layout)
+ pub fn stringified_from_default_assets(
+ path: &Path,
+ ) -> Result<(String, String, Option<(String, String)>), ConfigError> {
+ // (path_to_layout as String, stringified_layout, Option<path_to_swap_layout as String, stringified_swap_layout>)
// TODO: ideally these should not be hard-coded
// we should load layouts by name from the config
// and load them from a hashmap or some such
@@ -504,18 +689,31 @@ impl Layout {
Some("default") => Ok((
"Default layout".into(),
Self::stringified_default_from_assets()?,
+ Some((
+ "Default swap layout".into(),
+ Self::stringified_default_swap_from_assets()?,
+ )),
)),
Some("strider") => Ok((
"Strider layout".into(),
Self::stringified_strider_from_assets()?,
+ Some((
+ "Strider swap layout".into(),
+ Self::stringified_strider_swap_from_assets()?,
+ )),
)),
Some("disable-status-bar") => Ok((
"Disable Status Bar layout".into(),
Self::stringified_disable_status_from_assets()?,
+ None,
)),
Some("compact") => Ok((
"Compact layout".into(),
Self::stringified_compact_from_assets()?,
+ Some((
+ "Compact layout swap".into(),
+ Self::stringified_compact_swap_from_assets()?,
+ )),
)),
None | Some(_) => Err(ConfigError::IoPath(
std::io::Error::new(std::io::ErrorKind::Other, "The layout was not found"),
@@ -526,10 +724,15 @@ impl Layout {
pub fn stringified_default_from_assets() -> Result<String, ConfigError> {
Ok(String::from_utf8(setup::DEFAULT_LAYOUT.to_vec())?)
}
-
+ pub fn stringified_default_swap_from_assets() -> Result<String, ConfigError> {
+ Ok(String::from_utf8(setup::DEFAULT_SWAP_LAYOUT.to_vec())?)
+ }
pub fn stringified_strider_from_assets() -> Result<String, ConfigError> {
Ok(String::from_utf8(setup::STRIDER_LAYOUT.to_vec())?)
}
+ pub fn stringified_strider_swap_from_assets() -> Result<String, ConfigError> {
+ Ok(String::from_utf8(setup::STRIDER_SWAP_LAYOUT.to_vec())?)
+ }
pub fn stringified_disable_status_from_assets() -> Result<String, ConfigError> {
Ok(String::from_utf8(setup::NO_STATUS_LAYOUT.to_vec())?)
@@ -539,12 +742,12 @@ impl Layout {
Ok(String::from_utf8(setup::COMPACT_BAR_LAYOUT.to_vec())?)
}
- pub fn new_tab(&self) -> (PaneLayout, Vec<FloatingPanesLayout>) {
- let template = match &self.template {
- Some(template) => template.clone(),
- None => PaneLayout::default(),
- };
- (template, self.floating_panes_template.clone())
+ pub fn stringified_compact_swap_from_assets() -> Result<String, ConfigError> {
+ Ok(String::from_utf8(setup::COMPACT_BAR_SWAP_LAYOUT.to_vec())?)
+ }
+
+ pub fn new_tab(&self) -> (TiledPaneLayout, Vec<FloatingPaneLayout>) {
+ self.template.clone().unwrap_or_default()
}
pub fn is_empty(&self) -> bool {
@@ -555,7 +758,7 @@ impl Layout {
!self.tabs.is_empty()
}
- pub fn tabs(&self) -> Vec<(Option<String>, PaneLayout, Vec<FloatingPanesLayout>)> {
+ pub fn tabs(&self) -> Vec<(Option<String>, TiledPaneLayout, Vec<FloatingPaneLayout>)> {
// String is the tab name
self.tabs.clone()
}
@@ -563,16 +766,60 @@ impl Layout {
pub fn focused_tab_index(&self) -> Option<usize> {
self.focused_tab_index
}
+
+ fn swap_layout_and_path(path: &Path) -> Option<(String, String)> {
+ // Option<path, stringified_swap_layout>
+ let mut swap_layout_path = PathBuf::from(path);
+ swap_layout_path.set_extension("swap.kdl");
+ match File::open(&swap_layout_path) {
+ Ok(mut stringified_swap_layout_file) => {
+ let mut swap_kdl_layout = String::new();
+ match stringified_swap_layout_file.read_to_string(&mut swap_kdl_layout) {
+ Ok(..) => Some((
+ swap_layout_path.as_os_str().to_string_lossy().into(),
+ swap_kdl_layout,
+ )),
+ Err(e) => {
+ log::warn!(
+ "Failed to read swap layout file: {}. Error: {:?}",
+ swap_layout_path.as_os_str().to_string_lossy(),
+ e
+ );
+ None
+ },
+ }
+ },
+ Err(e) => {
+ log::warn!(
+ "Failed to read swap layout file: {}. Error: {:?}",
+ swap_layout_path.as_os_str().to_string_lossy(),
+ e
+ );
+ None
+ },
+ }
+ }
}
fn split_space(
space_to_split: &PaneGeom,
- layout: &PaneLayout,
+ layout: &TiledPaneLayout,
total_space_to_split: &PaneGeom,
-) -> Vec<(PaneLayout, PaneGeom)> {
+) -> Result<Vec<(TiledPaneLayout, PaneGeom)>, &'static str> {
let mut pane_positions = Vec::new();
- let sizes: Vec<Option<SplitSize>> =
- layout.children.iter().map(|part| part.split_size).collect();
+ let sizes: Vec<Option<SplitSize>> = if layout.children_are_stacked {
+ let mut sizes: Vec<Option<SplitSize>> = layout
+ .children
+ .iter()
+ .map(|_part| Some(SplitSize::Fixed(1)))
+ .collect();
+ if let Some(last_size) = sizes.last_mut() {
+ *last_size = None;
+ }
+ sizes
+ } else {
+ layout.children.iter().map(|part| part.split_size).collect()
+ };
let mut split_geom = Vec::new();
let (
@@ -595,7 +842,22 @@ fn split_space(
),
};
+ let min_size_for_panes = sizes.iter().fold(0, |acc, size| match size {
+ Some(SplitSize::Percent(_)) | None => acc + 1, // TODO: minimum height/width as relevant here
+ Some(SplitSize::Fixed(fixed)) => acc + fixed,
+ });
+ if min_size_for_panes > split_dimension_space.as_usize() {
+ return Err("Not enough room for panes"); // TODO: use error infra
+ }
+
let flex_parts = sizes.iter().filter(|s| s.is_none()).count();
+ let total_fixed_size = sizes.iter().fold(0, |acc, s| {
+ if let Some(SplitSize::Fixed(fixed)) = s {
+ acc + fixed
+ } else {
+ acc
+ }
+ });
let mut total_pane_size = 0;
for (&size, _part) in sizes.iter().zip(&*layout.children) {
@@ -617,7 +879,11 @@ fn split_space(
Dimension::percent(free_percent / flex_parts as f64)
},
};
- split_dimension.adjust_inner(total_split_dimension_space.as_usize());
+ split_dimension.adjust_inner(
+ total_split_dimension_space
+ .as_usize()
+ .saturating_sub(total_fixed_size),
+ );
total_pane_size += split_dimension.as_usize();
let geom = match layout.children_split_direction {
@@ -626,20 +892,22 @@ fn split_space(
y: space_to_split.y,
cols: split_dimension,
rows: inherited_dimension,
+ is_stacked: layout.children_are_stacked,
},
SplitDirection::Horizontal => PaneGeom {
x: space_to_split.x,
y: current_position,
cols: inherited_dimension,
rows: split_dimension,
+ is_stacked: layout.children_are_stacked,
},
};
split_geom.push(geom);
current_position += split_dimension.as_usize();
}
- // add extra space from rounding errors to the last pane
if total_pane_size < split_dimension_space.as_usize() {
+ // add extra space from rounding errors to the last pane
let increase_by = split_dimension_space.as_usize() - total_pane_size;
if let Some(last_geom) = split_geom.last_mut() {
match layout.children_split_direction {
@@ -647,21 +915,32 @@ fn split_space(
SplitDirection::Horizontal => last_geom.rows.increase_inner(increase_by),
}
}
+ } else if total_pane_size > split_dimension_space.as_usize() {
+ // remove extra space from rounding errors to the last pane
+ let decrease_by = total_pane_size - split_dimension_space.as_usize();
+ if let Some(last_geom) = split_geom.last_mut() {
+ match layout.children_split_direction {
+ SplitDirection::Vertical => last_geom.cols.decrease_inner(decrease_by),
+ SplitDirection::Horizontal => last_geom.rows.decrease_inner(decrease_by),
+ }
+ }
}
for (i, part) in layout.children.iter().enumerate() {
let part_position_and_size = split_geom.get(i).unwrap();
if !part.children.is_empty() {
let mut part_positions =
- split_space(part_position_and_size, part, total_space_to_split);
+ split_space(part_position_and_size, part, total_space_to_split)?;
pane_positions.append(&mut part_positions);
} else {
- pane_positions.push((part.clone(), *part_position_and_size));
+ let part = part.clone();
+ pane_positions.push((part, *part_position_and_size));
}
}
if pane_positions.is_empty() {
- pane_positions.push((layout.clone(), space_to_split.clone()));
+ let layout = layout.clone();
+ pane_positions.push((layout, space_to_split.clone()));
}
- pane_positions
+ Ok(pane_positions)
}
impl TryFrom<Url> for RunPluginLocation {
diff --git a/zellij-utils/src/input/options.rs b/zellij-utils/src/input/options.rs
index 93f15b2d..684aabc0 100644
--- a/zellij-utils/src/input/options.rs
+++ b/zellij-utils/src/input/options.rs
@@ -116,6 +116,11 @@ pub struct Options {
#[clap(long, value_parser)]
#[serde(default)]
pub attach_to_session: Option<bool>,
+
+ /// Whether to lay out panes in a predefined set of layouts whenever possible
+ #[clap(long, value_parser)]
+ #[serde(default)]
+ pub auto_layout: Option<bool>,
}
#[derive(ArgEnum, Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
@@ -157,6 +162,7 @@ impl Options {
pub fn merge(&self, other: Options) -> Options {
let mouse_mode = other.mouse_mode.or(self.mouse_mode);
let pane_frames = other.pane_frames.or(self.pane_frames);
+ let auto_layout = other.auto_layout.or(self.auto_layout);
let mirror_session = other.mirror_session.or(self.mirror_session);
let simplified_ui = other.simplified_ui.or(self.simplified_ui);
let default_mode = other.default_mode.or(self.default_mode);
@@ -197,6 +203,7 @@ impl Options {
scrollback_editor,
session_name,
attach_to_session,
+ auto_layout,
}
}
@@ -218,6 +225,7 @@ impl Options {
let simplified_ui = merge_bool(other.simplified_ui, self.simplified_ui);
let mouse_mode = merge_bool(other.mouse_mode, self.mouse_mode);
let pane_frames = merge_bool(other.pane_frames, self.pane_frames);
+ let auto_layout = merge_bool(other.auto_layout, self.auto_layout);
let mirror_session = merge_bool(other.mirror_session, self.mirror_session);
let default_mode = other.default_mode.or(self.default_mode);
@@ -258,6 +266,7 @@ impl Options {
scrollback_editor,
session_name,
attach_to_session,
+ auto_layout,
}
}
@@ -288,6 +297,7 @@ impl From<CliOptions> for Options {
fn from(cli_options: CliOptions) -> Self {
let mut opts = cli_options.options;
+ // TODO: what?
if cli_options.no_pane_frames {
opts.pane_frames = Some(false);
}
diff --git a/zellij-utils/src/input/unit/layout_test.rs b/zellij-utils/src/input/unit/layout_test.rs
index d588fcda..f15fd709 100644
--- a/zellij-utils/src/input/unit/layout_test.rs
+++ b/zellij-utils/src/input/unit/layout_test.rs
@@ -4,9 +4,9 @@ use insta::assert_snapshot;
#[test]
fn empty_layout() {
let kdl_layout = "layout";
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout::default()),
+ template: Some((TiledPaneLayout::default(), vec![])),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -19,12 +19,15 @@ fn layout_with_one_pane() {
pane
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![PaneLayout::default()],
- ..Default::default()
- }),
+ template: Some((
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout::default()],
+ ..Default::default()
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -39,16 +42,19 @@ fn layout_with_multiple_panes() {
pane
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![
- PaneLayout::default(),
- PaneLayout::default(),
- PaneLayout::default(),
- ],
- ..Default::default()
- }),
+ template: Some((
+ TiledPaneLayout {
+ children: vec![
+ TiledPaneLayout::default(),
+ TiledPaneLayout::default(),
+ TiledPaneLayout::default(),
+ ],
+ ..Default::default()
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -68,22 +74,25 @@ fn layout_with_nested_panes() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![
- PaneLayout {
- children_split_direction: SplitDirection::Vertical,
- children: vec![PaneLayout::default(), PaneLayout::default()],
- ..Default::default()
- },
- PaneLayout {
- children: vec![PaneLayout::default(), PaneLayout::default()],
- ..Default::default()
- },
- ],
- ..Default::default()
- }),
+ template: Some((
+ TiledPaneLayout {
+ children: vec![
+ TiledPaneLayout {
+ children_split_direction: SplitDirection::Vertical,
+ children: vec![TiledPaneLayout::default(), TiledPaneLayout::default()],
+ ..Default::default()
+ },
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout::default(), TiledPaneLayout::default()],
+ ..Default::default()
+ },
+ ],
+ ..Default::default()
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -106,32 +115,34 @@ fn layout_with_floating_panes() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout::default()),
- floating_panes_template: vec![
- FloatingPanesLayout::default(),
- FloatingPanesLayout {
- x: Some(PercentOrFixed::Fixed(10)),
- y: Some(PercentOrFixed::Percent(10)),
- width: Some(PercentOrFixed::Fixed(10)),
- height: Some(PercentOrFixed::Percent(10)),
- ..Default::default()
- },
- FloatingPanesLayout {
- x: Some(PercentOrFixed::Fixed(10)),
- y: Some(PercentOrFixed::Percent(10)),
- ..Default::default()
- },
- FloatingPanesLayout {
- run: Some(Run::Command(RunCommand {
- command: PathBuf::from("htop"),
- hold_on_close: true,
+ template: Some((
+ TiledPaneLayout::default(),
+ vec![
+ FloatingPaneLayout::default(),
+ FloatingPaneLayout {
+ x: Some(PercentOrFixed::Fixed(10)),
+ y: Some(PercentOrFixed::Percent(10)),
+ width: Some(PercentOrFixed::Fixed(10)),
+ height: Some(PercentOrFixed::Percent(10)),
..Default::default()
- })),
- ..Default::default()
- },
- ],
+ },
+ FloatingPaneLayout {
+ x: Some(PercentOrFixed::Fixed(10)),
+ y: Some(PercentOrFixed::Percent(10)),
+ ..Default::default()
+ },
+ FloatingPaneLayout {
+ run: Some(Run::Command(RunCommand {
+ command: PathBuf::from("htop"),
+ hold_on_close: true,
+ ..Default::default()
+ })),
+ ..Default::default()
+ },
+ ],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -148,13 +159,15 @@ fn layout_with_mixed_panes_and_floating_panes() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![PaneLayout::default(), PaneLayout::default()],
- ..Default::default()
- }),
- floating_panes_template: vec![FloatingPanesLayout::default()],
+ template: Some((
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout::default(), TiledPaneLayout::default()],
+ ..Default::default()
+ },
+ vec![FloatingPaneLayout::default()],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -175,20 +188,22 @@ fn layout_with_floating_panes_template() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![PaneLayout::default()],
- ..Default::default()
- }),
- floating_panes_template: vec![
- FloatingPanesLayout::default(),
- FloatingPanesLayout {
- x: Some(PercentOrFixed::Fixed(10)),
- y: Some(PercentOrFixed::Percent(10)),
+ template: Some((
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout::default()],
..Default::default()
},
- ],
+ vec![
+ FloatingPaneLayout::default(),
+ FloatingPaneLayout {
+ x: Some(PercentOrFixed::Fixed(10)),
+ y: Some(PercentOrFixed::Percent(10)),
+ ..Default::default()
+ },
+ ],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -208,30 +223,32 @@ fn layout_with_shared_tiled_and_floating_panes_template() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![PaneLayout {
- run: Some(Run::Command(RunCommand {
- command: PathBuf::from("htop"),
- hold_on_close: true,
- ..Default::default()
- })),
- ..Default::default()
- }],
- ..Default::default()
- }),
- floating_panes_template: vec![
- FloatingPanesLayout::default(),
- FloatingPanesLayout {
- run: Some(Run::Command(RunCommand {
- command: PathBuf::from("htop"),
- hold_on_close: true,
+ template: Some((
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout {
+ run: Some(Run::Command(RunCommand {
+ command: PathBuf::from("htop"),
+ hold_on_close: true,
+ ..Default::default()
+ })),
..Default::default()
- })),
+ }],
..Default::default()
},
- ],
+ vec![
+ FloatingPaneLayout::default(),
+ FloatingPaneLayout {
+ run: Some(Run::Command(RunCommand {
+ command: PathBuf::from("htop"),
+ hold_on_close: true,
+ ..Default::default()
+ })),
+ ..Default::default()
+ },
+ ],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -254,7 +271,7 @@ fn layout_with_tabs_and_floating_panes() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -265,10 +282,10 @@ fn layout_with_tabs() {
tab
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- tabs: vec![(None, PaneLayout::default(), vec![])],
- template: Some(PaneLayout::default()),
+ tabs: vec![(None, TiledPaneLayout::default(), vec![])],
+ template: Some((TiledPaneLayout::default(), vec![])),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -289,17 +306,17 @@ fn layout_with_nested_differing_tabs() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
tabs: vec![
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: SplitDirection::Vertical,
children: vec![
- PaneLayout::default(),
- PaneLayout::default(),
- PaneLayout::default(),
+ TiledPaneLayout::default(),
+ TiledPaneLayout::default(),
+ TiledPaneLayout::default(),
],
..Default::default()
},
@@ -307,15 +324,15 @@ fn layout_with_nested_differing_tabs() {
),
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: SplitDirection::Horizontal,
- children: vec![PaneLayout::default(), PaneLayout::default()],
+ children: vec![TiledPaneLayout::default(), TiledPaneLayout::default()],
..Default::default()
},
vec![], // floating panes
),
],
- template: Some(PaneLayout::default()),
+ template: Some((TiledPaneLayout::default(), vec![])),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -331,29 +348,32 @@ fn layout_with_panes_in_different_mixed_split_sizes() {
pane size=2;
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![
- PaneLayout {
- split_size: Some(SplitSize::Fixed(1)),
- ..Default::default()
- },
- PaneLayout {
- split_size: Some(SplitSize::Percent(10)),
- ..Default::default()
- },
- PaneLayout {
- split_size: None,
- ..Default::default()
- },
- PaneLayout {
- split_size: Some(SplitSize::Fixed(2)),
- ..Default::default()
- },
- ],
- ..Default::default()
- }),
+ template: Some((
+ TiledPaneLayout {
+ children: vec![
+ TiledPaneLayout {
+ split_size: Some(SplitSize::Fixed(1)),
+ ..Default::default()
+ },
+ TiledPaneLayout {
+ split_size: Some(SplitSize::Percent(10)),
+ ..Default::default()
+ },
+ TiledPaneLayout {
+ split_size: None,
+ ..Default::default()
+ },
+ TiledPaneLayout {
+ split_size: Some(SplitSize::Fixed(2)),
+ ..Default::default()
+ },
+ ],
+ ..Default::default()
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -366,19 +386,22 @@ fn layout_with_command_panes() {
pane command="htop"
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![PaneLayout {
- run: Some(Run::Command(RunCommand {
- command: PathBuf::from("htop"),
- hold_on_close: true,
+ template: Some((
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout {
+ run: Some(Run::Command(RunCommand {
+ command: PathBuf::from("htop"),
+ hold_on_close: true,
+ ..Default::default()
+ })),
..Default::default()
- })),
+ }],
..Default::default()
- }],
- ..Default::default()
- }),
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -391,20 +414,23 @@ fn layout_with_command_panes_and_cwd() {
pane command="htop" cwd="/path/to/my/cwd"
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![PaneLayout {
- run: Some(Run::Command(RunCommand {
- command: PathBuf::from("htop"),
- cwd: Some(PathBuf::from("/path/to/my/cwd")),
- hold_on_close: true,
+ template: Some((
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout {
+ run: Some(Run::Command(RunCommand {
+ command: PathBuf::from("htop"),
+ cwd: Some(PathBuf::from("/path/to/my/cwd")),
+ hold_on_close: true,
+ ..Default::default()
+ })),
..Default::default()
- })),
+ }],
..Default::default()
- }],
- ..Default::default()
- }),
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -419,21 +445,24 @@ fn layout_with_command_panes_and_cwd_and_args() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![PaneLayout {
- run: Some(Run::Command(RunCommand {
- command: PathBuf::from("htop"),
- cwd: Some(PathBuf::from("/path/to/my/cwd")),
- args: vec![String::from("-h"), String::from("-v")],
- hold_on_close: true,
+ template: Some((
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout {
+ run: Some(Run::Command(RunCommand {
+ command: PathBuf::from("htop"),
+ cwd: Some(PathBuf::from("/path/to/my/cwd")),
+ args: vec![String::from("-h"), String::from("-v")],
+ hold_on_close: true,
+ ..Default::default()
+ })),
..Default::default()
- })),
+ }],
..Default::default()
- }],
- ..Default::default()
- }),
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -448,7 +477,7 @@ fn layout_with_command_panes_and_close_on_exit() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -461,7 +490,7 @@ fn layout_with_command_panes_and_start_suspended() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -477,27 +506,32 @@ fn layout_with_plugin_panes() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![
- PaneLayout {
- run: Some(Run::Plugin(RunPlugin {
- location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
- _allow_exec_host_cmd: false,
- })),
- ..Default::default()
- },
- PaneLayout {
- run: Some(Run::Plugin(RunPlugin {
- location: RunPluginLocation::File(PathBuf::from("/path/to/my/plugin.wasm")),
- _allow_exec_host_cmd: false,
- })),
- ..Default::default()
- },
- ],
- ..Default::default()
- }),
+ template: Some((
+ TiledPaneLayout {
+ children: vec![
+ TiledPaneLayout {
+ run: Some(Run::Plugin(RunPlugin {
+ location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
+ _allow_exec_host_cmd: false,
+ })),
+ ..Default::default()
+ },
+ TiledPaneLayout {
+ run: Some(Run::Plugin(RunPlugin {
+ location: RunPluginLocation::File(PathBuf::from(
+ "/path/to/my/plugin.wasm",
+ )),
+ _allow_exec_host_cmd: false,
+ })),
+ ..Default::default()
+ },
+ ],
+ ..Default::default()
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -510,15 +544,18 @@ fn layout_with_borderless_panes() {
pane borderless=true
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![PaneLayout {
- borderless: true,
+ template: Some((
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout {
+ borderless: true,
+ ..Default::default()
+ }],
..Default::default()
- }],
- ..Default::default()
- }),
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -531,15 +568,18 @@ fn layout_with_focused_panes() {
pane focus=true
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![PaneLayout {
- focus: Some(true),
+ template: Some((
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout {
+ focus: Some(true),
+ ..Default::default()
+ }],
..Default::default()
- }],
- ..Default::default()
- }),
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -552,15 +592,18 @@ fn layout_with_pane_names() {
pane name="my awesome pane"
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
- template: Some(PaneLayout {
- children: vec![PaneLayout {
- name: Some("my awesome pane".into()),
+ template: Some((
+ TiledPaneLayout {
+ children: vec![TiledPaneLayout {
+ name: Some("my awesome pane".into()),
+ ..Default::default()
+ }],
..Default::default()
- }],
- ..Default::default()
- }),
+ },
+ vec![],
+ )),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -574,12 +617,12 @@ fn layout_with_tab_names() {
tab name="my cool tab name 2"
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
tabs: vec![
(
Some("my cool tab name 1".into()),
- PaneLayout {
+ TiledPaneLayout {
children: vec![],
..Default::default()
},
@@ -587,14 +630,14 @@ fn layout_with_tab_names() {
),
(
Some("my cool tab name 2".into()),
- PaneLayout {
+ TiledPaneLayout {
children: vec![],
..Default::default()
},
vec![], // floating panes
),
],
- template: Some(PaneLayout::default()),
+ template: Some((TiledPaneLayout::default(), vec![])),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -609,14 +652,14 @@ fn layout_with_focused_tab() {
tab
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
tabs: vec![
- (None, PaneLayout::default(), vec![]),
- (None, PaneLayout::default(), vec![]),
- (None, PaneLayout::default(), vec![]),
+ (None, TiledPaneLayout::default(), vec![]),
+ (None, TiledPaneLayout::default(), vec![]),
+ (None, TiledPaneLayout::default(), vec![]),
],
- template: Some(PaneLayout::default()),
+ template: Some((TiledPaneLayout::default(), vec![])),
focused_tab_index: Some(1),
..Default::default()
};
@@ -643,21 +686,21 @@ fn layout_with_tab_templates() {
one-above-one-below
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
let expected_layout = Layout {
tabs: vec![
(
Some("my first tab".into()),
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: SplitDirection::Horizontal,
children: vec![
- PaneLayout::default(),
- PaneLayout {
+ TiledPaneLayout::default(),
+ TiledPaneLayout {
children_split_direction: SplitDirection::Vertical,
- children: vec![PaneLayout::default(), PaneLayout::default()],
+ children: vec![TiledPaneLayout::default(), TiledPaneLayout::default()],
..Default::default()
},
- PaneLayout::default(),
+ TiledPaneLayout::default(),
],
..Default::default()
},
@@ -665,16 +708,16 @@ fn layout_with_tab_templates() {
),
(
Some("my second tab".into()),
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: SplitDirection::Horizontal,
children: vec![
- PaneLayout::default(),
- PaneLayout {
+ TiledPaneLayout::default(),
+ TiledPaneLayout {
children_split_direction: SplitDirection::Horizontal,
- children: vec![PaneLayout::default(), PaneLayout::default()],
+ children: vec![TiledPaneLayout::default(), TiledPaneLayout::default()],
..Default::default()
},
- PaneLayout::default(),
+ TiledPaneLayout::default(),
],
..Default::default()
},
@@ -682,19 +725,19 @@ fn layout_with_tab_templates() {
),
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: SplitDirection::Horizontal,
children: vec![
- PaneLayout::default(),
- PaneLayout::default(),
- PaneLayout::default(),
+ TiledPaneLayout::default(),
+ TiledPaneLayout::default(),
+ TiledPaneLayout::default(),
],
..Default::default()
},
vec![], // floating panes
),
],
- template: Some(PaneLayout::default()),
+ template: Some((TiledPaneLayout::default(), vec![])),
..Default::default()
};
assert_eq!(layout, expected_layout);
@@ -720,7 +763,7 @@ fn layout_with_default_tab_template() {
tab
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -747,7 +790,7 @@ fn layout_with_pane_templates() {
left-and-right
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -768,7 +811,7 @@ fn layout_with_tab_and_pane_templates() {
left-right-and-htop
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -789,7 +832,7 @@ fn layout_with_nested_pane_templates() {
left-and-right
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -815,7 +858,7 @@ fn layout_with_nested_branched_pane_templates() {
left-and-right
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -839,7 +882,7 @@ fn circular_dependency_pane_templates_error() {
one
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(layout.is_err(), "circular dependency detected");
}
@@ -861,7 +904,7 @@ fn children_not_as_first_child_of_tab_template() {
horizontal-with-vertical-top
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -884,7 +927,7 @@ fn error_on_more_than_one_children_block_in_tab_template() {
horizontal-with-vertical-top
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(
layout.is_err(),
"error provided for more than one children block"
@@ -909,7 +952,7 @@ fn children_not_as_first_child_of_pane_template() {
horizontal-with-vertical-top
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -932,7 +975,7 @@ fn error_on_more_than_one_children_block_in_pane_template() {
horizontal-with-vertical-top
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(
layout.is_err(),
"error provided for more than one children block"
@@ -961,7 +1004,7 @@ fn combined_tab_and_pane_template_both_with_children() {
horizontal-with-vertical-top
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -977,7 +1020,7 @@ fn cannot_define_tab_template_name_with_space() {
pane
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(layout.is_err(), "error provided for tab name with space");
}
@@ -993,7 +1036,7 @@ fn cannot_define_pane_template_name_with_space() {
pane
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(layout.is_err(), "error provided for tab name with space");
}
@@ -1007,7 +1050,7 @@ fn cannot_define_panes_and_tabs_on_same_level() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(
layout.is_err(),
"error provided for tab and pane on the same level"
@@ -1041,7 +1084,7 @@ fn cannot_define_tab_template_names_as_keywords() {
",
keyword
);
- let layout = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None, None);
assert!(
layout.is_err(),
"{}",
@@ -1079,7 +1122,7 @@ fn cannot_define_pane_template_names_as_keywords() {
",
keyword
);
- let layout = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None, None);
assert!(
layout.is_err(),
"{}",
@@ -1099,7 +1142,8 @@ fn error_on_multiple_layout_nodes_in_file() {
layout
"
);
- let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
+ let layout_error =
+ Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None, None).unwrap_err();
assert_snapshot!(format!("{:?}", layout_error));
}
@@ -1114,7 +1158,8 @@ fn error_on_unknown_layout_node() {
}}
"
);
- let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
+ let layout_error =
+ Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None, None).unwrap_err();
assert_snapshot!(format!("{:?}", layout_error));
}
@@ -1127,7 +1172,8 @@ fn error_on_unknown_layout_pane_property() {
}}
"
);
- let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
+ let layout_error =
+ Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None, None).unwrap_err();
assert_snapshot!(format!("{:?}", layout_error));
}
@@ -1140,7 +1186,8 @@ fn error_on_unknown_layout_pane_template_property() {
}}
"
);
- let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
+ let layout_error =
+ Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None, None).unwrap_err();
assert_snapshot!(format!("{:?}", layout_error));
}
@@ -1153,7 +1200,8 @@ fn error_on_unknown_layout_tab_property() {
}}
"
);
- let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
+ let layout_error =
+ Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None, None).unwrap_err();
assert_snapshot!(format!("{:?}", layout_error));
}
@@ -1166,7 +1214,8 @@ fn error_on_unknown_layout_tab_template_property() {
}}
"
);
- let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
+ let layout_error =
+ Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None, None).unwrap_err();
assert_snapshot!(format!("{:?}", layout_error));
}
@@ -1183,7 +1232,8 @@ fn error_on_pane_templates_without_a_name() {
}}
"
);
- let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
+ let layout_error =
+ Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None, None).unwrap_err();
assert_snapshot!(format!("{:?}", layout_error));
}
@@ -1200,7 +1250,8 @@ fn error_on_tab_templates_without_a_name() {
}}
"
);
- let layout_error = Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None).unwrap_err();
+ let layout_error =
+ Layout::from_kdl(&kdl_layout, "layout_file_name".into(), None, None).unwrap_err();
assert_snapshot!(format!("{:?}", layout_error));
}
@@ -1213,7 +1264,8 @@ fn error_on_more_than_one_focused_tab() {
tab
}
"#;
- let layout_error = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap_err();
+ let layout_error =
+ Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap_err();
assert_snapshot!(format!("{:?}", layout_error));
}
@@ -1231,7 +1283,7 @@ fn args_override_args_in_template() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1249,7 +1301,7 @@ fn close_on_exit_overrides_close_on_exit_in_template() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1266,7 +1318,7 @@ fn args_added_to_args_in_template() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1283,7 +1335,7 @@ fn close_on_exit_added_to_close_on_exit_in_template() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1301,7 +1353,7 @@ fn cwd_override_cwd_in_template() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1318,7 +1370,7 @@ fn cwd_added_to_cwd_in_template() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1331,7 +1383,7 @@ fn error_on_mixed_command_and_child_panes() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(layout.is_err(), "error provided");
}
@@ -1345,7 +1397,7 @@ fn error_on_mixed_cwd_and_child_panes() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(layout.is_err(), "error provided");
}
@@ -1358,7 +1410,7 @@ fn error_on_bare_args_without_command() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(layout.is_err(), "error provided");
}
@@ -1371,7 +1423,7 @@ fn error_on_bare_close_on_exit_without_command() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(layout.is_err(), "error provided");
}
@@ -1385,7 +1437,7 @@ fn error_on_bare_args_in_template_without_command() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(layout.is_err(), "error provided");
}
@@ -1399,7 +1451,7 @@ fn error_on_bare_close_on_exit_in_template_without_command() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None);
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None);
assert!(layout.is_err(), "error provided");
}
@@ -1418,7 +1470,7 @@ fn pane_template_command_with_cwd_overriden_by_its_consumers_command_cwd() {
// pane should have /tmp/foo and not /tmp/bar as cwd
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1435,7 +1487,7 @@ fn pane_template_command_with_cwd_remains_when_its_consumer_command_does_not_hav
// pane should have /tmp/bar as its cwd with the pwd command
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1453,7 +1505,7 @@ fn pane_template_command_without_cwd_is_overriden_by_its_consumers_cwd() {
// pane should have /tmp/bar as its cwd with the pwd command
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1472,7 +1524,7 @@ fn pane_template_command_with_cwd_is_overriden_by_its_consumers_bare_cwd() {
// pane should have /tmp/bar as its cwd with the tail command
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1490,7 +1542,7 @@ fn pane_template_command_without_cwd_receives_its_consumers_bare_cwd() {
// pane should have /tmp/bar as its cwd with the tail command
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1508,7 +1560,7 @@ fn pane_template_with_bare_cwd_overriden_by_its_consumers_bare_cwd() {
// pane should have /tmp/foo without a command
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1524,7 +1576,7 @@ fn pane_template_with_bare_propagated_to_its_consumer_command_without_cwd() {
// pane should have /tmp/foo with the tail command
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1542,7 +1594,7 @@ fn pane_template_with_bare_propagated_to_its_consumer_command_with_cwd() {
// pane should have /tmp/bar with the tail command
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1558,7 +1610,7 @@ fn pane_template_with_bare_propagated_to_its_consumer_edit() {
// pane should have /tmp/foo/bar with the edit file variant
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1574,7 +1626,7 @@ fn pane_template_with_command_propagated_to_its_consumer_edit() {
// pane should have /tmp/foo/bar with the edit file variant
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1588,7 +1640,7 @@ fn global_cwd_given_to_panes_without_cwd() {
// both should have the /tmp cwd
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1601,7 +1653,7 @@ fn global_cwd_prepended_to_panes_with_cwd() {
pane command="tail" cwd="/home/foo" // should be /home/foo because its an absolute path
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1618,6 +1670,7 @@ fn global_cwd_passed_from_layout_constructor() {
let layout = Layout::from_kdl(
kdl_layout,
"layout_file_name".into(),
+ None,
Some(PathBuf::from("/tmp")),
)
.unwrap();
@@ -1638,6 +1691,7 @@ fn global_cwd_passed_from_layout_constructor_overrides_global_cwd_in_layout_file
let layout = Layout::from_kdl(
kdl_layout,
"layout_file_name".into(),
+ None,
Some(PathBuf::from("/tmp")),
)
.unwrap();
@@ -1656,7 +1710,7 @@ fn global_cwd_with_tab_cwd_given_to_panes_without_cwd() {
// both should have the /tmp/foo cwd
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1671,7 +1725,7 @@ fn tab_cwd_given_to_panes_without_cwd() {
// both should have the /tmp cwd
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1686,7 +1740,7 @@ fn tab_cwd_prepended_to_panes_with_cwd() {
// both should have the /tmp/foo cwd
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1701,7 +1755,7 @@ fn global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd() {
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1722,7 +1776,7 @@ fn global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_pane_templa
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
@@ -1741,6 +1795,57 @@ fn global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_tab_templat
}
}
"#;
- let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None).unwrap();
+ let layout = Layout::from_kdl(kdl_layout, "layout_file_name".into(), None, None).unwrap();
+ assert_snapshot!(format!("{:#?}", layout));
+}
+
+#[test]
+fn can_load_swap_layouts_from_a_different_file() {
+ let kdl_layout = r#"
+ layout {
+ // here we define a tab_template in the main layout and later make sure we can sue it
+ // in the swap layouts
+ tab_template name="ui" {
+ pane size=1 borderless=true {
+ plugin location="zellij:tab-bar"
+ }
+ children
+ pane size=2 borderless=true {
+ plugin location="zellij:status-bar"
+ }
+ }
+ pane
+ }
+ "#;
+ let kdl_swap_layout = r#"
+ swap_tiled_layout name="vertical" {
+ ui max_panes=5 {
+ pane split_direction="vertical" {
+ pane
+ pane { children; }
+ }
+ }
+ ui max_panes=8 {
+ pane split_direction="vertical" {
+ pane { children; }
+ pane { pane; pane; pane; pane; }
+ }
+ }
+ ui max_panes=12 {
+ pane split_direction="vertical" {
+ pane { children; }
+ pane { pane; pane; pane; pane; }
+ pane { pane; pane; pane; pane; }
+ }
+ }
+ }
+ "#;
+ let layout = Layout::from_kdl(
+ kdl_layout,
+ "layout_file_name".into(),
+ Some(("swap_layout_file_name".into(), kdl_swap_layout)),
+ None,
+ )
+ .unwrap();
assert_snapshot!(format!("{:#?}", layout));
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_added_to_args_in_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_added_to_args_in_template.snap
index 0fc51aad..79990832 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_added_to_args_in_template.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_added_to_args_in_template.snap
@@ -1,66 +1,74 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1101
+assertion_line: 1266
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: None,
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: None,
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [
- "-f",
- "/tmp/bar",
- ],
- cwd: None,
- hold_on_close: true,
- hold_on_start: false,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [
+ "-f",
+ "/tmp/bar",
+ ],
+ cwd: None,
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_override_args_in_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_override_args_in_template.snap
index 64d47573..bb691fe7 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_override_args_in_template.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_override_args_in_template.snap
@@ -1,69 +1,77 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1066
+assertion_line: 1231
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [
- "-f",
- "/tmp/foo",
- ],
- cwd: None,
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [
+ "-f",
+ "/tmp/foo",
+ ],
+ cwd: None,
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [
- "-f",
- "/tmp/bar",
- ],
- cwd: None,
- hold_on_close: true,
- hold_on_start: false,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [
+ "-f",
+ "/tmp/bar",
+ ],
+ cwd: None,
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__can_load_swap_layouts_from_a_different_file.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__can_load_swap_layouts_from_a_different_file.snap
new file mode 100644
index 00000000..be292b58
--- /dev/null
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__can_load_swap_layouts_from_a_different_file.snap
@@ -0,0 +1,536 @@
+---
+source: zellij-utils/src/input/./unit/layout_test.rs
+assertion_line: 1788
+expression: "format!(\"{:#?}\", layout)"
+---
+Layout {
+ tabs: [],
+ focused_tab_index: None,
+ template: Some(
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
+ ),
+ swap_layouts: [],
+ swap_tiled_layouts: [
+ (
+ {
+ MaxPanes(
+ 5,
+ ): TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: Some(
+ 0,
+ ),
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ MaxPanes(
+ 8,
+ ): TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: Some(
+ 0,
+ ),
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ MaxPanes(
+ 12,
+ ): TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: Some(
+ 0,
+ ),
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ },
+ Some(
+ "vertical",
+ ),
+ ),
+ ],
+ swap_floating_layouts: [],
+}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_pane_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_pane_template.snap
index 36eeb717..304f0169 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_pane_template.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_pane_template.snap
@@ -1,142 +1,159 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 744
+assertion_line: 909
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: Some(
- "my pane",
- ),
- children: [
- PaneLayout {
- children_split_direction: Vertical,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Vertical,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: Some(
- 1,
- ),
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: Some(
+ "my pane",
+ ),
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: Some(
+ 1,
+ ),
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_tab_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_tab_template.snap
index ac027457..ded8fd1f 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_tab_template.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__children_not_as_first_child_of_tab_template.snap
@@ -1,6 +1,6 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 696
+assertion_line: 861
expression: "format!(\"{:#?}\", layout)"
---
Layout {
@@ -9,15 +9,15 @@ Layout {
Some(
"my tab",
),
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Vertical,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -26,12 +26,13 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -40,8 +41,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -50,6 +52,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -57,6 +60,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -64,8 +68,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -74,6 +79,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -81,20 +87,21 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Vertical,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -103,6 +110,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -112,8 +120,9 @@ Layout {
external_children_index: Some(
1,
),
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -122,6 +131,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -129,22 +139,29 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_added_to_close_on_exit_in_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_added_to_close_on_exit_in_template.snap
index 0386fd19..b7ed1fe8 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_added_to_close_on_exit_in_template.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_added_to_close_on_exit_in_template.snap
@@ -1,63 +1,71 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1118
+assertion_line: 1283
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: None,
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: None,
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: None,
- hold_on_close: false,
- hold_on_start: false,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: None,
+ hold_on_close: false,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_overrides_close_on_exit_in_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_overrides_close_on_exit_in_template.snap
index 487bfb82..b0c35796 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_overrides_close_on_exit_in_template.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_overrides_close_on_exit_in_template.snap
@@ -1,63 +1,71 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1084
+assertion_line: 1249
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: None,
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: None,
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: None,
- hold_on_close: false,
- hold_on_start: false,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: None,
+ hold_on_close: false,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__combined_tab_and_pane_template_both_with_children.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__combined_tab_and_pane_template_both_with_children.snap
index 0c4cb680..ad335416 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__combined_tab_and_pane_template_both_with_children.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__combined_tab_and_pane_template_both_with_children.snap
@@ -1,6 +1,6 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 796
+assertion_line: 961
expression: "format!(\"{:#?}\", layout)"
---
Layout {
@@ -9,15 +9,15 @@ Layout {
Some(
"my tab",
),
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Vertical,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -26,12 +26,13 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: Some(
"middle",
@@ -42,6 +43,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -49,8 +51,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -59,6 +62,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -66,12 +70,13 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -80,8 +85,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -90,6 +96,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -97,6 +104,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -104,20 +112,21 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Vertical,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -126,12 +135,13 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: Some(
"middle",
@@ -142,6 +152,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -149,8 +160,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -159,6 +171,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -166,8 +179,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -176,6 +190,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -183,22 +198,29 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_added_to_cwd_in_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_added_to_cwd_in_template.snap
index beb1f67f..1940a648 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_added_to_cwd_in_template.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_added_to_cwd_in_template.snap
@@ -1,65 +1,73 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1153
+assertion_line: 1318
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: None,
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: None,
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/home",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/home",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_override_cwd_in_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_override_cwd_in_template.snap
index 36cc0c24..f89eb14e 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_override_cwd_in_template.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_override_cwd_in_template.snap
@@ -1,67 +1,75 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1136
+assertion_line: 1301
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/tmp",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/tmp",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd.snap
index 71b46db4..0c0dc06d 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd.snap
@@ -1,17 +1,17 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1536
+assertion_line: 1701
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -24,8 +24,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -46,6 +47,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -57,22 +59,29 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_pane_templates.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_pane_templates.snap
index 5c39bbd1..7859311c 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_pane_templates.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_pane_templates.snap
@@ -1,21 +1,21 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1557
+assertion_line: 1722
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -28,8 +28,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -50,12 +51,13 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -68,6 +70,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -79,6 +82,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -90,6 +94,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -101,22 +106,29 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_tab_templates.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_tab_templates.snap
index 4c6bfd2d..76d08d57 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_tab_templates.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_tab_templates.snap
@@ -1,17 +1,17 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1576
+assertion_line: 1741
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -24,8 +24,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -46,12 +47,13 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -64,6 +66,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -75,6 +78,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -86,22 +90,29 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_given_to_panes_without_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_given_to_panes_without_cwd.snap
index 5256565c..c9b824bd 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_given_to_panes_without_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_given_to_panes_without_cwd.snap
@@ -1,59 +1,67 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1423
+assertion_line: 1588
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Cwd(
- "/tmp",
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Cwd(
+ "/tmp",
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/tmp",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/tmp",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor.snap
index b0eaf353..328b9bc9 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor.snap
@@ -1,59 +1,67 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1455
+assertion_line: 1620
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Cwd(
- "/tmp",
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Cwd(
+ "/tmp",
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/tmp",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/tmp",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor_overrides_global_cwd_in_layout_file.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor_overrides_global_cwd_in_layout_file.snap
index 5aa11997..d16986e1 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor_overrides_global_cwd_in_layout_file.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor_overrides_global_cwd_in_layout_file.snap
@@ -1,59 +1,67 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1475
+assertion_line: 1640
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Cwd(
- "/tmp",
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Cwd(
+ "/tmp",
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/tmp",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/tmp",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_prepended_to_panes_with_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_prepended_to_panes_with_cwd.snap
index 8c5d71c1..3b445963 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_prepended_to_panes_with_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_prepended_to_panes_with_cwd.snap
@@ -1,59 +1,67 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1436
+assertion_line: 1601
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Cwd(
- "/tmp/foo",
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Cwd(
+ "/tmp/foo",
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/home/foo",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/home/foo",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_with_tab_cwd_given_to_panes_without_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_with_tab_cwd_given_to_panes_without_cwd.snap
index b54634fb..58602c68 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_with_tab_cwd_given_to_panes_without_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_with_tab_cwd_given_to_panes_without_cwd.snap
@@ -1,17 +1,17 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1491
+assertion_line: 1656
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -24,8 +24,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -46,6 +47,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -57,22 +59,29 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_close_on_exit.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_close_on_exit.snap
index c16d495e..83f17c11 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_close_on_exit.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_close_on_exit.snap
@@ -1,43 +1,50 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 283
+assertion_line: 448
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "htop",
- args: [],
- cwd: None,
- hold_on_close: false,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "htop",
+ args: [],
+ cwd: None,
+ hold_on_close: false,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_start_suspended.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_start_suspended.snap
index 6723bc21..8b3afcdd 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_start_suspended.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_start_suspended.snap
@@ -1,43 +1,50 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 296
+assertion_line: 461
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "htop",
- args: [],
- cwd: None,
- hold_on_close: true,
- hold_on_start: true,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "htop",
+ args: [],
+ cwd: None,
+ hold_on_close: true,
+ hold_on_start: true,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_default_tab_template.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_default_tab_template.snap
index 8065fc4d..daf284ff 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_default_tab_template.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_default_tab_template.snap
@@ -1,6 +1,6 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 555
+assertion_line: 720
expression: "format!(\"{:#?}\", layout)"
---
Layout {
@@ -9,11 +9,11 @@ Layout {
Some(
"my first tab",
),
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -22,12 +22,13 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Vertical,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -36,8 +37,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -46,6 +48,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -53,8 +56,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -63,6 +67,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -70,6 +75,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
@@ -77,11 +83,11 @@ Layout {
Some(
"my second tab",
),
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -90,12 +96,13 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -104,8 +111,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -114,6 +122,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -121,8 +130,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -131,6 +141,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -138,16 +149,17 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -156,8 +168,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -166,8 +179,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -176,6 +190,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -183,53 +198,63 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_branched_pane_templates.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_branched_pane_templates.snap
index 687d7618..cb166970 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_branched_pane_templates.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_branched_pane_templates.snap
@@ -1,126 +1,142 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 650
+assertion_line: 815
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Vertical,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_pane_templates.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_pane_templates.snap
index e5a655f7..3fab5306 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_pane_templates.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_nested_pane_templates.snap
@@ -1,95 +1,108 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 624
+assertion_line: 789
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Vertical,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_pane_templates.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_pane_templates.snap
index cbbddf74..f52d2c97 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_pane_templates.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_pane_templates.snap
@@ -1,240 +1,267 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 582
+assertion_line: 747
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Vertical,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Vertical,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Vertical,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Vertical,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Vertical,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tab_and_pane_templates.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tab_and_pane_templates.snap
index 464c1647..9126477e 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tab_and_pane_templates.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tab_and_pane_templates.snap
@@ -1,21 +1,21 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 603
+assertion_line: 768
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Vertical,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -24,12 +24,13 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -48,6 +49,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -55,8 +57,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -65,6 +68,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -72,6 +76,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -79,22 +84,29 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap
index 5cdf517a..61286160 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap
@@ -1,17 +1,17 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 263
+assertion_line: 254
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -20,6 +20,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -27,9 +28,10 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[
- FloatingPanesLayout {
+ FloatingPaneLayout {
name: None,
height: None,
width: None,
@@ -42,11 +44,11 @@ Layout {
),
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -55,6 +57,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -62,9 +65,10 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[
- FloatingPanesLayout {
+ FloatingPaneLayout {
name: None,
height: None,
width: None,
@@ -73,7 +77,7 @@ Layout {
run: None,
focus: None,
},
- FloatingPanesLayout {
+ FloatingPaneLayout {
name: None,
height: None,
width: None,
@@ -87,16 +91,22 @@ Layout {
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_is_overriden_by_its_consumers_bare_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_is_overriden_by_its_consumers_bare_cwd.snap
index 4f4552ee..a3a4965c 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_is_overriden_by_its_consumers_bare_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_is_overriden_by_its_consumers_bare_cwd.snap
@@ -1,45 +1,52 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1307
+assertion_line: 1472
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/tmp/bar",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/tmp/bar",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_overriden_by_its_consumers_command_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_overriden_by_its_consumers_command_cwd.snap
index fc5523fa..a0d1a943 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_overriden_by_its_consumers_command_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_overriden_by_its_consumers_command_cwd.snap
@@ -1,45 +1,52 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1253
+assertion_line: 1418
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "pwd",
- args: [],
- cwd: Some(
- "/tmp/foo",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "pwd",
+ args: [],
+ cwd: Some(
+ "/tmp/foo",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_remains_when_its_consumer_command_does_not_have_a_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_remains_when_its_consumer_command_does_not_have_a_cwd.snap
index 3c00d46f..81f0a09f 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_remains_when_its_consumer_command_does_not_have_a_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_remains_when_its_consumer_command_does_not_have_a_cwd.snap
@@ -1,45 +1,52 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1270
+assertion_line: 1435
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "pwd",
- args: [],
- cwd: Some(
- "/tmp/bar",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "pwd",
+ args: [],
+ cwd: Some(
+ "/tmp/bar",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_is_overriden_by_its_consumers_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_is_overriden_by_its_consumers_cwd.snap
index b88f2a9e..ddcd1225 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_is_overriden_by_its_consumers_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_is_overriden_by_its_consumers_cwd.snap
@@ -1,45 +1,52 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1288
+assertion_line: 1453
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "pwd",
- args: [],
- cwd: Some(
- "/tmp/bar",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "pwd",
+ args: [],
+ cwd: Some(
+ "/tmp/bar",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_receives_its_consumers_bare_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_receives_its_consumers_bare_cwd.snap
index 3d561463..74318d3a 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_receives_its_consumers_bare_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_receives_its_consumers_bare_cwd.snap
@@ -1,45 +1,52 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1325
+assertion_line: 1490
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/tmp/bar",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/tmp/bar",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_cwd_overriden_by_its_consumers_bare_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_cwd_overriden_by_its_consumers_bare_cwd.snap
index 89332ea3..13492fea 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_cwd_overriden_by_its_consumers_bare_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_cwd_overriden_by_its_consumers_bare_cwd.snap
@@ -1,37 +1,44 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1343
+assertion_line: 1508
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Cwd(
- "/tmp/bar",
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Cwd(
+ "/tmp/bar",
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_with_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_with_cwd.snap
index 3797afc5..bb193e7c 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_with_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_with_cwd.snap
@@ -1,45 +1,52 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1377
+assertion_line: 1542
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/tmp/bar",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/tmp/bar",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_without_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_without_cwd.snap
index 072d0bc5..d28a7be1 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_without_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_without_cwd.snap
@@ -1,45 +1,52 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1359
+assertion_line: 1524
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- Command(
- RunCommand {
- command: "tail",
- args: [],
- cwd: Some(
- "/tmp/foo",
- ),
- hold_on_close: true,
- hold_on_start: false,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ Command(
+ RunCommand {
+ command: "tail",
+ args: [],
+ cwd: Some(
+ "/tmp/foo",
+ ),
+ hold_on_close: true,
+ hold_on_start: false,
+ },
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_edit.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_edit.snap
index a6aac1f1..34d0fb32 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_edit.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_edit.snap
@@ -1,38 +1,45 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1393
+assertion_line: 1558
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- EditFile(
- "/tmp/foo/bar",
- None,
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ EditFile(
+ "/tmp/foo/bar",
+ None,
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_command_propagated_to_its_consumer_edit.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_command_propagated_to_its_consumer_edit.snap
index e77e7b95..298be4e0 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_command_propagated_to_its_consumer_edit.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_command_propagated_to_its_consumer_edit.snap
@@ -1,38 +1,45 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1409
+assertion_line: 1574
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: Some(
- EditFile(
- "/tmp/foo/bar",
- None,
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: Some(
+ EditFile(
+ "/tmp/foo/bar",
+ None,
+ ),
),
- ),
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_given_to_panes_without_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_given_to_panes_without_cwd.snap
index 004238aa..718b0edb 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_given_to_panes_without_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_given_to_panes_without_cwd.snap
@@ -1,17 +1,17 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1506
+assertion_line: 1671
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -24,8 +24,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -46,6 +47,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -57,22 +59,29 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_prepended_to_panes_with_cwd.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_prepended_to_panes_with_cwd.snap
index 573e0465..1a205760 100644
--- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_prepended_to_panes_with_cwd.snap
+++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_prepended_to_panes_with_cwd.snap
@@ -1,17 +1,17 @@
---
source: zellij-utils/src/input/./unit/layout_test.rs
-assertion_line: 1521
+assertion_line: 1686
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [
(
None,
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -24,8 +24,9 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
children: [],
@@ -46,6 +47,7 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
],
split_size: None,
@@ -57,22 +59,29 @@ Layout {
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
[],
),
],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/kdl/kdl_layout_parser.rs b/zellij-utils/src/kdl/kdl_layout_parser.rs
index fad5fafe..7125d1fe 100644
--- a/zellij-utils/src/kdl/kdl_layout_parser.rs
+++ b/zellij-utils/src/kdl/kdl_layout_parser.rs
@@ -2,14 +2,15 @@ use crate::input::{
command::RunCommand,
config::ConfigError,
layout::{
- FloatingPanesLayout, Layout, PaneLayout, PercentOrFixed, Run, RunPlugin, RunPluginLocation,
- SplitDirection, SplitSize,
+ FloatingPaneLayout, Layout, LayoutConstraint, PercentOrFixed, Run, RunPlugin,
+ RunPluginLocation, SplitDirection, SplitSize, SwapFloatingLayout, SwapTiledLayout,
+ TiledPaneLayout,
},
};
use kdl::*;
-use std::collections::{HashMap, HashSet};
+use std::collections::{BTreeMap, HashMap, HashSet};
use std::str::FromStr;
use crate::{
@@ -28,17 +29,17 @@ use url::Url;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PaneOrFloatingPane {
- Pane(PaneLayout),
- FloatingPane(FloatingPanesLayout),
- Either(PaneLayout),
+ Pane(TiledPaneLayout),
+ FloatingPane(FloatingPaneLayout),
+ Either(TiledPaneLayout),
}
pub struct KdlLayoutParser<'a> {
global_cwd: Option<PathBuf>,
raw_layout: &'a str,
- tab_templates: HashMap<String, (PaneLayout, Vec<FloatingPanesLayout>, KdlNode)>,
+ tab_templates: HashMap<String, (TiledPaneLayout, Vec<FloatingPaneLayout>, KdlNode)>,
pane_templates: HashMap<String, (PaneOrFloatingPane, KdlNode)>,
- default_tab_template: Option<(PaneLayout, Vec<FloatingPanesLayout>, KdlNode)>,
+ default_tab_template: Option<(TiledPaneLayout, Vec<FloatingPaneLayout>, KdlNode)>,
}
impl<'a> KdlLayoutParser<'a> {
@@ -71,6 +72,8 @@ impl<'a> KdlLayoutParser<'a> {
|| word == "size"
|| word == "cwd"
|| word == "split_direction"
+ || word == "swap_tiled_layout"
+ || word == "swap_floating_layout"
}
fn is_a_valid_pane_property(&self, property_name: &str) -> bool {
property_name == "borderless"
@@ -110,6 +113,9 @@ impl<'a> KdlLayoutParser<'a> {
|| property_name == "split_direction"
|| property_name == "cwd"
|| property_name == "floating_panes"
+ || property_name == "children"
+ || property_name == "max_panes"
+ || property_name == "min_panes"
}
fn assert_legal_node_name(&self, name: &str, kdl_node: &KdlNode) -> Result<(), ConfigError> {
if name.contains(char::is_whitespace) {
@@ -402,7 +408,7 @@ impl<'a> KdlLayoutParser<'a> {
}
Ok(run)
}
- fn parse_pane_node(&self, kdl_node: &KdlNode) -> Result<PaneLayout, ConfigError> {
+ fn parse_pane_node(&self, kdl_node: &KdlNode) -> Result<TiledPaneLayout, ConfigError> {
self.assert_valid_pane_properties(kdl_node)?;
let borderless = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "borderless");
let focus = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus");
@@ -411,12 +417,13 @@ impl<'a> KdlLayoutParser<'a> {
let split_size = self.parse_split_size(kdl_node)?;
let run = self.parse_command_plugin_or_edit_block(kdl_node)?;
let children_split_direction = self.parse_split_direction(kdl_node)?;
- let (external_children_index, children) = match kdl_children_nodes!(kdl_node) {
- Some(children) => self.parse_child_pane_nodes_for_pane(&children)?,
- None => (None, vec![]),
- };
+ let (external_children_index, children_are_stacked, children) =
+ match kdl_children_nodes!(kdl_node) {
+ Some(children) => self.parse_child_pane_nodes_for_pane(&children)?,
+ None => (None, false, vec![]),
+ };
self.assert_no_mixed_children_and_properties(kdl_node)?;
- Ok(PaneLayout {
+ Ok(TiledPaneLayout {
borderless: borderless.unwrap_or_default(),
focus,
name,
@@ -425,13 +432,14 @@ impl<'a> KdlLayoutParser<'a> {
children_split_direction,
external_children_index,
children,
+ children_are_stacked,
..Default::default()
})
}
fn parse_floating_pane_node(
&self,
kdl_node: &KdlNode,
- ) -> Result<FloatingPanesLayout, ConfigError> {
+ ) -> Result<FloatingPaneLayout, ConfigError> {
self.assert_valid_floating_pane_properties(kdl_node)?;
let height = self.parse_percent_or_fixed(kdl_node, "height", false)?;
let width = self.parse_percent_or_fixed(kdl_node, "width", false)?;
@@ -442,7 +450,7 @@ impl<'a> KdlLayoutParser<'a> {
let name = kdl_get_string_property_or_child_value_with_error!(kdl_node, "name")
.map(|name| name.to_string());
self.assert_no_mixed_children_and_properties(kdl_node)?;
- Ok(FloatingPanesLayout {
+ Ok(FloatingPaneLayout {
name,
height,
width,
@@ -456,19 +464,21 @@ impl<'a> KdlLayoutParser<'a> {
fn insert_children_to_pane_template(
&self,
kdl_node: &KdlNode,
- pane_template: &mut PaneLayout,
+ pane_template: &mut TiledPaneLayout,
pane_template_kdl_node: &KdlNode,
) -> Result<(), ConfigError> {
let children_split_direction = self.parse_split_direction(kdl_node)?;
- let (external_children_index, pane_parts) = match kdl_children_nodes!(kdl_node) {
- Some(children) => self.parse_child_pane_nodes_for_pane(&children)?,
- None => (None, vec![]),
- };
+ let (external_children_index, children_are_stacked, pane_parts) =
+ match kdl_children_nodes!(kdl_node) {
+ Some(children) => self.parse_child_pane_nodes_for_pane(&children)?,
+ None => (None, false, vec![]),
+ };
if pane_parts.len() > 0 {
- let child_panes_layout = PaneLayout {
+ let child_panes_layout = TiledPaneLayout {
children_split_direction,
children: pane_parts,
external_children_index,
+ children_are_stacked,
..Default::default()
};
self.assert_one_children_block(&pane_template, pane_template_kdl_node)?;
@@ -480,12 +490,47 @@ impl<'a> KdlLayoutParser<'a> {
}
Ok(())
}
+ fn populate_external_children_index(
+ &self,
+ kdl_node: &KdlNode,
+ ) -> Result<Option<(usize, bool)>, ConfigError> {
+ // Option<(external_children_index, is_stacked)>
+ if let Some(pane_child_nodes) = kdl_children_nodes!(kdl_node) {
+ for (i, child) in pane_child_nodes.iter().enumerate() {
+ if kdl_name!(child) == "children" {
+ let stacked =
+ kdl_get_bool_property_or_child_value_with_error!(kdl_node, "stacked")
+ .unwrap_or(false);
+ if let Some(grand_children) = kdl_children_nodes!(child) {
+ let grand_children: Vec<&str> = grand_children
+ .iter()
+ .map(|g| kdl_name!(g))
+ .filter(|g| g != &"stacked")
+ .collect();
+ if !grand_children.is_empty() {
+ return Err(ConfigError::new_layout_kdl_error(
+ format!(
+ "Invalid `children` properties: {}",
+ grand_children.join(", ")
+ ),
+ child.span().offset(),
+ child.span().len(),
+ ));
+ }
+ }
+ return Ok(Some((i, stacked)));
+ }
+ }
+ }
+ return Ok(None);
+ }
fn parse_pane_node_with_template(
&self,
kdl_node: &KdlNode,
pane_template: PaneOrFloatingPane,
+ should_mark_external_children_index: bool,
pane_template_kdl_node: &KdlNode,
- ) -> Result<PaneLayout, ConfigError> {
+ ) -> Result<TiledPaneLayout, ConfigError> {
match pane_template {
PaneOrFloatingPane::Pane(mut pane_template)
| PaneOrFloatingPane::Either(mut pane_template) => {
@@ -501,6 +546,15 @@ impl<'a> KdlLayoutParser<'a> {
kdl_get_bool_property_or_child_value_with_error!(kdl_node, "start_suspended");
let split_size = self.parse_split_size(kdl_node)?;
let run = self.parse_command_plugin_or_edit_block_for_template(kdl_node)?;
+
+ // TODO: change should_insert_children to should_keep_pane_external_children_index
+ // or smth
+ let external_children_index_and_is_stacked = if should_mark_external_children_index
+ {
+ self.populate_external_children_index(kdl_node)?
+ } else {
+ None
+ };
self.assert_no_bare_attributes_in_pane_node_with_template(
&run,
&pane_template.run,
@@ -537,9 +591,13 @@ impl<'a> KdlLayoutParser<'a> {
if let Some(index_of_children) = pane_template.external_children_index {
pane_template
.children
- .insert(index_of_children, PaneLayout::default());
+ .insert(index_of_children, TiledPaneLayout::default());
}
- pane_template.external_children_index = None;
+ pane_template.external_children_index =
+ external_children_index_and_is_stacked.map(|(index, _is_stacked)| index);
+ pane_template.children_are_stacked = external_children_index_and_is_stacked
+ .map(|(_index, is_stacked)| is_stacked)
+ .unwrap_or(false);
Ok(pane_template)
},
PaneOrFloatingPane::FloatingPane(_) => {
@@ -561,7 +619,7 @@ impl<'a> KdlLayoutParser<'a> {
kdl_node: &KdlNode,
pane_template: PaneOrFloatingPane,
pane_template_kdl_node: &KdlNode,
- ) -> Result<FloatingPanesLayout, ConfigError> {
+ ) -> Result<FloatingPaneLayout, ConfigError> {
match pane_template {
PaneOrFloatingPane::Pane(_) => {
let pane_template_name = kdl_get_string_property_or_child_value_with_error!(
@@ -611,7 +669,7 @@ impl<'a> KdlLayoutParser<'a> {
let width = self.parse_percent_or_fixed(kdl_node, "width", false)?;
let x = self.parse_percent_or_fixed(kdl_node, "x", true)?;
let y = self.parse_percent_or_fixed(kdl_node, "y", true)?;
- // let mut floating_pane = FloatingPanesLayout::from(&pane_template);
+ // let mut floating_pane = FloatingPaneLayout::from(&pane_template);
if let Some(height) = height {
pane_template.height = Some(height);
}
@@ -662,7 +720,7 @@ impl<'a> KdlLayoutParser<'a> {
let width = self.parse_percent_or_fixed(kdl_node, "width", false)?;
let x = self.parse_percent_or_fixed(kdl_node, "x", true)?;
let y = self.parse_percent_or_fixed(kdl_node, "y", true)?;
- let mut floating_pane = FloatingPanesLayout::from(&pane_template);
+ let mut floating_pane = FloatingPaneLayout::from(&pane_template);
if let Some(height) = height {
floating_pane.height = Some(height);
}
@@ -812,7 +870,7 @@ impl<'a> KdlLayoutParser<'a> {
self.pane_templates.insert(
template_name,
(
- PaneOrFloatingPane::Either(PaneLayout {
+ PaneOrFloatingPane::Either(TiledPaneLayout {
focus,
run,
..Default::default()
@@ -830,7 +888,7 @@ impl<'a> KdlLayoutParser<'a> {
self.pane_templates.insert(
template_name,
(
- PaneOrFloatingPane::FloatingPane(FloatingPanesLayout {
+ PaneOrFloatingPane::FloatingPane(FloatingPaneLayout {
focus,
run,
height,
@@ -849,15 +907,16 @@ impl<'a> KdlLayoutParser<'a> {
kdl_get_bool_property_or_child_value_with_error!(kdl_node, "borderless");
let split_size = self.parse_split_size(kdl_node)?;
let children_split_direction = self.parse_split_direction(kdl_node)?;
- let (external_children_index, pane_parts) = match kdl_children_nodes!(kdl_node) {
- Some(children) => self.parse_child_pane_nodes_for_pane(&children)?,
- None => (None, vec![]),
- };
+ let (external_children_index, children_are_stacked, pane_parts) =
+ match kdl_children_nodes!(kdl_node) {
+ Some(children) => self.parse_child_pane_nodes_for_pane(&children)?,
+ None => (None, false, vec![]),
+ };
self.assert_no_mixed_children_and_properties(kdl_node)?;
self.pane_templates.insert(
template_name,
(
- PaneOrFloatingPane::Pane(PaneLayout {
+ PaneOrFloatingPane::Pane(TiledPaneLayout {
borderless: borderless.unwrap_or_default(),
focus,
split_size,
@@ -865,6 +924,7 @@ impl<'a> KdlLayoutParser<'a> {
children_split_direction,
external_children_index,
children: pane_parts,
+ children_are_stacked,
..Default::default()
}),
kdl_node.clone(),
@@ -877,8 +937,16 @@ impl<'a> KdlLayoutParser<'a> {
fn parse_tab_node(
&mut self,
kdl_node: &KdlNode,
- ) -> Result<(bool, Option<String>, PaneLayout, Vec<FloatingPanesLayout>), ConfigError> {
- // (is_focused, Option<tab_name>, PaneLayout, Vec<FloatingPanesLayout>)
+ ) -> Result<
+ (
+ bool,
+ Option<String>,
+ TiledPaneLayout,
+ Vec<FloatingPaneLayout>,
+ ),
+ ConfigError,
+ > {
+ // (is_focused, Option<tab_name>, PaneLayout, Vec<FloatingPaneLayout>)
self.assert_valid_tab_properties(kdl_node)?;
let tab_name =
kdl_get_string_property_or_child_value!(kdl_node, "name").map(|s| s.to_string());
@@ -889,11 +957,16 @@ impl<'a> KdlLayoutParser<'a> {
let mut child_floating_panes = vec![];
let children = match kdl_children_nodes!(kdl_node) {
Some(children) => {
- self.parse_child_pane_nodes_for_tab(children, &mut child_floating_panes)?
+ let should_mark_external_children_index = false;
+ self.parse_child_pane_nodes_for_tab(
+ children,
+ should_mark_external_children_index,
+ &mut child_floating_panes,
+ )?
},
None => vec![],
};
- let mut pane_layout = PaneLayout {
+ let mut pane_layout = TiledPaneLayout {
children_split_direction,
children,
..Default::default()
@@ -906,8 +979,9 @@ impl<'a> KdlLayoutParser<'a> {
fn parse_child_pane_nodes_for_tab(
&self,
children: &[KdlNode],
- child_floating_panes: &mut Vec<FloatingPanesLayout>,
- ) -> Result<Vec<PaneLayout>, ConfigError> {
+ should_mark_external_children_index: bool,
+ child_floating_panes: &mut Vec<FloatingPaneLayout>,
+ ) -> Result<Vec<TiledPaneLayout>, ConfigError> {
let mut nodes = vec![];
for child in children {
if kdl_name!(child) == "pane" {
@@ -918,6 +992,7 @@ impl<'a> KdlLayoutParser<'a> {
nodes.push(self.parse_pane_node_with_template(
child,
pane_template,
+ should_mark_external_children_index,
&pane_template_kdl_node,
)?);
} else if kdl_name!(child) == "floating_panes" {
@@ -937,37 +1012,51 @@ impl<'a> KdlLayoutParser<'a> {
}
}
if nodes.is_empty() {
- nodes.push(PaneLayout::default());
+ nodes.push(TiledPaneLayout::default());
}
Ok(nodes)
}
fn parse_child_pane_nodes_for_pane(
&self,
children: &[KdlNode],
- ) -> Result<(Option<usize>, Vec<PaneLayout>), ConfigError> {
- // usize is external_children_index
+ ) -> Result<(Option<usize>, bool, Vec<TiledPaneLayout>), ConfigError> {
+ // usize is external_children_index, bool is "children_are_stacked"
let mut external_children_index = None;
+ let mut children_are_stacked = false;
let mut nodes = vec![];
for (i, child) in children.iter().enumerate() {
if kdl_name!(child) == "pane" {
nodes.push(self.parse_pane_node(child)?);
} else if kdl_name!(child) == "children" {
- let node_has_child_nodes = child.children().map(|c| !c.is_empty()).unwrap_or(false);
- let node_has_entries = !child.entries().is_empty();
- if node_has_child_nodes || node_has_entries {
- return Err(ConfigError::new_layout_kdl_error(
- format!("The `children` node must be bare. All properties should be places on the node consuming this template."),
- child.span().offset(),
- child.span().len(),
- ));
+ let stacked = kdl_get_bool_property_or_child_value_with_error!(child, "stacked")
+ .unwrap_or(false);
+ if let Some(grand_children) = kdl_children_nodes!(child) {
+ let grand_children: Vec<&str> = grand_children
+ .iter()
+ .map(|g| kdl_name!(g))
+ .filter(|g| g != &"stacked")
+ .collect();
+ if !grand_children.is_empty() {
+ return Err(ConfigError::new_layout_kdl_error(
+ format!(
+ "Invalid `children` properties: {}",
+ grand_children.join(", ")
+ ),
+ child.span().offset(),
+ child.span().len(),
+ ));
+ }
}
external_children_index = Some(i);
+ children_are_stacked = stacked;
} else if let Some((pane_template, pane_template_kdl_node)) =
self.pane_templates.get(kdl_name!(child)).cloned()
{
+ let should_mark_external_children_index = false;
nodes.push(self.parse_pane_node_with_template(
child,
pane_template,
+ should_mark_external_children_index,
&pane_template_kdl_node,
)?);
} else if !self.is_a_valid_pane_property(kdl_name!(child)) {
@@ -978,7 +1067,7 @@ impl<'a> KdlLayoutParser<'a> {
));
}
}
- Ok((external_children_index, nodes))
+ Ok((external_children_index, children_are_stacked, nodes))
}
fn has_child_nodes(&self, kdl_node: &KdlNode) -> bool {
if let Some(children) = kdl_children_nodes!(kdl_node) {
@@ -1076,7 +1165,7 @@ impl<'a> KdlLayoutParser<'a> {
}
fn assert_one_children_block(
&self,
- layout: &PaneLayout,
+ layout: &TiledPaneLayout,
kdl_node: &KdlNode,
) -> Result<(), ConfigError> {
let children_block_count = layout.children_block_count();
@@ -1193,8 +1282,6 @@ impl<'a> KdlLayoutParser<'a> {
) -> Result<(), ConfigError> {
let has_borderless_prop =
kdl_get_bool_property_or_child_value_with_error!(kdl_node, "borderless").is_some();
- let has_focus_prop =
- kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus").is_some();
let has_cwd_prop =
kdl_get_string_property_or_child_value_with_error!(kdl_node, "cwd").is_some();
let has_non_cwd_run_prop = self
@@ -1206,15 +1293,12 @@ impl<'a> KdlLayoutParser<'a> {
.unwrap_or(false);
let has_nested_nodes_or_children_block = self.has_child_panes_tabs_or_templates(kdl_node);
if has_nested_nodes_or_children_block
- && (has_borderless_prop || has_focus_prop || has_non_cwd_run_prop || has_cwd_prop)
+ && (has_borderless_prop || has_non_cwd_run_prop || has_cwd_prop)
{
let mut offending_nodes = vec![];
if has_borderless_prop {
offending_nodes.push("borderless");
}
- if has_focus_prop {
- offending_nodes.push("focus");
- }
if has_non_cwd_run_prop {
offending_nodes.push("command/edit/plugin");
}
@@ -1235,8 +1319,8 @@ impl<'a> KdlLayoutParser<'a> {
}
fn insert_layout_children_or_error(
&self,
- layout: &mut PaneLayout,
- mut child_panes_layout: PaneLayout,
+ layout: &mut TiledPaneLayout,
+ mut child_panes_layout: TiledPaneLayout,
kdl_node: &KdlNode,
) -> Result<(), ConfigError> {
let successfully_inserted = layout.insert_children_layout(&mut child_panes_layout)?;
@@ -1253,11 +1337,20 @@ impl<'a> KdlLayoutParser<'a> {
fn parse_tab_node_with_template(
&self,
kdl_node: &KdlNode,
- mut tab_layout: PaneLayout,
- mut tab_template_floating_panes: Vec<FloatingPanesLayout>,
+ mut tab_layout: TiledPaneLayout,
+ mut tab_template_floating_panes: Vec<FloatingPaneLayout>,
+ should_mark_external_children_index: bool,
tab_layout_kdl_node: &KdlNode,
- ) -> Result<(bool, Option<String>, PaneLayout, Vec<FloatingPanesLayout>), ConfigError> {
- // (is_focused, Option<tab_name>, PaneLayout, Vec<FloatingPanesLayout>)
+ ) -> Result<
+ (
+ bool,
+ Option<String>,
+ TiledPaneLayout,
+ Vec<FloatingPaneLayout>,
+ ),
+ ConfigError,
+ > {
+ // (is_focused, Option<tab_name>, PaneLayout, Vec<FloatingPaneLayout>)
let tab_name =
kdl_get_string_property_or_child_value!(kdl_node, "name").map(|s| s.to_string());
let tab_cwd =
@@ -1266,9 +1359,12 @@ impl<'a> KdlLayoutParser<'a> {
let children_split_direction = self.parse_split_direction(kdl_node)?;
match kdl_children_nodes!(kdl_node) {
Some(children) => {
- let child_panes = self
- .parse_child_pane_nodes_for_tab(children, &mut tab_template_floating_panes)?;
- let child_panes_layout = PaneLayout {
+ let child_panes = self.parse_child_pane_nodes_for_tab(
+ children,
+ should_mark_external_children_index,
+ &mut tab_template_floating_panes,
+ )?;
+ let child_panes_layout = TiledPaneLayout {
children_split_direction,
children: child_panes,
..Default::default()
@@ -1284,7 +1380,7 @@ impl<'a> KdlLayoutParser<'a> {
if let Some(index_of_children) = tab_layout.external_children_index {
tab_layout
.children
- .insert(index_of_children, PaneLayout::default());
+ .insert(index_of_children, TiledPaneLayout::default());
}
},
}
@@ -1342,7 +1438,7 @@ impl<'a> KdlLayoutParser<'a> {
fn parse_tab_template_node(
&self,
kdl_node: &KdlNode,
- ) -> Result<(PaneLayout, Vec<FloatingPanesLayout>), ConfigError> {
+ ) -> Result<(TiledPaneLayout, Vec<FloatingPaneLayout>), ConfigError> {
self.assert_valid_tab_properties(kdl_node)?;
let children_split_direction = self.parse_split_direction(kdl_node)?;
let mut tab_children = vec![];
@@ -1368,9 +1464,11 @@ impl<'a> KdlLayoutParser<'a> {
} else if let Some((pane_template, pane_template_kdl_node)) =
self.pane_templates.get(kdl_name!(child)).cloned()
{
+ let should_mark_external_children_index = false;
tab_children.push(self.parse_pane_node_with_template(
child,
pane_template,
+ should_mark_external_children_index,
&pane_template_kdl_node,
)?);
} else if kdl_name!(child) == "floating_panes" {
@@ -1392,7 +1490,7 @@ impl<'a> KdlLayoutParser<'a> {
}
}
Ok((
- PaneLayout {
+ TiledPaneLayout {
children_split_direction,
children: tab_children,
external_children_index,
@@ -1401,14 +1499,14 @@ impl<'a> KdlLayoutParser<'a> {
tab_floating_children,
))
}
- fn default_template(&self) -> Result<Option<PaneLayout>, ConfigError> {
+ fn default_template(&self) -> Result<Option<TiledPaneLayout>, ConfigError> {
match &self.default_tab_template {
Some((template, _template_floating_panes, _kdl_node)) => {
let mut template = template.clone();
if let Some(children_index) = template.external_children_index {
template
.children
- .insert(children_index, PaneLayout::default())
+ .insert(children_index, TiledPaneLayout::default())
}
template.external_children_index = None;
Ok(Some(template))
@@ -1545,28 +1643,230 @@ impl<'a> KdlLayoutParser<'a> {
}
Ok(())
}
+ fn populate_swap_tiled_layouts(
+ &mut self,
+ layout_children: &[KdlNode],
+ swap_tiled_layouts: &mut Vec<SwapTiledLayout>,
+ ) -> Result<(), ConfigError> {
+ for child in layout_children.iter() {
+ let child_name = kdl_name!(child);
+ if child_name == "swap_tiled_layout" {
+ let swap_layout_name =
+ kdl_get_string_property_or_child_value!(child, "name").map(|n| String::from(n));
+ if let Some(swap_tiled_layout_group) = kdl_children_nodes!(child) {
+ let mut swap_tiled_layout = BTreeMap::new();
+ for layout in swap_tiled_layout_group {
+ let layout_node_name = kdl_name!(layout);
+ if layout_node_name == "tab" {
+ let layout_constraint = self.parse_constraint(layout)?;
+
+ match &self.default_tab_template {
+ Some((
+ default_tab_template,
+ _default_tab_template_floating_panes,
+ default_tab_template_kdl_node,
+ )) => {
+ let default_tab_template = default_tab_template.clone();
+ let layout = self
+ .populate_one_swap_tiled_layout_with_template(
+ layout,
+ default_tab_template,
+ default_tab_template_kdl_node.clone(),
+ )?;
+ swap_tiled_layout.insert(layout_constraint, layout);
+ },
+ None => {
+ let layout = self.populate_one_swap_tiled_layout(layout)?;
+ swap_tiled_layout.insert(layout_constraint, layout);
+ },
+ }
+ } else if let Some((
+ tab_template,
+ _tab_template_floating_panes,
+ tab_template_kdl_node,
+ )) = self.tab_templates.get(layout_node_name).cloned()
+ {
+ let layout_constraint = self.parse_constraint(layout)?;
+ let layout = self.populate_one_swap_tiled_layout_with_template(
+ layout,
+ tab_template,
+ tab_template_kdl_node,
+ )?;
+ swap_tiled_layout.insert(layout_constraint, layout);
+ }
+ }
+ swap_tiled_layouts.push((swap_tiled_layout, swap_layout_name));
+ }
+ }
+ }
+ Ok(())
+ }
+ fn populate_swap_floating_layouts(
+ &mut self,
+ layout_children: &[KdlNode],
+ swap_floating_layouts: &mut Vec<SwapFloatingLayout>,
+ ) -> Result<(), ConfigError> {
+ for child in layout_children.iter() {
+ let child_name = kdl_name!(child);
+ if child_name == "swap_floating_layout" {
+ let swap_layout_name =
+ kdl_get_string_property_or_child_value!(child, "name").map(|n| String::from(n));
+ if let Some(swap_floating_layout_group) = kdl_children_nodes!(child) {
+ let mut swap_floating_layout = BTreeMap::new();
+ for layout in swap_floating_layout_group {
+ let layout_node_name = kdl_name!(layout);
+ if layout_node_name == "floating_panes" {
+ let layout_constraint = self.parse_constraint(layout)?;
+ let layout = self.populate_one_swap_floating_layout(layout)?;
+ swap_floating_layout.insert(layout_constraint, layout);
+ } else if let Some((
+ tab_template,
+ tab_template_floating_panes,
+ tab_template_kdl_node,
+ )) = self.tab_templates.get(layout_node_name).cloned()
+ {
+ let layout_constraint = self.parse_constraint(layout)?;
+ let layout = self.populate_one_swap_floating_layout_with_template(
+ layout,
+ tab_template,
+ tab_template_floating_panes,
+ tab_template_kdl_node,
+ )?;
+ swap_floating_layout.insert(layout_constraint, layout);
+ }
+ }
+ swap_floating_layouts.push((swap_floating_layout, swap_layout_name));
+ }
+ }
+ }
+ Ok(())
+ }
+ fn parse_constraint(&mut self, layout_node: &KdlNode) -> Result<LayoutConstraint, ConfigError> {
+ if let Some(max_panes) = kdl_get_string_property_or_child_value!(layout_node, "max_panes") {
+ return Err(kdl_parsing_error!(
+ format!(
+ "max_panes should be a fixed number (eg. 1) and not a quoted string (\"{}\")",
+ max_panes
+ ),
+ layout_node
+ ));
+ };
+ if let Some(min_panes) = kdl_get_string_property_or_child_value!(layout_node, "min_panes") {
+ return Err(kdl_parsing_error!(
+ format!(
+ "min_panes should be a fixed number (eg. 1) and not a quoted string (\"{}\")",
+ min_panes
+ ),
+ layout_node
+ ));
+ };
+ let max_panes = kdl_get_int_property_or_child_value!(layout_node, "max_panes");
+ let min_panes = kdl_get_int_property_or_child_value!(layout_node, "min_panes");
+ match (min_panes, max_panes) {
+ (Some(_min_panes), Some(_max_panes)) => Err(kdl_parsing_error!(
+ format!("cannot have more than one constraint (eg. max_panes + min_panes)'"),
+ layout_node
+ )),
+ (Some(min_panes), None) => Ok(LayoutConstraint::MinPanes(min_panes as usize)),
+ (None, Some(max_panes)) => Ok(LayoutConstraint::MaxPanes(max_panes as usize)),
+ _ => Ok(LayoutConstraint::NoConstraint),
+ }
+ }
+ fn populate_one_swap_tiled_layout(
+ &self,
+ layout_node: &KdlNode,
+ ) -> Result<TiledPaneLayout, ConfigError> {
+ self.assert_valid_tab_properties(layout_node)?;
+ let children_split_direction = self.parse_split_direction(layout_node)?;
+ let mut child_floating_panes = vec![];
+ let children = match kdl_children_nodes!(layout_node) {
+ Some(children) => {
+ let should_mark_external_children_index = true;
+ self.parse_child_pane_nodes_for_tab(
+ children,
+ should_mark_external_children_index,
+ &mut child_floating_panes,
+ )?
+ },
+ None => vec![],
+ };
+ let pane_layout = TiledPaneLayout {
+ children_split_direction,
+ children,
+ ..Default::default()
+ };
+ Ok(pane_layout)
+ }
+ fn populate_one_swap_tiled_layout_with_template(
+ &self,
+ layout_node: &KdlNode,
+ tab_template: TiledPaneLayout,
+ tab_template_kdl_node: KdlNode,
+ ) -> Result<TiledPaneLayout, ConfigError> {
+ let should_mark_external_children_index = true;
+ let layout = self.parse_tab_node_with_template(
+ layout_node,
+ tab_template,
+ vec![], // no floating_panes in swap tiled node
+ should_mark_external_children_index,
+ &tab_template_kdl_node,
+ )?;
+ Ok(layout.2)
+ }
+ fn populate_one_swap_floating_layout(
+ &self,
+ layout_node: &KdlNode,
+ ) -> Result<Vec<FloatingPaneLayout>, ConfigError> {
+ let mut floating_panes = vec![];
+ self.assert_valid_tab_properties(layout_node)?;
+ self.populate_floating_pane_children(layout_node, &mut floating_panes)?;
+ Ok(floating_panes)
+ }
+ fn populate_one_swap_floating_layout_with_template(
+ &self,
+ layout_node: &KdlNode,
+ tab_template: TiledPaneLayout,
+ tab_template_floating_panes: Vec<FloatingPaneLayout>,
+ tab_template_kdl_node: KdlNode,
+ ) -> Result<Vec<FloatingPaneLayout>, ConfigError> {
+ let should_mark_external_children_index = false;
+ let layout = self.parse_tab_node_with_template(
+ layout_node,
+ tab_template,
+ tab_template_floating_panes,
+ should_mark_external_children_index,
+ &tab_template_kdl_node,
+ )?;
+ Ok(layout.3)
+ }
fn layout_with_tabs(
&self,
- tabs: Vec<(Option<String>, PaneLayout, Vec<FloatingPanesLayout>)>,
+ tabs: Vec<(Option<String>, TiledPaneLayout, Vec<FloatingPaneLayout>)>,
focused_tab_index: Option<usize>,
+ swap_tiled_layouts: Vec<SwapTiledLayout>,
+ swap_floating_layouts: Vec<SwapFloatingLayout>,
) -> Result<Layout, ConfigError> {
let template = self
.default_template()?
- .unwrap_or_else(|| PaneLayout::default());
+ .unwrap_or_else(|| TiledPaneLayout::default());
Ok(Layout {
tabs: tabs,
- template: Some(template),
+ template: Some((template, vec![])),
focused_tab_index,
+ swap_tiled_layouts,
+ swap_floating_layouts,
..Default::default()
})
}
fn layout_with_one_tab(
&self,
- panes: Vec<PaneLayout>,
- floating_panes: Vec<FloatingPanesLayout>,
+ panes: Vec<TiledPaneLayout>,
+ floating_panes: Vec<FloatingPaneLayout>,
+ swap_tiled_layouts: Vec<SwapTiledLayout>,
+ swap_floating_layouts: Vec<SwapFloatingLayout>,
) -> Result<Layout, ConfigError> {
- let main_tab_layout = PaneLayout {
+ let main_tab_layout = TiledPaneLayout {
children: panes,
..Default::default()
};
@@ -1582,30 +1882,39 @@ impl<'a> KdlLayoutParser<'a> {
// create a layout with one tab that has these child panes
Ok(Layout {
tabs,
- template: Some(template),
- floating_panes_template: floating_panes,
+ template: Some((template, floating_panes)),
+ swap_tiled_layouts,
+ swap_floating_layouts,
..Default::default()
})
}
fn layout_with_one_pane(
&self,
- child_floating_panes: Vec<FloatingPanesLayout>,
+ child_floating_panes: Vec<FloatingPaneLayout>,
+ swap_tiled_layouts: Vec<SwapTiledLayout>,
+ swap_floating_layouts: Vec<SwapFloatingLayout>,
) -> Result<Layout, ConfigError> {
let template = self
.default_template()?
- .unwrap_or_else(|| PaneLayout::default());
+ .unwrap_or_else(|| TiledPaneLayout::default());
Ok(Layout {
- template: Some(template),
- floating_panes_template: child_floating_panes,
+ template: Some((template, child_floating_panes)),
+ swap_tiled_layouts,
+ swap_floating_layouts,
..Default::default()
})
}
fn populate_layout_child(
&mut self,
child: &KdlNode,
- child_tabs: &mut Vec<(bool, Option<String>, PaneLayout, Vec<FloatingPanesLayout>)>,
- child_panes: &mut Vec<PaneLayout>,
- child_floating_panes: &mut Vec<FloatingPanesLayout>,
+ child_tabs: &mut Vec<(
+ bool,
+ Option<String>,
+ TiledPaneLayout,
+ Vec<FloatingPaneLayout>,
+ )>,
+ child_panes: &mut Vec<TiledPaneLayout>,
+ child_floating_panes: &mut Vec<FloatingPaneLayout>,
) -> Result<(), ConfigError> {
let child_name = kdl_name!(child);
if (child_name == "pane" || child_name == "floating_panes") && !child_tabs.is_empty() {
@@ -1638,10 +1947,12 @@ impl<'a> KdlLayoutParser<'a> {
default_tab_template_kdl_node,
)) => {
let default_tab_template = default_tab_template.clone();
+ let should_mark_external_children_index = false;
child_tabs.push(self.parse_tab_node_with_template(
child,
default_tab_template,
default_tab_template_floating_panes.clone(),
+ should_mark_external_children_index,
default_tab_template_kdl_node,
)?);
},
@@ -1659,10 +1970,12 @@ impl<'a> KdlLayoutParser<'a> {
child.span().len(),
));
}
+ let should_mark_external_children_index = false;
child_tabs.push(self.parse_tab_node_with_template(
child,
tab_template,
tab_template_floating_panes,
+ should_mark_external_children_index,
&tab_template_kdl_node,
)?);
} else if let Some((pane_template, pane_template_kdl_node)) =
@@ -1675,8 +1988,13 @@ impl<'a> KdlLayoutParser<'a> {
child.span().len(),
));
}
- let mut pane_template =
- self.parse_pane_node_with_template(child, pane_template, &pane_template_kdl_node)?;
+ let should_mark_external_children_index = false;
+ let mut pane_template = self.parse_pane_node_with_template(
+ child,
+ pane_template,
+ should_mark_external_children_index,
+ &pane_template_kdl_node,
+ )?;
if let Some(cwd_prefix) = &self.cwd_prefix(None)? {
pane_template.add_cwd_to_layout(&cwd_prefix);
}
@@ -1693,7 +2011,7 @@ impl<'a> KdlLayoutParser<'a> {
fn populate_floating_pane_children(
&self,
child: &KdlNode,
- child_floating_panes: &mut Vec<FloatingPanesLayout>,
+ child_floating_panes: &mut Vec<FloatingPaneLayout>,
) -> Result<(), ConfigError> {
if let Some(children) = kdl_children_nodes!(child) {
for child in children {
@@ -1713,7 +2031,6 @@ impl<'a> KdlLayoutParser<'a> {
)?;
child_floating_panes.push(pane_node);
} else {
- // TODO: invalid node name
return Err(ConfigError::new_layout_kdl_error(
format!(
"floating_panes can only contain pane nodes, found: {}",
@@ -1727,6 +2044,54 @@ impl<'a> KdlLayoutParser<'a> {
};
Ok(())
}
+ pub fn parse_external_swap_layouts(
+ &mut self,
+ raw_swap_layouts: &str,
+ mut existing_layout: Layout,
+ ) -> Result<Layout, ConfigError> {
+ let kdl_swap_layout: KdlDocument = raw_swap_layouts.parse()?;
+ let mut swap_tiled_layouts = vec![];
+ let mut swap_floating_layouts = vec![];
+
+ for node in kdl_swap_layout.nodes() {
+ let node_name = kdl_name!(node);
+ if node_name == "swap_floating_layout"
+ || node_name == "swap_tiled_layout"
+ || node_name == "tab_template"
+ || node_name == "pane_template"
+ {
+ continue;
+ } else if node_name == "layout" {
+ return Err(ConfigError::new_layout_kdl_error(
+ "Swap layouts should not have their own layout node".into(),
+ node.span().offset(),
+ node.span().len(),
+ ))?;
+ } else if self.is_a_reserved_word(node_name) {
+ return Err(ConfigError::new_layout_kdl_error(
+ format!(
+ "Swap layouts should not contain bare nodes of type: {}",
+ node_name
+ ),
+ node.span().offset(),
+ node.span().len(),
+ ))?;
+ }
+ }
+
+ self.populate_pane_templates(kdl_swap_layout.nodes(), &kdl_swap_layout)?;
+ self.populate_tab_templates(kdl_swap_layout.nodes())?;
+ self.populate_swap_tiled_layouts(kdl_swap_layout.nodes(), &mut swap_tiled_layouts)?;
+ self.populate_swap_floating_layouts(kdl_swap_layout.nodes(), &mut swap_floating_layouts)?;
+
+ existing_layout
+ .swap_tiled_layouts
+ .append(&mut swap_tiled_layouts);
+ existing_layout
+ .swap_floating_layouts
+ .append(&mut swap_floating_layouts);
+ Ok(existing_layout)
+ }
pub fn parse(&mut self) -> Result<Layout, ConfigError> {
let kdl_layout: KdlDocument = self.raw_layout.parse()?;
let layout_node = kdl_layout
@@ -1754,10 +2119,14 @@ impl<'a> KdlLayoutParser<'a> {
let mut child_tabs = vec![];
let mut child_panes = vec![];
let mut child_floating_panes = vec![];
+ let mut swap_tiled_layouts = vec![];
+ let mut swap_floating_layouts = vec![];
if let Some(children) = kdl_children_nodes!(layout_node) {
self.populate_global_cwd(layout_node)?;
self.populate_pane_templates(children, &kdl_layout)?;
self.populate_tab_templates(children)?;
+ self.populate_swap_tiled_layouts(children, &mut swap_tiled_layouts)?;
+ self.populate_swap_floating_layouts(children, &mut swap_floating_layouts)?;
for child in children {
self.populate_layout_child(
child,
@@ -1783,7 +2152,7 @@ impl<'a> KdlLayoutParser<'a> {
let focused_tab_index = child_tabs
.iter()
.position(|(is_focused, _, _, _)| *is_focused);
- let child_tabs: Vec<(Option<String>, PaneLayout, Vec<FloatingPanesLayout>)> =
+ let child_tabs: Vec<(Option<String>, TiledPaneLayout, Vec<FloatingPaneLayout>)> =
child_tabs
.drain(..)
.map(
@@ -1792,11 +2161,25 @@ impl<'a> KdlLayoutParser<'a> {
},
)
.collect();
- self.layout_with_tabs(child_tabs, focused_tab_index)
+ self.layout_with_tabs(
+ child_tabs,
+ focused_tab_index,
+ swap_tiled_layouts,
+ swap_floating_layouts,
+ )
} else if !child_panes.is_empty() {
- self.layout_with_one_tab(child_panes, child_floating_panes)
+ self.layout_with_one_tab(
+ child_panes,
+ child_floating_panes,
+ swap_tiled_layouts,
+ swap_floating_layouts,
+ )
} else {
- self.layout_with_one_pane(child_floating_panes)
+ self.layout_with_one_pane(
+ child_floating_panes,
+ swap_tiled_layouts,
+ swap_floating_layouts,
+ )
}
}
}
diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs
index f7a6ac4d..f3c7d9fb 100644
--- a/zellij-utils/src/kdl/mod.rs
+++ b/zellij-utils/src/kdl/mod.rs
@@ -66,6 +66,8 @@ macro_rules! parse_kdl_action_arguments {
"Confirm" => Ok(Action::Confirm),
"Deny" => Ok(Action::Deny),
"ToggleMouseMode" => Ok(Action::ToggleMouseMode),
+ "PreviousSwapLayout" => Ok(Action::PreviousSwapLayout),
+ "NextSwapLayout" => Ok(Action::NextSwapLayout),
_ => Err(ConfigError::new_kdl_error(
format!("Unsupported action: {:?}", $action_name),
$action_node.span().offset(),
@@ -452,6 +454,7 @@ impl Action {
Ok(Action::MovePane(Some(direction)))
}
},
+ "MovePaneBackwards" => Ok(Action::MovePaneBackwards),
"DumpScreen" => Ok(Action::DumpScreen(string, false)),
"NewPane" => {
if string.is_empty() {
@@ -729,6 +732,11 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
action_arguments,
kdl_action
),
+ "MovePaneBackwards" => parse_kdl_action_char_or_string_arguments!(
+ action_name,
+ action_arguments,
+ kdl_action
+ ),
"DumpScreen" => parse_kdl_action_char_or_string_arguments!(
action_name,
action_arguments,
@@ -745,7 +753,7 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
"NewTab" => {
let command_metadata = action_children.iter().next();
if command_metadata.is_none() {
- return Ok(Action::NewTab(None, vec![], None));
+ return Ok(Action::NewTab(None, vec![], None, None, None));
}
let current_dir = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
@@ -762,7 +770,7 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
.and_then(|c_m| kdl_child_string_value_for_entry(c_m, "name"))
.map(|name_string| name_string.to_string());
- let (path_to_raw_layout, raw_layout) =
+ let (path_to_raw_layout, raw_layout, swap_layouts) =
Layout::stringified_from_path_or_default(layout.as_ref(), None).map_err(
|e| {
ConfigError::new_kdl_error(
@@ -773,14 +781,19 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
},
)?;
- let layout =
- Layout::from_str(&raw_layout, path_to_raw_layout, cwd).map_err(|e| {
- ConfigError::new_kdl_error(
- format!("Failed to load layout: {}", e),
- kdl_action.span().offset(),
- kdl_action.span().len(),
- )
- })?;
+ let layout = Layout::from_str(
+ &raw_layout,
+ path_to_raw_layout,
+ swap_layouts.as_ref().map(|(f, p)| (f.as_str(), p.as_str())),
+ cwd,
+ )
+ .map_err(|e| {
+ ConfigError::new_kdl_error(
+ format!("Failed to load layout: {}", e),
+ kdl_action.span().offset(),
+ kdl_action.span().len(),
+ )
+ })?;
let mut tabs = layout.tabs();
if tabs.len() > 1 {
@@ -793,11 +806,23 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
let (tab_name, layout, floating_panes_layout) = tabs.drain(..).next().unwrap();
let name = tab_name.or(name);
- Ok(Action::NewTab(Some(layout), floating_panes_layout, name))
+ Ok(Action::NewTab(
+ Some(layout),
+ floating_panes_layout,
+ None,
+ None,
+ name,
+ ))
} else {
let (layout, floating_panes_layout) = layout.new_tab();
- Ok(Action::NewTab(Some(layout), floating_panes_layout, name))
+ Ok(Action::NewTab(
+ Some(layout),
+ floating_panes_layout,
+ None,
+ None,
+ name,
+ ))
}
},
"GoToTab" => parse_kdl_action_u8_arguments!(action_name, action_arguments, kdl_action),
@@ -847,6 +872,8 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
};
Ok(Action::Run(run_command_action))
},
+ "PreviousSwapLayout" => Ok(Action::PreviousSwapLayout),
+ "NextSwapLayout" => Ok(Action::NextSwapLayout),
_ => Err(ConfigError::new_kdl_error(
format!("Unsupported action: {}", action_name).into(),
kdl_action.span().offset(),
@@ -1273,6 +1300,8 @@ impl Options {
.map(|(string, _entry)| PathBuf::from(string));
let pane_frames =
kdl_property_first_arg_as_bool_or_error!(kdl_options, "pane_frames").map(|(v, _)| v);
+ let auto_layout =
+ kdl_property_first_arg_as_bool_or_error!(kdl_options, "auto_layout").map(|(v, _)| v);
let theme = kdl_property_first_arg_as_string_or_error!(kdl_options, "theme")
.map(|(theme, _entry)| theme.to_string());
let default_mode =
@@ -1337,6 +1366,7 @@ impl Options {
scrollback_editor,
session_name,
attach_to_session,
+ auto_layout,
})
}
}
@@ -1370,36 +1400,66 @@ impl Layout {
pub fn from_kdl(
raw_layout: &str,
file_name: String,
+ raw_swap_layouts: Option<(&str, &str)>, // raw_swap_layouts swap_layouts_file_name
cwd: Option<PathBuf>,
) -> Result<Self, ConfigError> {
- KdlLayoutParser::new(raw_layout, cwd).parse().map_err(|e| {
- match e {
- ConfigError::KdlError(kdl_error) => ConfigError::KdlError(kdl_error.add_src(file_name, String::from(raw_layout))),
- ConfigError::KdlDeserializationError(kdl_error) => {
- let error_message = match kdl_error.kind {
- kdl::KdlErrorKind::Context("valid node terminator") => {
- format!("Failed to deserialize KDL node. \nPossible reasons:\n{}\n{}\n{}\n{}",
- "- Missing `;` after a node name, eg. { node; another_node; }",
- "- Missing quotations (\") around an argument node eg. { first_node \"argument_node\"; }",
- "- Missing an equal sign (=) between node arguments on a title line. eg. argument=\"value\"",
- "- Found an extraneous equal sign (=) between node child arguments and their values. eg. { argument=\"value\" }")
+ let mut kdl_layout_parser = KdlLayoutParser::new(raw_layout, cwd);
+ let layout = kdl_layout_parser.parse().map_err(|e| match e {
+ ConfigError::KdlError(kdl_error) => {
+ ConfigError::KdlError(kdl_error.add_src(file_name, String::from(raw_layout)))
+ },
+ ConfigError::KdlDeserializationError(kdl_error) => {
+ kdl_layout_error(kdl_error, file_name, raw_layout)
+ },
+ e => e,
+ })?;
+ match raw_swap_layouts {
+ Some((raw_swap_layout_filename, raw_swap_layout)) => {
+ // here we use the same parser to parse the swap layout so that we can reuse assets
+ // (eg. pane and tab templates)
+ kdl_layout_parser
+ .parse_external_swap_layouts(raw_swap_layout, layout)
+ .map_err(|e| match e {
+ ConfigError::KdlError(kdl_error) => {
+ ConfigError::KdlError(kdl_error.add_src(
+ String::from(raw_swap_layout_filename),
+ String::from(raw_swap_layout),
+ ))
},
- _ => String::from(kdl_error.help.unwrap_or("Kdl Deserialization Error")),
- };
- let kdl_error = KdlError {
- error_message,
- src: Some(NamedSource::new(file_name, String::from(raw_layout))),
- offset: Some(kdl_error.span.offset()),
- len: Some(kdl_error.span.len()),
- help_message: None,
- };
- ConfigError::KdlError(kdl_error)
- },
- e => e
- }
- })
+ ConfigError::KdlDeserializationError(kdl_error) => kdl_layout_error(
+ kdl_error,
+ raw_swap_layout_filename.into(),
+ raw_swap_layout,
+ ),
+ e => e,
+ })
+ },
+ None => Ok(layout),
+ }
}
}
+
+fn kdl_layout_error(kdl_error: kdl::KdlError, file_name: String, raw_layout: &str) -> ConfigError {
+ let error_message = match kdl_error.kind {
+ kdl::KdlErrorKind::Context("valid node terminator") => {
+ format!("Failed to deserialize KDL node. \nPossible reasons:\n{}\n{}\n{}\n{}",
+ "- Missing `;` after a node name, eg. { node; another_node; }",
+ "- Missing quotations (\") around an argument node eg. { first_node \"argument_node\"; }",
+ "- Missing an equal sign (=) between node arguments on a title line. eg. argument=\"value\"",
+ "- Found an extraneous equal sign (=) between node child arguments and their values. eg. { argument=\"value\" }")
+ },
+ _ => String::from(kdl_error.help.unwrap_or("Kdl Deserialization Error")),
+ };
+ let kdl_error = KdlError {
+ error_message,
+ src: Some(NamedSource::new(file_name, String::from(raw_layout))),
+ offset: Some(kdl_error.span.offset()),
+ len: Some(kdl_error.span.len()),
+ help_message: None,
+ };
+ ConfigError::KdlError(kdl_error)
+}
+
impl EnvironmentVariables {
pub fn from_kdl(kdl_env_variables: &KdlNode) -> Result<Self, ConfigError> {
let mut env: HashMap<String, String> = HashMap::new();
diff --git a/zellij-utils/src/pane_size.rs b/zellij-utils/src/pane_size.rs
index 66f66ad5..1df73a32 100644
--- a/zellij-utils/src/pane_size.rs
+++ b/zellij-utils/src/pane_size.rs
@@ -1,15 +1,17 @@
use serde::{Deserialize, Serialize};
+use std::hash::{Hash, Hasher};
use crate::position::Position;
/// Contains the position and size of a [`Pane`], or more generally of any terminal, measured
/// in character rows and columns.
-#[derive(Clone, Copy, Default, PartialEq, Debug, Serialize, Deserialize, Eq)]
+#[derive(Clone, Copy, Default, PartialEq, Debug, Serialize, Deserialize, Eq, Hash)]
pub struct PaneGeom {
pub x: usize,
pub y: usize,
pub rows: Dimension,
pub cols: Dimension,
+ pub is_stacked: bool,
}
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
@@ -40,7 +42,7 @@ pub struct SizeInPixels {
pub width: usize,
}
-#[derive(Eq, Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
+#[derive(Eq, Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Hash)]
pub struct Dimension {
pub constraint: Constraint,
inner: usize,
@@ -109,10 +111,16 @@ impl Dimension {
pub fn increase_inner(&mut self, by: usize) {
self.inner += by;
}
+ pub fn decrease_inner(&mut self, by: usize) {
+ self.inner -= by;
+ }
pub fn is_fixed(&self) -> bool {
matches!(self.constraint, Constraint::Fixed(_))
}
+ pub fn is_percent(&self) -> bool {
+ matches!(self.constraint, Constraint::Percent(_))
+ }
}
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
@@ -123,6 +131,16 @@ pub enum Constraint {
Percent(f64),
}
+#[allow(clippy::derive_hash_xor_eq)]
+impl Hash for Constraint {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ match self {
+ Constraint::Fixed(size) => size.hash(state),
+ Constraint::Percent(size) => (*size as usize).hash(state),
+ }
+ }
+}
+
impl Eq for Constraint {}
impl PaneGeom {
@@ -149,6 +167,14 @@ impl Offset {
}
}
+ pub fn shift_right_and_top(right: usize, top: usize) -> Self {
+ Self {
+ right,
+ top,
+ ..Default::default()
+ }
+ }
+
// FIXME: This should be top and left, not bottom and right, but `boundaries.rs` would need
// some changing
pub fn shift(bottom: usize, right: usize) -> Self {
@@ -189,3 +215,17 @@ impl From<&PaneGeom> for Size {
}
}
}
+
+impl From<&Size> for PaneGeom {
+ fn from(size: &Size) -> Self {
+ let mut rows = Dimension::percent(100.0);
+ let mut cols = Dimension::percent(100.0);
+ rows.set_inner(size.rows);
+ cols.set_inner(size.cols);
+ Self {
+ rows,
+ cols,
+ ..Default::default()
+ }
+ }
+}
diff --git a/zellij-utils/src/setup.rs b/zellij-utils/src/setup.rs
index ddbc5967..2c4d8989 100644
--- a/zellij-utils/src/setup.rs
+++ b/zellij-utils/src/setup.rs
@@ -104,12 +104,24 @@ pub const DEFAULT_LAYOUT: &[u8] = include_bytes!(concat!(
"assets/layouts/default.kdl"
));
+pub const DEFAULT_SWAP_LAYOUT: &[u8] = include_bytes!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/",
+ "assets/layouts/default.swap.kdl"
+));
+
pub const STRIDER_LAYOUT: &[u8] = include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/",
"assets/layouts/strider.kdl"
));
+pub const STRIDER_SWAP_LAYOUT: &[u8] = include_bytes!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/",
+ "assets/layouts/strider.swap.kdl"
+));
+
pub const NO_STATUS_LAYOUT: &[u8] = include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/",
@@ -122,6 +134,12 @@ pub const COMPACT_BAR_LAYOUT: &[u8] = include_bytes!(concat!(
"assets/layouts/compact.kdl"
));
+pub const COMPACT_BAR_SWAP_LAYOUT: &[u8] = include_bytes!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/",
+ "assets/layouts/compact.swap.kdl"
+));
+
pub const FISH_EXTRA_COMPLETION: &[u8] = include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/",
@@ -175,6 +193,18 @@ pub fn dump_specified_layout(layout: &str) -> std::io::Result<()> {
}
}
+pub fn dump_specified_swap_layout(swap_layout: &str) -> std::io::Result<()> {
+ match swap_layout {
+ "strider" => dump_asset(STRIDER_SWAP_LAYOUT),
+ "default" => dump_asset(DEFAULT_SWAP_LAYOUT),
+ "compact" => dump_asset(COMPACT_BAR_SWAP_LAYOUT),
+ not_found => Err(std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Swap Layout not found for: {}", not_found),
+ )),
+ }
+}
+
#[cfg(not(target_family = "wasm"))]
pub fn dump_builtin_plugins(path: &PathBuf) -> Result<()> {
for (asset_path, bytes) in ASSET_MAP.iter() {
@@ -230,6 +260,10 @@ pub struct Setup {
#[clap(long, value_parser)]
pub dump_layout: Option<String>,
+ /// Dump the specified swap layout file to stdout
+ #[clap(long, value_parser)]
+ pub dump_swap_layout: Option<String>,
+
/// Dump the builtin plugins to DIR or "DATA DIR" if unspecified
#[clap(
long,
@@ -337,6 +371,11 @@ impl Setup {
std::process::exit(0);
}
+ if let Some(swap_layout) = &self.dump_swap_layout {
+ dump_specified_swap_layout(swap_layout)?;
+ std::process::exit(0);
+ }
+
Ok(())
}
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_config_options.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_config_options.snap
index 00801403..dfe128da 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_config_options.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_config_options.snap
@@ -1,6 +1,6 @@
---
source: zellij-utils/src/setup.rs
-assertion_line: 561
+assertion_line: 597
expression: "format!(\"{:#?}\", options)"
---
Options {
@@ -24,4 +24,5 @@ Options {
scrollback_editor: None,
session_name: None,
attach_to_session: None,
+ auto_layout: None,
}
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options-2.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options-2.snap
index 8c6d5992..2b284c4a 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options-2.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options-2.snap
@@ -7,16 +7,22 @@ Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options.snap
index a36a7543..881d22ee 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__cli_arguments_override_layout_options.snap
@@ -1,6 +1,6 @@
---
source: zellij-utils/src/setup.rs
-assertion_line: 584
+assertion_line: 625
expression: "format!(\"{:#?}\", options)"
---
Options {
@@ -24,4 +24,5 @@ Options {
scrollback_editor: None,
session_name: None,
attach_to_session: None,
+ auto_layout: None,
}
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap
index 8d89277c..b87b9344 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap
@@ -1,83 +1,1605 @@
---
source: zellij-utils/src/setup.rs
-assertion_line: 583
+assertion_line: 601
expression: "format!(\"{:#?}\", layout)"
---
Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: Some(
- Fixed(
- 1,
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
+ ),
),
- ),
- run: Some(
- Plugin(
- RunPlugin {
- _allow_exec_host_cmd: false,
- location: Zellij(
- PluginTag(
- "tab-bar",
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
),
- ),
- },
+ },
+ ),
),
- ),
- borderless: true,
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
+ ),
+ swap_layouts: [],
+ swap_tiled_layouts: [
+ (
+ {
+ MaxPanes(
+ 5,
+ ): TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: Some(
+ 0,
+ ),
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ MaxPanes(
+ 8,
+ ): TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
- children: [],
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: Some(
+ 0,
+ ),
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
split_size: None,
run: None,
borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- PaneLayout {
+ MaxPanes(
+ 12,
+ ): TiledPaneLayout {
children_split_direction: Horizontal,
name: None,
- children: [],
- split_size: Some(
- Fixed(
- 2,
- ),
- ),
- run: Some(
- Plugin(
- RunPlugin {
- _allow_exec_host_cmd: false,
- location: Zellij(
- PluginTag(
- "status-bar",
- ),
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
),
- },
- ),
- ),
- borderless: true,
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: Some(
+ 0,
+ ),
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
focus: None,
external_children_index: None,
+ children_are_stacked: false,
},
- ],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
- ),
- floating_panes_template: [],
+ },
+ Some(
+ "vertical",
+ ),
+ ),
+ (
+ {
+ MaxPanes(
+ 5,
+ ): TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ MaxPanes(
+ 8,
+ ): TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: Some(
+ 0,
+ ),
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ MaxPanes(
+ 12,
+ ): TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: Some(
+ 0,
+ ),
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ },
+ Some(
+ "horizontal",
+ ),
+ ),
+ (
+ {
+ MinPanes(
+ 5,
+ ): TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "tab-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Vertical,
+ name: None,
+ children: [
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: Some(
+ 0,
+ ),
+ children_are_stacked: true,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: Some(
+ Plugin(
+ RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: Zellij(
+ PluginTag(
+ "status-bar",
+ ),
+ ),
+ },
+ ),
+ ),
+ borderless: true,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ ],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ },
+ Some(
+ "stacked",
+ ),
+ ),
+ ],
+ swap_floating_layouts: [
+ (
+ {
+ NoConstraint: [],
+ },
+ Some(
+ "staggered",
+ ),
+ ),
+ (
+ {
+ MaxPanes(
+ 10,
+ ): [
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ x: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ y: Some(
+ Fixed(
+ 1,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ x: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ y: Some(
+ Fixed(
+ 2,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ x: Some(
+ Fixed(
+ 3,
+ ),
+ ),
+ y: Some(
+ Fixed(
+ 3,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ x: Some(
+ Fixed(
+ 4,
+ ),
+ ),
+ y: Some(
+ Fixed(
+ 4,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ x: Some(
+ Fixed(
+ 5,
+ ),
+ ),
+ y: Some(
+ Fixed(
+ 5,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ x: Some(
+ Fixed(
+ 6,
+ ),
+ ),
+ y: Some(
+ Fixed(
+ 6,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ x: Some(
+ Fixed(
+ 7,
+ ),
+ ),
+ y: Some(
+ Fixed(
+ 7,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ x: Some(
+ Fixed(
+ 8,
+ ),
+ ),
+ y: Some(
+ Fixed(
+ 8,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ x: Some(
+ Fixed(
+ 9,
+ ),
+ ),
+ y: Some(
+ Fixed(
+ 9,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 90,
+ ),
+ ),
+ x: Some(
+ Fixed(
+ 10,
+ ),
+ ),
+ y: Some(
+ Fixed(
+ 10,
+ ),
+ ),
+ run: None,
+ focus: Some(
+ true,
+ ),
+ },
+ ],
+ },
+ Some(
+ "enlarged",
+ ),
+ ),
+ (
+ {
+ MaxPanes(
+ 1,
+ ): [
+ FloatingPaneLayout {
+ name: None,
+ height: None,
+ width: None,
+ x: Some(
+ Percent(
+ 50,
+ ),
+ ),
+ y: Some(
+ Percent(
+ 50,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ ],
+ MaxPanes(
+ 2,
+ ): [
+ FloatingPaneLayout {
+ name: None,
+ height: None,
+ width: Some(
+ Percent(
+ 45,
+ ),
+ ),
+ x: Some(
+ Percent(
+ 1,
+ ),
+ ),
+ y: Some(
+ Percent(
+ 25,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: None,
+ width: Some(
+ Percent(
+ 45,
+ ),
+ ),
+ x: Some(
+ Percent(
+ 50,
+ ),
+ ),
+ y: Some(
+ Percent(
+ 25,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ ],
+ MaxPanes(
+ 3,
+ ): [
+ FloatingPaneLayout {
+ name: None,
+ height: Some(
+ Percent(
+ 45,
+ ),
+ ),
+ width: Some(
+ Percent(
+ 45,
+ ),
+ ),
+ x: None,
+ y: Some(
+ Percent(
+ 55,
+ ),
+ ),
+ run: None,
+ focus: Some(
+ true,
+ ),
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: None,
+ width: Some(
+ Percent(
+ 45,
+ ),
+ ),
+ x: Some(
+ Percent(
+ 1,
+ ),
+ ),
+ y: Some(
+ Percent(
+ 1,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ FloatingPaneLayout {
+ name: None,
+ height: None,
+ width: Some(
+ Percent(
+ 45,
+ ),
+ ),
+ x: Some(
+ Percent(
+ 50,
+ ),
+ ),
+ y: Some(
+ Percent(
+ 1,
+ ),
+ ),
+ run: None,
+ focus: None,
+ },
+ ],
+ },
+ Some(
+ "spread",
+ ),
+ ),
+ ],
}
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-3.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-3.snap
index e23c0d24..b8c2a501 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-3.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-3.snap
@@ -1,6 +1,6 @@
---
source: zellij-utils/src/setup.rs
-assertion_line: 546
+assertion_line: 584
expression: "format!(\"{:#?}\", options)"
---
Options {
@@ -22,4 +22,5 @@ Options {
scrollback_editor: None,
session_name: None,
attach_to_session: None,
+ auto_layout: None,
}
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap
index 2ccadb3c..6ba66680 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap
@@ -1,5 +1,6 @@
---
source: zellij-utils/src/setup.rs
+assertion_line: 621
expression: "format!(\"{:#?}\", config)"
---
Config {
@@ -37,6 +38,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -364,6 +379,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -693,6 +722,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -977,6 +1020,8 @@ Config {
None,
[],
None,
+ None,
+ None,
),
SwitchToMode(
Normal,
@@ -1042,6 +1087,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1300,6 +1359,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1498,6 +1571,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1775,6 +1862,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1973,6 +2074,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2168,6 +2283,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2368,6 +2497,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2594,6 +2737,11 @@ Config {
None,
),
],
+ Char(
+ 'p',
+ ): [
+ MovePaneBackwards,
+ ],
Alt(
Char(
'+',
@@ -2626,6 +2774,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2818,6 +2980,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -3006,6 +3182,11 @@ Config {
),
],
Char(
+ ' ',
+ ): [
+ NextSwapLayout,
+ ],
+ Char(
'"',
): [
NewPane(
@@ -3052,6 +3233,8 @@ Config {
None,
[],
None,
+ None,
+ None,
),
SwitchToMode(
Normal,
@@ -3171,6 +3354,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -3343,6 +3540,7 @@ Config {
scrollback_editor: None,
session_name: None,
attach_to_session: None,
+ auto_layout: None,
},
themes: {},
plugins: {
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap
index 6bc0fbba..97a16c77 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap
@@ -1,5 +1,6 @@
---
source: zellij-utils/src/setup.rs
+assertion_line: 679
expression: "format!(\"{:#?}\", config)"
---
Config {
@@ -37,6 +38,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -364,6 +379,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -693,6 +722,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -977,6 +1020,8 @@ Config {
None,
[],
None,
+ None,
+ None,
),
SwitchToMode(
Normal,
@@ -1042,6 +1087,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1300,6 +1359,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1498,6 +1571,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1775,6 +1862,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1973,6 +2074,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2168,6 +2283,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2368,6 +2497,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2594,6 +2737,11 @@ Config {
None,
),
],
+ Char(
+ 'p',
+ ): [
+ MovePaneBackwards,
+ ],
Alt(
Char(
'+',
@@ -2626,6 +2774,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2818,6 +2980,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -3006,6 +3182,11 @@ Config {
),
],
Char(
+ ' ',
+ ): [
+ NextSwapLayout,
+ ],
+ Char(
'"',
): [
NewPane(
@@ -3052,6 +3233,8 @@ Config {
None,
[],
None,
+ None,
+ None,
),
SwitchToMode(
Normal,
@@ -3171,6 +3354,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -3343,6 +3540,7 @@ Config {
scrollback_editor: None,
session_name: None,
attach_to_session: None,
+ auto_layout: None,
},
themes: {},
plugins: {
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_keybinds_override_config_keybinds.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_keybinds_override_config_keybinds.snap
index fd8007af..e8d8bccb 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_keybinds_override_config_keybinds.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_keybinds_override_config_keybinds.snap
@@ -1,6 +1,6 @@
---
source: zellij-utils/src/setup.rs
-assertion_line: 625
+assertion_line: 696
expression: "format!(\"{:#?}\", config)"
---
Config {
@@ -80,6 +80,7 @@ Config {
scrollback_editor: None,
session_name: None,
attach_to_session: None,
+ auto_layout: None,
},
themes: {},
plugins: {
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options-2.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options-2.snap
index 97b1c8b6..790df2f6 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options-2.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options-2.snap
@@ -7,16 +7,22 @@ Layout {
tabs: [],
focused_tab_index: None,
template: Some(
- PaneLayout {
- children_split_direction: Horizontal,
- name: None,
- children: [],
- split_size: None,
- run: None,
- borderless: false,
- focus: None,
- external_children_index: None,
- },
+ (
+ TiledPaneLayout {
+ children_split_direction: Horizontal,
+ name: None,
+ children: [],
+ split_size: None,
+ run: None,
+ borderless: false,
+ focus: None,
+ external_children_index: None,
+ children_are_stacked: false,
+ },
+ [],
+ ),
),
- floating_panes_template: [],
+ swap_layouts: [],
+ swap_tiled_layouts: [],
+ swap_floating_layouts: [],
}
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options.snap
index d8fc7879..2a3e7ace 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_options_override_config_options.snap
@@ -1,6 +1,6 @@
---
source: zellij-utils/src/setup.rs
-assertion_line: 567
+assertion_line: 607
expression: "format!(\"{:#?}\", options)"
---
Options {
@@ -24,4 +24,5 @@ Options {
scrollback_editor: None,
session_name: None,
attach_to_session: None,
+ auto_layout: None,
}
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap
index d2391edd..2b07b2f9 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap
@@ -1,5 +1,6 @@
---
source: zellij-utils/src/setup.rs
+assertion_line: 707
expression: "format!(\"{:#?}\", config)"
---
Config {
@@ -37,6 +38,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -364,6 +379,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -693,6 +722,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -977,6 +1020,8 @@ Config {
None,
[],
None,
+ None,
+ None,
),
SwitchToMode(
Normal,
@@ -1042,6 +1087,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1300,6 +1359,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1498,6 +1571,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1775,6 +1862,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1973,6 +2074,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2168,6 +2283,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2368,6 +2497,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2594,6 +2737,11 @@ Config {
None,
),
],
+ Char(
+ 'p',
+ ): [
+ MovePaneBackwards,
+ ],
Alt(
Char(
'+',
@@ -2626,6 +2774,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2818,6 +2980,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -3006,6 +3182,11 @@ Config {
),
],
Char(
+ ' ',
+ ): [
+ NextSwapLayout,
+ ],
+ Char(
'"',
): [
NewPane(
@@ -3052,6 +3233,8 @@ Config {
None,
[],
None,
+ None,
+ None,
),
SwitchToMode(
Normal,
@@ -3171,6 +3354,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -3343,6 +3540,7 @@ Config {
scrollback_editor: None,
session_name: None,
attach_to_session: None,
+ auto_layout: None,
},
themes: {},
plugins: {
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap
index a69286fe..13e440e0 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap
@@ -1,5 +1,6 @@
---
source: zellij-utils/src/setup.rs
+assertion_line: 721
expression: "format!(\"{:#?}\", config)"
---
Config {
@@ -37,6 +38,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -364,6 +379,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -693,6 +722,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -977,6 +1020,8 @@ Config {
None,
[],
None,
+ None,
+ None,
),
SwitchToMode(
Normal,
@@ -1042,6 +1087,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1300,6 +1359,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1498,6 +1571,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1775,6 +1862,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1973,6 +2074,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2168,6 +2283,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2368,6 +2497,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2594,6 +2737,11 @@ Config {
None,
),
],
+ Char(
+ 'p',
+ ): [
+ MovePaneBackwards,
+ ],
Alt(
Char(
'+',
@@ -2626,6 +2774,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2818,6 +2980,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -3006,6 +3182,11 @@ Config {
),
],
Char(
+ ' ',
+ ): [
+ NextSwapLayout,
+ ],
+ Char(
'"',
): [
NewPane(
@@ -3052,6 +3233,8 @@ Config {
None,
[],
None,
+ None,
+ None,
),
SwitchToMode(
Normal,
@@ -3171,6 +3354,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -3343,6 +3540,7 @@ Config {
scrollback_editor: None,
session_name: None,
attach_to_session: None,
+ auto_layout: None,
},
themes: {
"other-theme-from-config": Theme {
diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap
index dc086ff0..072f2182 100644
--- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap
+++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap
@@ -1,5 +1,6 @@
---
source: zellij-utils/src/setup.rs
+assertion_line: 693
expression: "format!(\"{:#?}\", config)"
---
Config {
@@ -37,6 +38,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -364,6 +379,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -693,6 +722,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -977,6 +1020,8 @@ Config {
None,
[],
None,
+ None,
+ None,
),
SwitchToMode(
Normal,
@@ -1042,6 +1087,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1300,6 +1359,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1498,6 +1571,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1775,6 +1862,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -1973,6 +2074,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2168,6 +2283,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2368,6 +2497,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2594,6 +2737,11 @@ Config {
None,
),
],
+ Char(
+ 'p',
+ ): [
+ MovePaneBackwards,
+ ],
Alt(
Char(
'+',
@@ -2626,6 +2774,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -2818,6 +2980,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -3006,6 +3182,11 @@ Config {
),
],
Char(
+ ' ',
+ ): [
+ NextSwapLayout,
+ ],
+ Char(
'"',
): [
NewPane(
@@ -3052,6 +3233,8 @@ Config {
None,
[],
None,
+ None,
+ None,
),
SwitchToMode(
Normal,
@@ -3171,6 +3354,20 @@ Config {
],
Alt(
Char(
+ '[',
+ ),
+ ): [
+ PreviousSwapLayout,
+ ],
+ Alt(
+ Char(
+ ']',
+ ),
+ ): [
+ NextSwapLayout,
+ ],
+ Alt(
+ Char(
'h',
),
): [
@@ -3343,6 +3540,7 @@ Config {
scrollback_editor: None,
session_name: None,
attach_to_session: None,
+ auto_layout: None,
},
themes: {},
plugins: {