From f1ff272b0b65f6d328fef24531ada67ea585ce85 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Fri, 17 Feb 2023 12:05:50 +0100 Subject: [PATCH] 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 --- default-plugins/compact-bar/src/line.rs | 94 + default-plugins/compact-bar/src/main.rs | 6 + default-plugins/status-bar/src/first_line.rs | 146 +- default-plugins/status-bar/src/main.rs | 103 +- default-plugins/status-bar/src/second_line.rs | 7 +- .../status-bar/src/tip/data/compact_layout.rs | 8 +- .../src/tip/data/edit_scrollbuffer.rs | 8 +- .../src/tip/data/floating_panes_mouse.rs | 3 +- .../tip/data/move_focus_hjkl_tab_switch.rs | 4 +- .../status-bar/src/tip/data/quicknav.rs | 8 +- .../status-bar/src/tip/data/sync_tab.rs | 8 +- src/tests/e2e/remote_runner.rs | 7 + ...e2e__cases__detach_and_attach_session.snap | 2 +- ...ts__e2e__cases__focus_pane_with_mouse.snap | 4 +- ...ests__e2e__cases__mirrored_sessions-2.snap | 2 +- ..._tests__e2e__cases__mirrored_sessions.snap | 2 +- ...ers_in_different_panes_and_same_tab-2.snap | 4 +- ...users_in_different_panes_and_same_tab.snap | 4 +- ...ellij__tests__e2e__cases__resize_pane.snap | 4 +- ...s__e2e__cases__resize_terminal_window.snap | 4 +- ...__e2e__cases__scrolling_inside_a_pane.snap | 6 +- ...s__scrolling_inside_a_pane_with_mouse.snap | 4 +- ...__cases__send_command_through_the_cli.snap | 2 +- ...2e__cases__split_terminals_vertically.snap | 4 +- ...e2e__cases__start_without_pane_frames.snap | 4 +- .../zellij__tests__e2e__cases__tmux_mode.snap | 4 +- ...ts__e2e__cases__toggle_floating_panes.snap | 4 +- ...s__e2e__cases__toggle_pane_fullscreen.snap | 4 +- zellij-server/src/lib.rs | 20 +- zellij-server/src/os_input_output.rs | 29 +- zellij-server/src/panes/active_panes.rs | 1 + .../floating_panes/floating_pane_grid.rs | 55 + zellij-server/src/panes/floating_panes/mod.rs | 126 +- zellij-server/src/panes/plugin_pane.rs | 24 +- zellij-server/src/panes/terminal_pane.rs | 32 +- zellij-server/src/panes/tiled_panes/mod.rs | 364 +- .../src/panes/tiled_panes/pane_resizer.rs | 137 +- .../src/panes/tiled_panes/stacked_panes.rs | 630 +++ .../src/panes/tiled_panes/tiled_pane_grid.rs | 445 +- .../src/panes/unit/search_in_pane_tests.rs | 1 + .../src/panes/unit/terminal_pane_tests.rs | 12 + zellij-server/src/plugins/mod.rs | 11 +- zellij-server/src/pty.rs | 10 +- zellij-server/src/route.rs | 34 +- zellij-server/src/screen.rs | 103 +- zellij-server/src/tab/layout_applier.rs | 367 +- zellij-server/src/tab/mod.rs | 322 +- zellij-server/src/tab/swap_layouts.rs | 284 ++ ...ng_layout_is_included_in_swap_layouts.snap | 26 + ...se_layout_is_included_in_swap_layouts.snap | 26 + ...ase_size_into_pane_stack_horizontally.snap | 26 + ...ize_into_pane_stack_non_directionally.snap | 46 + ...rease_size_into_pane_stack_vertically.snap | 46 + ...ze_of_main_pane_in_stack_horizontally.snap | 26 + ..._main_pane_in_stack_non_directionally.snap | 46 + ...size_of_main_pane_in_stack_vertically.snap | 46 + ...ts__can_swap_between_multiple_layouts.snap | 26 + ...__can_swap_floating_layout_at_runtime.snap | 26 + ...sts__can_swap_tiled_layout_at_runtime.snap | 26 + ...ease_stack_size_beyond_minimum_height.snap | 26 + ...ration_tests__close_main_stacked_pane.snap | 26 + ..._close_main_stacked_pane_in_mid_stack.snap | 26 + ...ne_liner_stacked_pane_above_main_pane.snap | 26 + ...ne_liner_stacked_pane_below_main_pane.snap | 26 + ..._tests__close_pane_near_stacked_panes.snap | 26 + ...ne_with_previously_focused_other_pane.snap | 26 + ...ole_tab_treats_stacked_panes_properly.snap | 26 + ..._plugins_and_commands_swaped_properly.snap | 26 + ...focus_next_pane_expands_stacked_panes.snap | 26 + ...ane_over_flexible_pane_with_the_mouse.snap | 26 + ...ne_under_flexible_pane_with_the_mouse.snap | 26 + ...ack_horizontally_does_not_break_stack.snap | 46 + ...ack_horizontally_does_not_break_stack.snap | 46 + ...ole_tab_treats_stacked_panes_properly.snap | 26 + ..._plugins_and_commands_swaped_properly.snap | 26 + ...s__move_focus_down_into_stacked_panes.snap | 26 + ...s__move_focus_down_with_stacked_panes.snap | 26 + ...s__move_focus_left_into_stacked_panes.snap | 26 + ...__move_focus_right_into_stacked_panes.snap | 26 + ...sts__move_focus_up_into_stacked_panes.snap | 26 + ...sts__move_focus_up_with_stacked_panes.snap | 26 + ..._tests__move_focus_with_stacked_panes.snap | 26 + ...s__new_floating_pane_in_auto_layout-2.snap | 26 + ...s__new_floating_pane_in_auto_layout-3.snap | 26 + ...sts__new_floating_pane_in_auto_layout.snap | 26 + ...tion_tests__new_pane_in_auto_layout-2.snap | 26 + ...tion_tests__new_pane_in_auto_layout-3.snap | 26 + ...tion_tests__new_pane_in_auto_layout-4.snap | 26 + ...tion_tests__new_pane_in_auto_layout-5.snap | 26 + ...tion_tests__new_pane_in_auto_layout-6.snap | 26 + ...tion_tests__new_pane_in_auto_layout-7.snap | 26 + ...ration_tests__new_pane_in_auto_layout.snap | 26 + ...tests__resize_tab_with_floating_panes.snap | 2 +- ..._tab_while_floting_pane_is_suppressed.snap | 2 +- ...ing_panes_horizontally_and_vertically.snap | 2 +- ...ntally_and_vertically_and_expand_back.snap | 2 +- ...__stacked_panes_can_become_fullscreen.snap | 26 + ...and_panes_absent_from_existing_layout.snap | 26 + ...gin_panes_absent_from_existing_layout.snap | 26 + ...mand_panes_present_in_existing_layout.snap | 26 + ...ugin_panes_present_in_existing_layout.snap | 26 + ...and_panes_absent_from_existing_layout.snap | 26 + ...gin_panes_absent_from_existing_layout.snap | 26 + ...mand_panes_present_in_existing_layout.snap | 26 + ...ugin_panes_present_in_existing_layout.snap | 26 + ...ap_tiled_layout_with_stacked_children.snap | 26 + ...h_stacked_children_and_no_pane_frames.snap | 26 + ..._after_resize_snaps_to_current_layout.snap | 26 + ...t_the_focus_goes_to_last_focused_pane.snap | 26 + ...t_the_focus_goes_to_last_focused_pane.snap | 26 + ...oating_panes_the_layout_is_maintained.snap | 36 + ...e_layout_and_pane_focus_are_unchanged.snap | 26 + ...ed_state_pane_focuses_on_focused_node.snap | 26 + ...cus_node_pane_focuses_on_deepest_node.snap | 26 + ...e_layout_and_pane_focus_are_unchanged.snap | 26 + ...ed_state_pane_focuses_on_focused_node.snap | 26 + ...cus_node_pane_focuses_on_deepest_node.snap | 26 + .../src/tab/unit/tab_integration_tests.rs | 4067 ++++++++++++++++- zellij-server/src/tab/unit/tab_tests.rs | 55 +- zellij-server/src/thread_bus.rs | 6 + zellij-server/src/ui/boundaries.rs | 14 +- zellij-server/src/ui/pane_boundaries_frame.rs | 133 +- zellij-server/src/ui/pane_contents_and_ui.rs | 15 + .../src/unit/os_input_output_tests.rs | 1 + zellij-server/src/unit/screen_tests.rs | 194 +- ...end_cli_new_tab_action_default_params.snap | 11 +- ...i_new_tab_action_with_name_and_layout.snap | 14 +- ...en__screen_tests__send_cli_rename_tab.snap | 48 +- ...creen_tests__send_cli_undo_rename_tab.snap | 56 +- zellij-utils/assets/compact-bar.wasm | Bin 0 -> 397489 bytes zellij-utils/assets/config/default.kdl | 11 + zellij-utils/assets/layouts/compact.swap.kdl | 91 + zellij-utils/assets/layouts/default.swap.kdl | 94 + zellij-utils/assets/layouts/strider.kdl | 23 +- zellij-utils/assets/layouts/strider.swap.kdl | 102 + zellij-utils/assets/plugins/compact-bar.wasm | Bin 397489 -> 427886 bytes zellij-utils/assets/plugins/status-bar.wasm | Bin 485616 -> 520407 bytes zellij-utils/assets/plugins/strider.wasm | Bin 413509 -> 441654 bytes zellij-utils/assets/plugins/tab-bar.wasm | Bin 373679 -> 400807 bytes zellij-utils/assets/status-bar.wasm | Bin 0 -> 485616 bytes zellij-utils/assets/strider.wasm | Bin 0 -> 413509 bytes zellij-utils/assets/tab-bar.wasm | Bin 0 -> 373679 bytes zellij-utils/src/cli.rs | 42 +- zellij-utils/src/data.rs | 2 + zellij-utils/src/errors.rs | 3 + zellij-utils/src/input/actions.rs | 52 +- zellij-utils/src/input/layout.rs | 373 +- zellij-utils/src/input/options.rs | 10 + zellij-utils/src/input/unit/layout_test.rs | 669 +-- ..._test__args_added_to_args_in_template.snap | 116 +- ..._test__args_override_args_in_template.snap | 122 +- ...ad_swap_layouts_from_a_different_file.snap | 536 +++ ...n_not_as_first_child_of_pane_template.snap | 281 +- ...en_not_as_first_child_of_tab_template.snap | 63 +- ...it_added_to_close_on_exit_in_template.snap | 110 +- ...t_overrides_close_on_exit_in_template.snap | 110 +- ..._and_pane_template_both_with_children.snap | 78 +- ...ut_test__cwd_added_to_cwd_in_template.snap | 114 +- ...ut_test__cwd_override_cwd_in_template.snap | 118 +- ...epended_to_panes_with_and_without_cwd.snap | 39 +- ...ith_and_without_cwd_in_pane_templates.snap | 48 +- ...with_and_without_cwd_in_tab_templates.snap | 45 +- ...global_cwd_given_to_panes_without_cwd.snap | 102 +- ...al_cwd_passed_from_layout_constructor.snap | 102 +- ...r_overrides_global_cwd_in_layout_file.snap | 102 +- ...lobal_cwd_prepended_to_panes_with_cwd.snap | 102 +- ...th_tab_cwd_given_to_panes_without_cwd.snap | 39 +- ..._with_command_panes_and_close_on_exit.snap | 71 +- ...ith_command_panes_and_start_suspended.snap | 71 +- ...est__layout_with_default_tab_template.snap | 143 +- ...t_with_nested_branched_pane_templates.snap | 248 +- ...st__layout_with_nested_pane_templates.snap | 183 +- ...yout_test__layout_with_pane_templates.snap | 487 +- ...t__layout_with_tab_and_pane_templates.snap | 48 +- ...__layout_with_tabs_and_floating_panes.snap | 48 +- ...s_overriden_by_its_consumers_bare_cwd.snap | 75 +- ...verriden_by_its_consumers_command_cwd.snap | 75 +- ..._consumer_command_does_not_have_a_cwd.snap | 75 +- ...cwd_is_overriden_by_its_consumers_cwd.snap | 75 +- ...t_cwd_receives_its_consumers_bare_cwd.snap | 75 +- ...d_overriden_by_its_consumers_bare_cwd.snap | 59 +- ...ated_to_its_consumer_command_with_cwd.snap | 75 +- ...d_to_its_consumer_command_without_cwd.snap | 75 +- ..._bare_propagated_to_its_consumer_edit.snap | 61 +- ...mmand_propagated_to_its_consumer_edit.snap | 61 +- ...t__tab_cwd_given_to_panes_without_cwd.snap | 39 +- ...__tab_cwd_prepended_to_panes_with_cwd.snap | 39 +- zellij-utils/src/kdl/kdl_layout_parser.rs | 577 ++- zellij-utils/src/kdl/mod.rs | 134 +- zellij-utils/src/pane_size.rs | 44 +- zellij-utils/src/setup.rs | 39 + ...cli_arguments_override_config_options.snap | 3 +- ...i_arguments_override_layout_options-2.snap | 28 +- ...cli_arguments_override_layout_options.snap | 3 +- ...efault_config_with_no_cli_arguments-2.snap | 1636 ++++++- ...efault_config_with_no_cli_arguments-3.snap | 3 +- ..._default_config_with_no_cli_arguments.snap | 198 + ...out_env_vars_override_config_env_vars.snap | 198 + ...out_keybinds_override_config_keybinds.snap | 3 +- ...out_options_override_config_options-2.snap | 28 +- ...ayout_options_override_config_options.snap | 3 +- ...ayout_plugins_override_config_plugins.snap | 198 + ..._layout_themes_override_config_themes.snap | 198 + ..._ui_config_overrides_config_ui_config.snap | 198 + 204 files changed, 16278 insertions(+), 2904 deletions(-) create mode 100644 zellij-server/src/panes/tiled_panes/stacked_panes.rs create mode 100644 zellij-server/src/tab/swap_layouts.rs create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_floating_layout_is_included_in_swap_layouts.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_layout_is_included_in_swap_layouts.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_horizontally.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_non_directionally.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_into_pane_stack_vertically.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_horizontally.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_non_directionally.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_increase_size_of_main_pane_in_stack_vertically.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_between_multiple_layouts.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_floating_layout_at_runtime.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_tiled_layout_at_runtime.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__cannot_decrease_stack_size_beyond_minimum_height.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_main_stacked_pane.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_main_stacked_pane_in_mid_stack.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_one_liner_stacked_pane_above_main_pane.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_one_liner_stacked_pane_below_main_pane.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_pane_near_stacked_panes.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_stacked_pane_with_previously_focused_other_pane.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__decreasing_size_of_whole_tab_treats_stacked_panes_properly.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_layout_with_plugins_and_commands_swaped_properly.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_next_pane_expands_stacked_panes.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_stacked_pane_over_flexible_pane_with_the_mouse.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_stacked_pane_under_flexible_pane_with_the_mouse.snap create mode 100644 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 create mode 100644 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 create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increasing_size_of_whole_tab_treats_stacked_panes_properly.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__layout_with_plugins_and_commands_swaped_properly.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_down_into_stacked_panes.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_down_with_stacked_panes.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_left_into_stacked_panes.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_right_into_stacked_panes.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_up_into_stacked_panes.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_up_with_stacked_panes.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_focus_with_stacked_panes.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-2.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-3.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-2.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-3.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-4.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-5.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-6.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout-7.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_pane_in_auto_layout.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__stacked_panes_can_become_fullscreen.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_command_panes_absent_from_existing_layout.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_plugin_panes_absent_from_existing_layout.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_command_panes_present_in_existing_layout.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_plugin_panes_present_in_existing_layout.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_including_command_panes_absent_from_existing_layout.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_including_plugin_panes_absent_from_existing_layout.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_command_panes_present_in_existing_layout.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_plugin_panes_present_in_existing_layout.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_tiled_layout_with_stacked_children.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_tiled_layout_with_stacked_children_and_no_pane_frames.snap create mode 100644 zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swapping_layouts_after_resize_snaps_to_current_layout.snap create mode 100644 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 create mode 100644 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 create mode 100644 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 create mode 100644 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 create mode 100644 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 create mode 100644 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 create mode 100644 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 create mode 100644 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 create mode 100644 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 create mode 100644 zellij-utils/assets/compact-bar.wasm create mode 100644 zellij-utils/assets/layouts/compact.swap.kdl create mode 100644 zellij-utils/assets/layouts/default.swap.kdl create mode 100644 zellij-utils/assets/layouts/strider.swap.kdl create mode 100644 zellij-utils/assets/status-bar.wasm create mode 100644 zellij-utils/assets/strider.wasm create mode 100644 zellij-utils/assets/tab-bar.wasm create mode 100644 zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__can_load_swap_layouts_from_a_different_file.snap 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, + is_swap_layout_dirty: bool, ) -> Vec { 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, + is_swap_layout_damaged: bool, + input_mode: InputMode, + palette: &Palette, + separator: &str, +) -> Option { + 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 = 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, + is_swap_layout_damaged: bool, + mode_info: &ModeInfo, + colored_elements: ColoredElements, + palette: &Palette, + separator: &str, +) -> Option { + 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)], 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> { +pub fn style_key_with_modifier( + keyvec: &[Key], + palette: &Palette, + background: Option, +) -> Vec> { // 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 Vec "", "←→" => "", "↓↑" => "", + "[]" => "", _ => "|", }; 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, "".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, "".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, "".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 + ".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 + ".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, "".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 + ".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 + ".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 = 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)> { 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)> { &[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)> { (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 { } 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 { } 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 { } 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 { 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 { } 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  <←→> Move focus / New / Close / Rename / Sync / Toggle / 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => 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 + / Alt + <←↓↑→> or Alt + / 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - <↓↑> Scroll / Scroll / Scroll / Edit / Search / Select + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  + <↓↑> Scroll / Scroll / Scroll / Edit / Search / 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  BASE  Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - (FLOATING PANES VISIBLE): Press Ctrl+p, to hide. + (FLOATING PANES VISIBLE): Press Ctrl+p, 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 + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  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, + pub layout: Box, screen_thread: Option>, pty_thread: Option>, plugin_thread: Option>, @@ -346,7 +347,7 @@ pub fn start_server(mut os_input: Box, 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, 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, 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, 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>, client_senders: Arc>>, terminal_id_to_raw_fd: Arc>>>, // 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>>>, // } // 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, 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 { @@ -767,6 +787,7 @@ pub fn get_server_os_input() -> Result { 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, os_api: Box, 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 { + let panes = self.panes.borrow(); + let mut panes: Vec<(PaneId, &&mut Box)> = 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 { + let panes = self.panes.borrow(); + let mut panes: Vec<(PaneId, &&mut Box)> = 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 { let panes = self.panes.borrow(); let pane_geoms: Vec = 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 { self.active_panes.get(&client_id).copied() } + pub fn active_pane_id_or_focused_pane_id(&self, client_id: Option) -> Option { + // 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, + 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)> { self.panes.iter() } + pub fn visible_panes_count(&self) -> usize { + self.panes.len() + } + pub fn drain(&mut self) -> BTreeMap> { + 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 = 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, 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, borderless: bool, pane_frame_color_override: Option<(PaletteColor, Option)>, + invoked_with: Option, } impl PluginPane { @@ -80,6 +82,7 @@ impl PluginPane { link_handler: Rc>, character_cell_size: Rc>>, style: Style, + invoked_with: Option, ) -> 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 { + &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, // 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)>, + invoked_with: Option, } 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 { + &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>, terminal_emulator_color_codes: Rc>>, initial_pane_title: Option, + invoked_with: Option, ) -> 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 = + 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 = + 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::() { 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::() { 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 = { 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 = { 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 = { 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> { + 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 = 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>; impl<'a> PaneResizer<'a> { pub fn new(panes: Rc>>>) -> 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) -> 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 { + 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 { + panes: Rc>>>, +} + +impl<'a> StackedPanes<'a> { + pub fn new(panes: Rc>>>) -> Self { + StackedPanes { panes } + } + pub fn new_from_btreemap( + panes: impl IntoIterator)>, + panes_to_hide: &HashSet, + ) -> 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 { + 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 { + 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 { + 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 { + 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> { + // 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, + ) -> Result { + 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 { + 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 { + 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, HashSet)> { + 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 = { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { 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> { 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> { 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 = result.iter().map(|t| t.pid()).collect(); + let pane_ids: Vec = 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 { @@ -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 { + 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)> = 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 { + 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)> = 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 { 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 { 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, ) -> Option<(PaneId, SplitDirection)> { let panes = self.panes.borrow(); - let pane_sequence: Vec<(&PaneId, &&mut Box)> = - panes.iter().filter(|(_, p)| p.selectable()).collect(); + let pane_sequence: Vec<(&PaneId, &&mut Box)> = 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, - Option, - Vec, + Option, + Vec, Option, // 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> = 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, - Option, - Vec, + Option, + Vec, Option, usize, // tab_index HashMap>, // plugin_ids @@ -575,8 +575,8 @@ impl Pty { } pub fn spawn_terminals_for_layout( &mut self, - layout: PaneLayout, - floating_panes_layout: Vec, + layout: TiledPaneLayout, + floating_panes_layout: Vec, default_shell: Option, plugin_ids: HashMap>, 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, - Option, - Vec, + Option, + Vec, Option, + (Vec, Vec), // swap layouts ClientId, ), ApplyLayout( - PaneLayout, - Vec, + TiledPaneLayout, + Vec, Vec<(u32, HoldForCommand)>, // new pane pids Vec<(u32, HoldForCommand)>, // new floating pane pids HashMap>, @@ -196,7 +200,12 @@ pub enum ScreenInstruction { ToggleActiveSyncTab(ClientId), CloseTab(ClientId), GoToTab(u32, Option), // this Option is a hacky workaround, please do not copy this behaviour - GoToTabName(String, bool, Option), + GoToTabName( + String, + (Vec, Vec), // swap layouts + bool, + Option, + ), ToggleTab(ClientId), UpdateTabName(Vec, ClientId), UndoRenameTab(ClientId), @@ -231,6 +240,8 @@ pub enum ScreenInstruction { SearchToggleWrap(ClientId), AddRedPaneFrameColorOverride(Vec, Option), // Option => optional error text ClearPaneFrameColorOverride(Vec), + 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, 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, Vec), + 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, + layout: TiledPaneLayout, + floating_panes_layout: Vec, new_terminal_ids: Vec<(u32, HoldForCommand)>, new_floating_terminal_ids: Vec<(u32, HoldForCommand)>, new_plugin_ids: HashMap>, @@ -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, + layout: TiledPaneLayout, + floating_panes_layout: Vec, new_terminal_ids: Vec<(u32, HoldForCommand)>, new_floating_terminal_ids: Vec<(u32, HoldForCommand)>, mut new_plugin_ids: HashMap>, @@ -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, + ) -> 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 = 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>, 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 = 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, + floating_panes_layout: Vec, new_floating_terminal_ids: Vec<(u32, HoldForCommand)>, new_plugin_ids: &mut HashMap>, layout_name: Option, @@ -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, + refocus_pane: bool, + client_id: Option, + ) -> Result { + // 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 = 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, + layout: &TiledPaneLayout, + position_and_size: Option, + ) { + 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, + 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>, + currently_focused_pane_id: Option, +} + +impl ExistingTabState { + pub fn new( + existing_panes: BTreeMap>, + currently_focused_pane_id: Option, + ) -> Self { + ExistingTabState { + existing_panes, + currently_focused_pane_id, + } + } + pub fn find_and_extract_pane( + &mut self, + run: &Option, + position_and_size: &PaneGeom, + is_focused: bool, + default_to_closest_position: bool, + ) -> Option> { + 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(¤t_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(¤tly_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 { + self.existing_panes.keys().copied().collect() + } + pub fn remove_pane(&mut self, pane_id: &PaneId) -> Option> { + self.existing_panes.remove(pane_id) + } + fn pane_candidates( + &self, + run: &Option, + position_and_size: &PaneGeom, + default_to_closest_position: bool, + ) -> Vec<(&PaneId, &Box)> { + 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)>, + ) -> Option { + 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)>, + run: &Option, + ) -> Option { + 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, +} + +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, + pane: &Box, + ) { + 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, + ) { + 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>>, draw_pane_frames: bool, + auto_layout: bool, pending_vte_events: HashMap>, 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>, @@ -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, // 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); fn clear_pane_frame_color_override(&mut self); fn frame_color_override(&self) -> Option; + fn invoked_with(&self) -> &Option; + 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>>, session_is_mirrored: bool, client_id: ClientId, copy_options: CopyOptions, terminal_emulator_colors: Rc>, terminal_emulator_color_codes: Rc>>, + swap_layouts: (Vec, Vec), ) -> 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, + layout: TiledPaneLayout, + floating_panes_layout: Vec, new_terminal_ids: Vec<(u32, HoldForCommand)>, new_floating_terminal_ids: Vec<(u32, HoldForCommand)>, new_plugin_ids: HashMap>, 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, 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, + 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, + 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) -> 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, + 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 = 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, default_shell: Option, ) -> 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, ) -> Option> { // 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, + swap_floating_layouts: Vec, + current_floating_layout_position: usize, + current_tiled_layout_position: usize, + is_floating_damaged: bool, + is_tiled_damaged: bool, + display_area: Rc>, // includes all panes (including eg. the status bar and tab bar in the default layout) +} + +impl SwapLayouts { + pub fn new( + swap_layouts: (Vec, Vec), + display_area: Rc>, + ) -> 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)) { + 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, 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, 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> { + 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 { + 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 { + 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): │ to run, to exit │ to run, 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): │ to run, to exit ││ ││ to run, 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): │ to run, to exit │ to run, 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): │ to run, to exit │ +07 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +08 (C): ┌ command1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +09 (C): │ │ +10 (C): │ Waiting to run: command1 │ +11 (C): │ │ +12 (C): │ to run, 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): │ │ │ to run, 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): │ to run, to exit │ +13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +14 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +15 (C): │ Waiting to run: command2 │ +16 (C): │ │ +17 (C): │ to run, 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): │ to run, to exit │ +07 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +08 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +09 (C): │ │ +10 (C): │ Waiting to run: command2 │ +11 (C): │ │ +12 (C): │ to run, 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, Vec), + base_layout_and_ids: Option<( + TiledPaneLayout, + Vec, + Vec<(u32, Option)>, + Vec<(u32, Option)>, + HashMap>, + )>, + 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 = + 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) { + // 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, } +#[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) { + 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, 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, exit_status: Option, 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) { @@ -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> { + 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> { 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, Option)> { 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)); + 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)); } - } 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)); - - 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, multiple_users_exist_in_session: bool, z_index: Option, + 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, multiple_users_exist_in_session: bool, z_index: Option, + pane_is_stacked_under: bool, + pane_is_stacked_over: bool, + should_draw_pane_frames: bool, ) -> Self { let mut focused_clients: Vec = 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) -> std::thread::JoinHandle<()> { + pub fn run(&mut self, initial_layout: Option) -> 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 0000000000000000000000000000000000000000..46267f5e753216f0ac9c97feaf82d706efcb3014 GIT binary patch literal 397489 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%0A@w^wAH;H*NRA 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%0D|oca9w3RU_I%J!7bf7#l${lkyG|6$%; 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 sL^@*vVcRBZL_ndQ= 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 zra�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 z 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

Kl7HG=H(y2Kt)E`wkwA8deWR4jmB%R+{G}ReP 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⋘Hah=8^UmI zH$)cgl!>yk|2o>!3`M={hx1yB!>De9PbK<*h2#BJLyYxQPy9)8@Om=hqo8u>dTN({ z9(XvI8dK-RRfe3{oq^85Ng@F9Y|QGNYUW-|Xng(Bp{GcK>hnV(qd9 z60G_=jHS#+jd?L|12qplOE^o#UZe3EXT&js<5(uDSx~uwLiv9}PH`BTXHx&ITK0uw zn+sC^Taimr8rxhsX(L@B&Xas^BV0)=M}6=PCCT#}X-S6itjQP$*WbWU;^m(L3J|aV zR8&x1UZ-NuY*`U`|&W>kRX>zk+|Y4`IyIZMM0CWwl_ zCo`~0=--0PBctVun=vj6WW{FcmbCmru&U=HV7Xf;6tpZ{AP~o0)FU0z8eJ- zz6Z8YFu7Ev4ni8#`9M72#mbkqP}Ah<3Y1E;a%yiuU;fGDo+0W zYc`>b3I!slY=Fn#p(brEBB^*jH`NdC&LW9-;J^=dgkXZw46G}n-})vOD5wiaY`*QU zNL;y{QWHi;QOP#jC|NGpMsXLjq|~k-a}SFp+qdzRX!GTY?TX)nw_`R_{kd&BHM|&! zH9z)4i`z&%JLo3GoO^a)nlnmH*+ESr0R)UIw(yWq$QduS?%YAax^u{r;(&PQJUwBZ zgoppooSifd+b7ftZsV90+*En%E=u&jLY`VE#Ml_s8}f-=xJK*I@Kx{9Bn~?Nu^SWI z?{-sd>%D)6Dm7gj1TzT18i>cSHO&5gu;Ci^L39u|;km;B(ZE6udIIOZ(~RQqlY6KU z(Hruuj;=ugdsfd2?obfC#;u5GFCgbE_~AP5Q#{ezGHWm8(%SHqdtnXnEclSHC4284 zx%VTwQ|#L#+w7y)r%4fBjOUsZ6(1Iq@ZG2G>~ zpHLII`xElCvqlDvSo6rZ^qRqi2xP(msvlT?3^ej&9}eYiU^mVpLD^0(C7RF&teS zyjj8CzhMQe;M-&Q-{F}Qe)dyZL5=OqB3OLox#$5ec;m2Q9^e)PKts%9@F7~8YEM1l zIZ8Z>_3~UUHAc2OOqU}j^Wb4b1w`r5@Vw6;o?_`yx#DwdGC;zi&*>S05dYs1dX@6m zp;S;EUDmMw%h+5(ydQLZ&D0MORVsTFF&MU6sjP8hQg>T;H`c`PVM%T3 z>(h;eGdD9Z+~38={F5_}BgBL7({Xw|sHXm$#WPd>fP2R$5#rb_Pcy)(ggy=&C7%I3&UPVw)gO90AEPB9_U zrT!-{*V$_=dmRa@5w^~SX!bX9Qk-akM>tOO1dGna;W|W&l2_cKtyuS({M0Qb<}AgK z1P6Ew?_PzfgT}elK*5o#qSw^-ay$^nD~cDlxe5uxU6-%*r$KVn-NI#WQ*uqppQ;du*8;ORn*FlX{1g!QRLR^xJEcQMy31l+S*I5_rP(d2IlDzG)z}kbS77y4J z;IJ%9Jy6LOelZ>Pf4yIHhu#0(FS13#E@p+BC*?9XNjw}`7&*){=^XiLlIWd;&10}` zaH#|FnTFuNXQmvIERtn%GVUZ>H(9n!MmHDB+mc07-e6XgEbgiEArsE=6l2|Fc-q4M z;hYqaL1s8JMZ}T&L-<8Jx0F36(Url~ZveUACB`ThWBsQONp9MM+eklDj*ce=TJA{| zgW?o{8;{C{X`&;|m$#*fcJ@ZM$FOuApDxCLhG%7nW&-_EktGHPxL=rzHV)f^vb;LPUkw633uVuGU}T}puP1J;8`Z6P#5GZR zx2m4FCI8ZSP`%YV>(FtwfJWb%plb9wroz_Z?WLPQ9Kcf@`JlXriOWu{IZQJC?_`%ja^&0 zq*D&wF6v^a?P&mjpWm&JBQtPI?MeGZ?0i>-0-_0hF0bOnrqbQ=fq-at)#}|SYtP&hOwvT3Fa1`s)EaIbL61wm+p zX;wmuBv<1&V=kjUEJq}{t`Tq%HYK^T#KM{K#*lb2BPwcam<S6yu ze72ZRC*|U7(Sui(PGpOwkd00#Cgpf4r62fK;9{X zvoS2z2-e`ro!aO{#O&0r1x_~bKjgu~c)Bq(!K`qnCgN-2oymb*kyiiH&yde^GK5bZ z*Jr|I1%Vw6mAv6K`OjSOFR}SGxhhw56&uyFRXD4uNTie>7lMjbhQ=bRP>+_PN#I>xVGD!;&5f;`ib$UE4(sej#z{+OKLcEK0j0=y1nRMmUE#y? z;AdRVIR7^=f%S|X@z7_+e764Awi5l5cTxt=$?F*voDpa;Y?FVdT-i#bC+|?qR~Z3b zEYe2$cgRDnLTmgLTS%Zmk@f|6C>()@GNZUZ7bAQHiJz;srb9()J>&rIn1<6nl{@{5vVw zJ5Vo2RKy1fbeH>ZJthvT26|Y&#@Y5zGdsi0JBa@f>|u5%(agH?v~{3~e^>aXPU1CZ ztsPuFM?*uZ`qb`XADVNrJKsrtK;_AwdWbxfAKX(k$K%_d7E0#$GQY8ZQ11a6bSv-w%@UJWxRoNv_ z^R~#A4G>r5Lu3Jj1x1W$>%B_Y?<~sojk#PP5MohAgdalL3hQL>d+Qqk&S*7kQ^?`p zK{gWmm2vQE6a|FM5_-mo(>uXNC{P}sC!ZWBYSW4Ew1FbssX_SVgM&mn`PsFi-!PWd z`hmt6c}^5(@`9bX@LV0TTHmO2*|ORo;*;VoV#vD-z)G+$j{z=rUlO?34Pec`GhBR~ z_{;@5hTkl@I0=L04)GQEI_*xF{%_=~cZwF*@W?c3cg3{_sRDA1u<7AnEmuBMB_&2onPbe44uli#u=Mhq)B= zAbP-lgI98xrDZcaKfy~40JO*QtZR-0fH$%;;7A1cRR)K^3>C^gLqx!bt$z_`^1u-} zYKUm!dU;O;PRuLg+iDrVv$O8S_N5wjPgi#DO$7_PSAmzmw9JqF-{081J^v?Kx=LVS zVD@OJ=x3X~WO?UM5y!UgzM-O<0C7u(itfn;`#}&kUUD#?2=B1a8S;aBL>jK3_YF|D z?;&gp^%)}L@b@^g0f&SmpPV@BhsZYv*pQqBJmBmBtmPXx_|0DG4!i@Wah%h*;i#v| zN>eIcl|ykZ_ZGvj3k#SXP6Z@q-vyO%foqZ?pKImvO8?!W|NqhFFirnqv-IAJDM4uz_$aa+;QiVp|2jB9bTz#L&!pPZkpBUp^ zho}%w1B3x&H{35e^QIGE;MljiEM_;r<(ff?N zdZb9}Qiv9!JuMs#K4grMjXKVFuM z6y4Cm&qs=DV%A6n%POfgQq7WCYmJmITD^2PeKA&~$frh$>jWg=gHfVwzvyBt4)LMy zt%X~)`5rMT<}k}91XisrRU-w}wQH_m4tQ8(UBxj_O9X}J2|?a#3-T7m=7-13G%1mK)vgEUC7rTykF=+{ph^+o! zy$_~xW4I!&vqtk&&18Itiw@9@MwB`=YETD!KQ+ieX!xN=#7Ann()-^C=3v?~`rp`7 zwNzgFn8>Qd6K7s5fLU;1hBM|dgg(9ruXs$9YV@r9=NJ*HzZw%9{Km^{CnRq49!Pqw=2mR0)^S{%2OLUARiL_ql1p*A(u5k2X)zKNUAYeMia&>#V%Jp> z8MgYEd3E|JaZtFU3iP7_5vtabe-wy8km`So75}VOGRw#Q<+z3Pj=)rW&^Xa4J}S3z z#yFAQV50D;tDg9#1O%Opj(HHOB3!_X&cyx$xpSNtlUXgk5S)=U#rMwfBBOP+2Ca?a zlY|cs6==5wCy{R?vEo72QuV9jMM-s+Tw5r5qdjv9MNV~lwiSx{F*R$(c~tGRRHu_w z=lMb`j9?|d=>(A(qg{msA{gYB38HZ|#-a)0swPHK9Y)j1%ezM30ld zOb~7Q|ICAp?Fg=P;JdS8_Fz~XvWC5jcZglc!CHWh@l?&Z**X0fKv&4Gt7k)aCWuk!k2$CK;wBo1YbFeRm>?O&xdcaN$xwtL_eM6|LxAm=dbSQtac z@pcP`@jdh<2<9zLY(7+^#L{$pF3wKf_(g@yBz13iRQ=7Nf!N}OLnhG_=zABRFj3eP zEBJVd^$C?S5mhM-szalQ-W|10;1af_=zNxNsw|r%u8bL-VzT(ar-Fo~^ zg~!Oi00*gs_MR^|aZ8LZ9X!tfnO@#P^K7`?v*HFytAOl)E&(;F97-%SLvdp`E|@0z z{>5#LqN#f)lOKnndh2wN?%vB^ZhSpCT@0le^2l^}vUB7g)5V=_W?=rn z$5Pbhf4n8b4HS_+L-VowneB(=vGM&nbBe|F@<_3WA7B-A^P!#qIsuNeQOPw~?j4&b z9*g#Z=mF%Yh>lX>g1s=nf6MT^^m^G0@#tSWhnr@IhHiV{&XK2PAgFzcOEOtL%;7Oa z;6U6xQ@rT6ofV~bkX$U2Op(_kMnzcGmOW}T8GVc)YHz4QnK%^>h*&JOx5v%gUuV`( zhEaWm)3G28df&u|c9!>Bx?EO33Za7G=sR*RY!Lvnbb@lnPF)OIn2^Y}X2J_>u zW{a*(&;A&lH%zr(RVT-GTH%-6X|n$u(a!yWwM%D?ESw`A?i9mN@DLVOc_c6aO0hxW z1%A6F2oAL1Xe+PJaJxoXo->tgC-CPn?2dwCQ3ID4^JfcN@?dGIPlLr=x z%c(eAXOY0~+H95gydn-m{a&$Hv^ADP@u|&@kUMo2lh;Ae6l3b=$l$=OJz{=Ws2rZ! z4wfVJ2a3c0xqNf6Xc)a}VEJ*Bs&UmomV9K1kXZZnmWs<@|FNC%mab9$WLn;kwUyD9 zP#vR@CpUVGDT%fBpOlJwv8dGJRnfg6HU%nDl0z87=;i9M13QmS4`9QVeCbs&2ip@m zEfqIUQ?=Xmn<7`0HijJM!53LU`p#9$tYK6v@`Ba38~H z`Rq#3Tbw*0+pJO%f$wU5_FskEz0uqy{JA>%>0FJ^`PQdC8s=7hum+Qk;+1+_bo02d z_C@1T$P*kgNJDq9>|lQi?i2bO@N-{Z0G{x-;KwcmkN;cny%&PJ{}#ObLU3H0^Eb4Y zUI^~`Tk!c8f;;~fy!b+JJqFy~9EOcS5x(?CuL; zv&%$L)|=nN1cvtE!$2^AAB3&_+sj1IKE)G5U`eGS5aNwZC$?}%-x|@#z=DgbE;7R|+|eBfL3I?s!uSRYwo` z=Y((?seM>v+xLC|oO}K*lsbtUeH1EqYc$MertW33Q=B*i8=$z&q$g zPwSsiZspbDpZ&x>4#WOMvf??`$pZxr<6s^7MAaa(`UviQ<>DqBcimLZdk)6SAIlMw zD4#E{d`n#4@W?YvVLbcK28;37WeotzDN&zS_i(tN(T|R951)76@%IzR_%-JUscxy zJp}cS*hW`%aUd7%zfN4P?oh*~OckI}xmsVe8@cn=iMHxKIgoaDt zaozuCA|6{GO9bL7HHg@;UbJm!^W#DyV7^KaxCJNhl=U}=rWZ@=0o+`5X=xp`K~&$M z72Y5^L`0uO_vZ~F&|<3kv5V+w6+ZmAd;)A?K`9g!tcf{ifIF`znM4^o` z*oV@jG_{};yEy$L<>7b4qhghijoM*dRwaQA0!xF~#EWYxo(?#21wu+zZH$3ylk2vL zS^if9JGoGIM(J6YlQcOf%a!Wn*G#o;P<){rv1lS&VPjmLH?|Tod@cyH(HW(|Av|>e+L8&Q28F zc-lg-{IpfHm_f2+Aj6ePRdU2mII8pI)}7+YW{VJYueoiP4Fqr3g~yG3=UxQq_=z9l zlkInjP@S_lJ7%p$Vc98wc+_%v|1QzNRwFQtC~jRBQjG|*4vE1Gjtkb7cG(l-W9h8i+{5G1KV~o8g|d3R&c7^`7Sm*?fpUi^e%pragl7fTMQNzKgr_V zBDo)Sm*8jf*jrVW2tx#JE4$tZFGbG@msWuv))`@kC)r`U+@KruvDZzW0dg94s`IbG zV#MJ#SPTx%i|$d+-6N)nmxZ+x{Utf%J#1G~cZsFK3IF*~eL%~-KU4shA{}C5SIyr> zjoJYMCwPVQy)W9he`oQD#{usv-xrH0Wu@TostW;D92`_G1o>Bn&+ip+dU}n+wh&rA zcIL(J?k<%L_KS=h6$<7wwF8;s!s=Waf)CLgSS>&g*)JMqs1s^#UNLYZ;Pjb}dmaZY{6iJyqY9jz<;B4Gz!F^^o~hnWY|fVIkCUo*k;PHqv7(A{-FjPjKJ z2OMT;g9GyA0ns+vTcDE%d?0#NT(eKbYJf z8Ary-CU5DX^dm?>v#~`K%cy*@`&-ta_rl1Lf;f};oEu`E0edb)$2pl zo>;4A`@>2+y^wZDDG$*VYxSV|Ia^NiDGT9Wf>+KvwpMR?UAg)JL%x*HD8f-^s8oFz zSXCQ4K^3hzd026Ni4Q^J1`qBJ1_jICQi~Lb4I#+UpAR=${|wMKcwLmff%3g|`fw20 zZ9O(QoRD{}*BjVG@{mMfb`GZ@Glh*;EsHX|CF0Fv)A)}FjTkC6jqd+Oqxv0A(8yIZ z3}{zd=Qu@ArmyP;i@rNH=<7jR)<(SnNb9;$&lF)HZ{7%Y9+IOs>Wvgl9#CTaoEo!` z`S$uoy_wi|P=2vdZz>A+N>7EJmGnfwR%cjdRjL7ioh$SPb!+kt_dh7+$%iWRe)u&^ zJ{hN^sA!zrTA>d@%_*Do{<+9Ou+)wPl>dy;!UrMM%_e~aHSm1=7Zz*cCOuocj{~cl z^cmMN6Zw)~zEl`TJgZ6PC=_T%qT1@{FSl4z-3gqdv^%6)iH-uTK=7-+_Co3egjcav z(AjYfbdPSl4~K&M6ZG(i1{i+1(`S)L$)~5Y;k?8R3lZ;kj0hAMuH34S-~YCd>o)7@ zH&uSjmpmOo=n=yLy8Hq7vuD|bz;A|E@e|`rAnhF9p&s$4O3(AJ6%iT3wU+08WnBvC z2`Q5sz){?FLblkVw`rs>!0EuojvR-hgX3pC0GM2@O7G}^?n5ag$?;oszGR_vi{7Lz zN`MZl8cYTQ0demz|9W|Ri@r5~145f%d^~f~IO})-Q8>5yU1j0l$d(OW7UEnQp7?=b zHPUOdSH!GVvy*`O$xz%V%A+ZMMX$4tr$cr5?rNWoU;7LR>uMXp3N4PWE{#I~7Qf09 zh!57%V6s{$7mM2;N`WSr|%iU^Y&yH>kF*59sYH36;QN<4nU2yY0Z zHbDCef2(lhIvgDx(DvN*Q-7Sn;w+GWoUmPQH>em;2-|MK-etRN5a6qk+REVw zIlHLR*x&U!Qs9b*@RJzmX7(^g;7*1;0 zc`D)oXbTkfAzS2yK*jt&DjX1)kh6oL0(+E7{-}@(ccAZVAo=bNy;uGs!2Qp)so@@} z&1Kh?joN^|_`KC@-D>t!d~*FR)Q{C^)amTw%SL;!XIz2cW*%h8sXO)B1Cfi1J{lrS zsVvSRJ1|MuI#7P;vL99B60{P8O zJu9Uk4)2vb3iw`jH3I!>WyUVOO+Bmm+{-gTV{9+aJ6|F1+od;%_VTn{dPgr~H|7JB zk$y93Y!Ya;wjcpz zqt)h$%-F4Wvv3!Vuf`qImq@n+ z17i*{6o^WyB_HTHJud>AfO|+3f_*rou}e?3C|tezk`x}{V+oN?Nwhm90iE(A=!y0> zI^~z@Z-x8-*0+022X$5Gl*9NHWV>wRfYxigd3k8y7>VZnGjFPrs*U zM+Zpe`+CQRmNSxb&oGiwymD7sT8pu>wp-0lGD;bBxdK))gsLtaHt3Wy6Jy$P5+7EN zRqGJB>3uyT@i*ky>~R`DPYi$izTQ>jSE?x(YYJh^vIJGJ&DuJM@m?cSHb;3YB}#Wz7c}XSqs2A4V~(Rw;#}brdCRVvnf; zC2`eA533ZgJBoClNeF(<#s z5x?ne|HfQ4*r(%{bLAJG!Pp*>L-y%y{s#D(&lT|buk}!VeXOLyFThW&VYeY%D0XIH z4&Uag5u;&;rXMdV^KFT4qjD1begR|2evfeuUz{@{6wi;*ApwsE^T@)!x2$$VMq*7mXheZTSbF)v ze!Y1EeBf7)0&oN)rrX7%4!>@$Ot;MX7{6#?1Ia5s)-RVcKh}f!*_|CnxT*WJJcE5e z%a6%GO0`LXWq^8S@rP3uW6E*x-Zte*X)D*z5*zM3*b-&RK~)fBL`*r`OMF_U+#%b3 z5+y4rZ~jE@mai;TF*x`?*J&wpyH2IdQD?}iBx2CjPcZ04#Gu!T8g!WK5LyLot3X^b z<$zu{AB?KS3cc3f*z#JIEpHmJ<^F10ewg@s<^I*Rkk5wR$&`dPd2v@C^t*>sMSr-_i<6XYSG+5OqHiU)l>47IVhN_ z%s~yIJ*gUDH--#lB&xWdEF*ztL^U~TZHVe>YI5DUP?Ia+5xpWD=B?g|a>7BqZLDT@ zL9@$k2lfAlyf*=~vaI(1_kM?cX4nVLIn1#40S*TQ0hK`p5B^9P6l>?QPmD=y~UC+CRGocOl_y7NY z|BSPr_nC+FthJuC*0Y|?CE;Xlf9aG!t2GEadBI|OA$8C3Rgrpfxy95H2hYjYqV^4* zldfXzgqyRpWvIQBQV=}>1i)1@l~MZ|(ThhcwHCEMXfd^@eVfJ9qV{_%W&qTFCv_HD zI5=ht?tQzW*MptEvn!gu59};dzRaJB?c^gtH!qS&Vgvd-n!}HO%fp`-YG{N81ruvA z;Iscpsxi(}jd6IpG#99bxXY}w&Jxc7f3;lNU-+(NoekK_tTVt~=F*UhEdBbfkM#WD zGdsWd^OQ>ysMm67;oL>R<-!>Tw-vIoV-4ur4stCi1(C7aUSca9;ePb**SI5o>TxbC z>m>J{pGF6lcC0NI?MREZs3@_OqEMpeYrluANM5Rb8;2xfu=EpPo87@Yga=$P0WZbV^8mC8*)yhw>hdHz*d=|KvdX$ih^anQ*%z5;8z!o7I3^jX-6;j-xW3NS zJr?yWUlUjPC3HJ}K$WsPEry|2Vi1Xw=lLoQP_Oq!?y<+BBVJ|${XM);*H{nLW1HZF zw01!CBu_I~#c|B7o*vG*KRpzU8S0m|8u`=5qjB!4pGHGVd)AeKsUZaboh4Ua)f)iT z@LgVSvDXGX|EV?SWB~A#d3Ck$&^I2tu}*vg>|uUJK!%75zzXm#Nli6NnH+>;K6mxrXe@R-`@a+&{Xejvb4K|E<#pekWi-{| z=_(5<;lcV}c)DCUwkEgz!oB`U^oT!lNB=e&?RuV!x=MRL*>|HADZA>LniXZ&eTeT` z6lcfeGK#A?CfBs9HMO(eZS?fuBKOFpR3=7 zq>Lq61Dvg5$HNkp5C8kbmd3uio#)N{b`j~Q%Gw+AZ>+uNl2SIijNAS5O3A&|?u9zE+*RBEjg=2S+sM!+ z6xt+2OTPJRW!>ZCYtOnFzlug30cwG}=!TD=1-+B4F?<5!(#0*RpbZ zJgTobrF#NVdrJ2NB0Z(sA>9)QIJwixRhL=0Bm4+-xUO=XwWP~)oV6_6CH>eu&v8P% z-v3ne`Tt`la@1Kmk&mvSLY?Sa{Q`=@-&cVrJ^;4=t^%KJaoZbZQc|-wr10GKlP})p z&qsEG=(jftS@+#%q7f%=r_R4`XOt0&j_>!}&=MgWAaza+e;~)6?j7 zNtSmDV?n=+%t81#@f-zpGCEhw^Y>$9`ms8FnIYq-+$legy4+QJqlHa1jQRhR@Mg{k z4=TJ#zs=M&Ff2nW7+svhfb?zZZ!4nWaqfiQMhm+86F8BB{shk5`P-;4)uySqPW5}xc&n%t4Ud%5~P_&e&W5|y%WXcYC`4|LV?=ij)&{iJt&Ujx0SB-zO9 zH=lK*pNnRv5H}uvcW_k&;3VK12*akr3xF==p#Zs*h@>3W6Cx?bN2LmkUc&tG<&%|lOFsaeEmTe-Vnw>$BhN&wUVy)oY6s|6F9H6L6nza-w{EQI zR&GV|o$7aG^Dg};P44yr{4#0B>>_#K{%@7hmt^;S&=)eBho33y6?Rc=xm)jqp-mUU zi)eICMnG3v^$(u-;KiP65C$UKO6wKtv1^6$7wT{z2q>YLG+ zIS5nJE_g;F?LsXmY`eK;W&nk6-t6v0Rh(`(u{Pf(M=d~q_h$E}KSm3JM{ag=o{tX1 zanrv(AKjSkB|`V&i(cf{C><+XrkaTtU(^tBVKdQui7%4pEq|??Wv|855@)1GjJTHw zeYZsoAZOXBO0VfBLie)%+S8+#_4gvugNe{7bzNcvY*s@eIkEdAsBS0SNzX`U?YZ8FD}AYepON4Hv18yt1CYtqike{r z!ym{};EKOibjTy!=D$V<9b2^&C{rPo9YFtFIm!u>Y=IC|RDRoVG?JpikykE=7oFr) z(kbzHIXeNb1&8cZ%egkACTQgJ|vPSE{sMCaSxO zs?9j3dZssqt=xT13nIn+6*grV^msQrjyo0^3y{j4Yeftr89|LiZcq_JTkdFjv+Y)Q zZ5&TooJtR{Xs}U3^t*1TrYTNuQ{RD9^XAJK-V@B$!z&#?uGdrh{v&W ztHOIedP9mGhmC6}%NU=FPOAu*#*qJyAF5zV6E@Y5Y>p;~dh4r91Xu)AP*yT@n!-O- z*H_4%TheiXd4~Zuh`{hjU+OSi6PWQ%AyLMTU?^L96*H9p=lT+|wmo}g!pxeZXcJ%O+=*{Mp?SJuAV8c%O} zDhyh@P4F6b^82GtA?5$``=hzpyqkStG@?|`ipEKshJfWOhAddR%SN`&+sNk4Mm8?w z*JFOpRYhhE>ttzNMCrJVATwEB6DT%^OpvT(5kRfzME;%M$!rvcdgBtQzsZ*6cV!Xc zXW!h5NZi*h!~nS7J#}HUpkqzy@!8~443zl6``ws6ClyGtj$ExbCn$%lXYws3oP_vSCZ zJ-i@WxZdIbZf;v7J_8@(o_xv8Z#XkNIT*hC1FFWdfnV*zZCeq3xZ^(~O0u(fcGrj6 z6x#f@m0?dVxGZviK0ADL_}+49X>R?;<~`?xql4TkYkqV6zlCp)vX^dt&wqqJ%;t9Z z$k)6t471)3am-zTwVO}5Al%l_vWpv_$;4!hGIhJ@mxi<3?+psA_<3fzT0v$W-0yYg zTpCWw?Y6qyHJ65?MqVZnVa@|3m)ineqPh`30Pf54qw%fSBX{ERkSlte&8Q^jeljXWOyzwN)|6~nXLPN^ngFhS|&G7Q8b}K^CX29Eth$1HN(W_$%usMj**5iJMc=B|Bdo{WHREbTd*A4qclf(P-(_adVnvdZ1Y5O;xczRI*C4Y`NICb zQ7$Q2U|GwA=AybZXL*a{XT2I$~1E9icYRjfYxxkMs_|M^@$gZPZ$>#&sD+m;&H9HDvo~+>E%#BS~zYLPdRS-Qv zVP1FS7kVcssDbkdR)Y2rpZ{qi1E(5Z@+vg?G&~2Ai#ss+kB3FP97QNGCSi8TtkDOf z$eoeKPy7Ch@oP*Fxti&)W;B!><<(0bV@pH4hf4n#pwI*hL5PgHkufQqYk@}kVbEbS zU4{?j$kCZVh+5Qtw8{cachvM4_jiR<@WR4cJzdCcYje~k-WR9^7aSRdfZ5bv|?cF0SlJC2QWFdhebF`d^ zi`}>-?B3#X1J{0Nzu#_1_sg*6HUYvos{$%g*}d7pcds_jRINpM@AwY^%YN@=YgJ)I z^Dlfxe>rXmNvI$F(2XMZiEen*svo*(w^@8e=!W`xqZ^B;K{ucVYU>WBSN8MtbU!m1 z+s~TeboS%w?2`(N#|A^K&BHa5W0$w+A;&@HhlTAuJ)WRc=SOqfZ+;ZH&-ocX!2D=L zuMizmfA9IRh+gx<*z^>o02{QTP3%8B)?-k9mNaw^qcyWcYGs!4yxGbOj9HG8yxx$Z z3AT|Nw_+iHvP5P*??Yl+x(n?WFt_o&B7mjp8JWO#S75u#oDN3G=;c`2k+hFWN>!qz zu^F#Wo&o>iX8<(oXMhS*rb{!BqJ1IZGMt#VKurCXTfo0|qko?Wdxx!iQOAQ0quT{eY>I@TMbHq^v4Aj(2`N)0huqb!5%@J+0 z?wT!jGa0Nm%LKa1&VifHK`G@5kfuTU-0dc(WnWfy``56%r5-%>o5P}xBPywu6`8Bh ziEknO@QujrF65!M5%bU|CZi=sZO0yt@p+}TWq8`eS+{69XR855Pm$jISc(VjIqm`S z>zvz*K}_?ThtM*9E_vLhtA{f(Z?rjlBXhV+K4@oTPEOIJLPk*4y_C0rBLZxc7p{oh zx--FA@w1#yL+u%Q@QAT0%z_V)#%lz`@3Qz}sfDC8jQxGF5#m`&RPYJULJ* z?knL>oxzJCQKklFpM3tKo{zLLjhav3gj>7?pn*-{w|r6DjBWX1v)xjqVzCgo39wLF zz3u#R_5Q=EFZs?6Sbxe$QNIuEtA5Y)q}}%)FV}tJfJ)YX3+}W3o(W3p_a84;zcDvf zy$=o8{ZcwVSWMQ5*Xe=K3VJ-R>cLNJqHQwI(8ZW4jiGgCa+9n3y6rIuW{^;l4_hs<2iAT;QM%PE)QL3iA7QAhCm zxTkf|@SaWYirgo^9yGKp%;g%&|Km>GYs0Z_*5r6h4ja`>{wwa;*M>{7kMVku2j7A`! z7K{2d(bGppW!ud`l{@3$+@+234~-Xxl|v43L%)U}w)}$J)KLPi8{S<0bXqrOp3Qbk0L!oYk zMks_N0|}l&h&p&dMj?b3nh<-iN>40k#d2aJ107~ewq}znqbv{%4j%HWSSKV;{?Xmh z8c}gLqLJD)p!P9-sHZH>&0aFGHuam_Orx^t)>K$&>MY5H0u!0azWE>}`=;T1h&U1p$S!6k~t7Y;e0r z#Uo2lgQGzU#%^IMceLgp643$RiyY3h8e!y5W}YB4F=0uz*rJ@^h9kf`W+l+VE^8`q zCxTD>ZOEH8rEwLDqmBHxv7;#tp=QIeMfgK}AQXoqy5|j&PVBDmwGt1}_orI`0-!=hku$F$xnc-;9b&|e){AxOMh)nwO0`O^BXDbMH~f+E!W8lDEuZo{B5zOD zWd0%0VRx`duW(yE+e#ionIJh^9IBc?$Vb36nL3-Ri_|oH ze8uv~;|1P03aQkagiSy}SR^iwFq;>j-#a$$sORS2Vepf6?uxPTm=d@6X7Pn8b~-;u zGP?QUsmDo7B%*S>2ziD?B94YagA7DMCL@*SXmx>UL=?=+iK3%3GOtJej__F`6#J0? z8r>iyOU2Q2i?MCv%nB^c9jW*P*|4Z1wgJm9IDI`i>)r9=;Jais$hpooiH(ONAA94S#DGgpvfe2 ze17xTJ=el#+QaAb)Dq`_Ofp{~^Td6yLNJsmRbeONfCQj4?}Y@lDCkz?og|YiATvLj z7EK7KtUAVTD8oXVhQ)HAl`OK%hWmjM(QVm-@pHqJ_yB$$nG#Rp=TB4OX~CmW&#w*``!{lM z!Pi}sI?EO}3scrcT5!jT29)XZ0& z8~k8L*=x}bG^5d^jHjH1fX?9|S#KJINy`dwUzjvO@cC&JV;{mlc|a9o#S6!1>GdER z2~&OUDVDpGbouPvE1H0@Fxk(z0bO?-p7I4@(rzKy>b6-(7CbX7q^pe6EreEcMrK+O z0w8XpO|pRul!_B_21?baAFShMWQG;<5Lq2itYf8!o`pJ}%x5?9AJ1LAb44c}w~Tzw zhol*!AVj~Uvt9ts15?FD^A%ZaDAX0}!zIaw9@~mf`Xnso#8MRMSqB5X|^~D=BO!oSkGCC_#rn=6NqjCx z{sL!*JU9Z+y*i!g8D-cGEG|dsE)NQk5i7hsSRKo3?}wAzw!$AT>Hq@vK>pu_?CO$M zK4fvG)4yo8LhKIeM4xWzSS4O-;K z8FLO^qw-8zTQc(8b2_2f+z~(ov~zVdu_S^HkWf^2>(R@zjKRjG%@=l#G9`SbFls%l zCEQd-X_fyYbd#^%Zmk*ZZOFH7rL-&wIvF5LIA9W_xegT)*Spj4Y4%2_NRHZ* zO~2=A;+$mDA8?DfF-rtn61Wn2VEs8N6q^lXl1%9cq>&-gA7ga6jHf9U0@K1nc<0+j zpat5Cv>z6EqHPxmaRg0fToY%YFkOboz|(Ap`Jf|E4!(oP=Mf4}i5(V{U8j(f!xI$BZT$muqJerE%V5o!I2;_`iY~JCoxtaBZ;bn9K0cjK+m%SG`$E= zw;nWjkfk+1J6buUArl6n{+H!pF})rqpS;BqIFD-v$@aAye-y66N2Nv` zTmG=MWUd9P{o$Zg)|LvZgxadDU=yZz7}%pQ+z?5A%sGiLFTW-<1!d?&36L;>;{R=W zE6|ZX7XS{4nL&6*$=SddOd?ldo{U7aXbq7UKaodpaf;yTi}0RA>o_6gmepA%Pf1`w zdok-?S|5!r39ky!wG+xu`mqIAZ^hX|-I)v!1Z4nLg-Qjj9D{7-#HboCDB*1?sr3wQ zwipXinMobd%cj0eiZC@`09_M=9RlfjwC;6%Dw&T-s(r-o0(LtSd~Uha4V2O{YLuUXT-} zkYiK8MSXUO2OfUhm*L|vF%Mg}K@FUE)a^js_EHPC z_2Zm5WX`uci#eZrs3%v)N&RVNzgU1EnhUUY1%O8(Mt* zP=9E`Jkmuo<2OvG*_a5bwZ>k(02DN@$Uo%HpBW#N0s?!I-7R$J?wc83)}nK}nOtgR z+<8-?H*#3`&Xnl1+WZI;$bV>ebV_!o`($@?6@FLeOpOkavr3X|2=2sL@#6Fv7V{ui zz!ZYLWT&OwxP4Zo8*E!hlXc^_v*MN34Xenyv2Z#bRe$6zpB^2?&%@KBb{c$gdi1Ix zH4SE(zUt=Bh+a*Oi)TbDCNT+E1T#MEY?EF|9LK2$JnmJg`ER?{{i6=X(7k{3rIXb! z){+H-Xu_DB2muI_?_(4R?LlhN30J-xXG|sn5iEWWtIwfg`$98+-U+UtKARuOE|4C^PwtlN=JjjCx-fg9yTgSC@bfblzB+j1KDYn6@F@Mh zZ(TTx=+CSRr}Oi}bzu)v@vf`FrLhOnJFf~~8_3` zDc}hBdsl}Cwf|thptY2fliW=K&SJ42%HT}@r;mrD+(So)jqc{jQLCH$sj#i5{<0yT zcum-VHFB^i%ih(PH@V9`87^w9`QGtK`gXT_@sr`|dZK-%k6aUuu72HdO?c|$avCnD zhRNMi=?=Iq{D>;lS$dQE+I3;E`nC7E@U7LaQ$7`r zs(xMYsqnZ_<#HN<)e2LjUT<(e|5P|{{6NWSM_plw7F-{0tXBB!_2KyHSNjd&>6#$x zmQ4^6vAE9!`95ELgP$P(^~??7p+ox=bUSVgC%QL(I^4f^j~kf>AlJI&ZuxZBO^*>V z<-Z3yW^S^aD*4@{x6FX`@NW0ir^Atr)roXNZVWH3_W7zC!wJ=|EjNZ|Os(w*=XaCa z4Lpih-xQuuEqv2W;Q_s;FD-0+_0#v%${v${8}e zV1HN6@~ez62rk1Q_aI;#7hrDwhH%~izEE!8g{ZU8wqBwt@Q=G;LpZ#4Dev15uJj^} zGL};92j3dLZCttbI{1h>`Dm^)YjtR*`v2uy!&B{55pk&$DgIaJKs;akukclN6-1?a zd3IK5H+y3!SCzAG3+2=NxZA=vy?o}!ZwrgyGA&&!Gk@D@m0j(|eI`81M&LUFn$tM1 z{Y?12m#_Mmjp4uAAb5*GgV?e$+%NkB_teJl zOw3Mpn?D;aUZl6Ik{2#w7$cxK-egOvVQPtzK8XnQBhwqFiEh^C!ZE=MKX=D`E_{Jn zU;X*;w9@IFLCbJ5j`q6z*3ujzWj(|%Nf!;%z#kbj>Zwv^p0dh!nU=DWhfyEd%i zn!zgme03g5(^{E6;$UkFd{74elX zgh!4z-p&g`HS~y04~@NaKJVTykR=RL0n9T=(G@9uDP;T~rWB;r!m?j{RadW}2XjOJ|xb4+037jO8-83zJq& zm5zc(Y+n1tFrOWE`zN!(q*5rBW(O<{cZ+&jSB@G{&wCJFi_ip8;*2XHc4zFCye8~$ zzy3{-@7ef^=K57xXn2sU>e>2>5fcKiY|@GHnxDVusst(Ui8XoJ-5ukyaUJR(I&iYQ z(U(fWjLa(ILI_;M85X;eY!F8AA&VE~>gpR7E@(WsY5u&qa}GN2fZ5G0Lx#?pxqp5} z>-7DmO&!)fd`eqad&h{8qehPzJ8tr%iQ^{}ik*itFWtc<*CTYd2$-fr_-XFCMJ6ws!1W`d0XaHPqIQnM>a!--ovL1%oGH z0W(-BOk(;bmD|Ebrf*WYEsSOcOTu=hZ&JC!g9cAJaPTB7YX++jQ=7g?t(>IB3 zJoc4+EEa}2eT$T9!%kbicemEDpnxs1k3g`tfe; z1L22;Vd7PZ=QM;Rn7iu%7>*YAg9pM>d&WK4=q9X=>)ZuLg^g3Z`eWrXq;FIpIb@)jK2FuyTHc(X7=9x`+P8AGS%L3rJ* zQ-*a7pWIePd6On~juXl=EM-1t^6wJvOPk|}3K3UtlIWaH2_q3v&&`Mx3eC^L1{_E8 zVk+1;NIru{%8dC72&7ZH1mw*F#+jRgd6^Fik+XKIvdzM+YT*Sazp@Cw5?#}QSO0At zC{aiM4g`aCKrIc>0Yk=q1{Uz(N_oN+{1c-%Fh3A$bs!4JvZ0@mT+D-3B9)O~g|m&+_=UO^ z#abHN*z=pSJMhLR$(9^y$?(UdoS~OY<`P&1`M8k;n6ox%(EMPD{zG5;Xh!nYtb|%4 z(ShpGQSoT8&TSF~AeLk>snH- zp%cZ7XC0D;m7T50h@&`*w4R&vtXdVFjd8Uk*QyY+chx4nIyF~@g2c1eP*6o0H}ggt zU9#@OcGi%7BORcfnBlL;NES5CmuGF@9EQ~jbw|e_HyKKMm_;#jD-$$8$jX>3smcrP zu}|kl^lVxgm0-QdtzMZPiH<2_9efa**cPa+Im6qCw9{wCIr=cyeVCz~n4#LiNG+r_ z0wJ6tbAWoA{u!ADlogzvPLPcSsvCk?#ETL)X`w<}C{Cv8vDibKw_f$Yc~KqJq^L&h z-szy6$X)SF(4MX9dCM;*Wg7%WJtw~|-?QX5b){Tl+LRP%hWln4k{3O&s3olnb0N0A z_ehi(u^bbg@PyjxE$Pwe45DE|(?K9Q=?7TiM6KW4m0gXfVJdT0I}M<$SQ07xR`;q^ zb@{2G0`7mDOW)9oC-FJOkZv?4SO#d$1mSdAlLnCH#|d6nF+%B_n)%Uk(4-#N8jY~n zj~!H*FBD=rPcw>j`7zmIsZO26RwGIPO@N)_N2jbPWJ)3BL@T_$uA%@_J_eIvv4b8FJsyH42S#cbFVvtSl^FmP8T(kS zYOtCxm#(QvMQUn#TaaRUV>f+O(*~=FGhaX zfU+2HAFRsBzRp4yk|~~u@Sp_nqt|Wru#cdp=w>|tiS%!mwzUv$wBQvz&3WlHY=adCf1BhGa5mtrpzR72r}!J- zwVhn)(?AHl0;j7aXly=E;IOwBGuT*V2J5@se|$7<>ACEajqc>V0eHhiEj_z$$@k2- zqHc`A#hC^d7)sZ`MWLw*5q;AKL~*#gHi+0Gh>#m;{sIv*J&w~VpJ|Lpcks>>#XVO8 z6~bqvcodhSH!QPDohUs#imO&R+lHqKp@k}ij!D-mfSlSY+42baGpMO+`(qGl1!rXb zwG5#=g;LWO3YJTptRXBEG*^mXx30FrzC{Fv&}wlE*u4nOV4{i*!aOx2Gb9V|jqF1U&$uRh%lRivrndpy>JX%zQYjGII!D<_kD6&MBXnDLYkCb=V{o{wByR~Nz_%i{2iy}|er4TwJmTfzC19mMcJ zo9x~oPUx6xfwVt?=JM7^#*m&mFs|%ZunfIwN3FneFUZ_P-6GJX>wP1{UeDAVZk=bp z7Bp>j$=CgDzxqVhBp|lEmsO~=XYJ~e&#)qOlK9T>uMF1lg`agpT^m&Sl9hr=oyE)p zf=~m}TE$@~TJo1du-mNj_h-Gq+LTL^VqNEb%Gky$Y_Yo?RBfg;1af*Mw@Uu8@{ zrPrhz{jce)_y^J_vEP`iU>SVBUa%dKFGk_TQrO{p8>g6O* zu^9w5{+^0v zxzKF3KAL8XzwBYHy5u419I6-PZB^AZ3 zwNoZBHZC_yMrjX}h*+au07A;lZy;U~J2#yb?aCp4||3msl3#jf|KO^edus zgI}6-*7Kg2cb2J;AR2J5BQFtB{m1sY-^IPRdg-6E z*V)$n_d1)ave!-aW1CTu0fD$(k0?n*z(<|lYJ@VU5`)3F^4*>=tGp3r=Fk`j{A$#0 zWz&236UaVgxupSwxdVw(i~giCfGk%n4RC6isdH<{KjD-uvE8ZR_yq6MIkCziG|0PH z4U14Gbs} ziKXD>Xb2tb6+8uOfVkr$e-e&)E8>rl7)+;3L?kAnZ`Slw)QNb7zNliOJCT?O&JV}{ zWq%$^Y>A+?1^lS4R>YPKJx{-TbjgYiB%#EOK(8kK`87)Jrl}3-iUTIbTMOMa$SjHW zB8euS6Fn*S3X$TmAVL#Na<8VBV6w5;NWW~HJs0h1FNw$T^X&OAU{rQECZDwHMVPW{ z5p)|@rsp!rc?OLv6y9bL0DOyVYR^Ub%+FaZF>k0Om+&SC;#i&e$~J#^S>^Z!OM_W{ zvL$Og%{VS9CwGUE2&R^S<0KRdB>sD_DyWm7P{&aiVgZD#wKEKsK?Yb+!JOM&7)9j- z7|HLkXVY@jA43K^$8ujOErxx!<$22Tgm3q?q?x=7yj+dX;yY+VN;{bZMHEd8&a@!} z7(u!J5&V0&9lOWExVd^-7Q(9c2YWvI+EJJumAT*sfjC#7Dj<$57Z4YKH?v*9%(j}% z9?aeGH;2=8qnNI1Xl4aBAFcaO*LAsj^o7!zPdr6 z94B1}*<%mVcwg%U(gxAS{&&^`(;dfgD^QpafRJ!21!hAfTucT);BmQiw1R_LMl$z) zXhD6nZRX`9_2N<{m3sG6b}<4;%v#h^B(2sS)>~KXb_?ntqLYdK7VYrPuXyyLZc}r3 zE9$ZjF8E>ibTveq1l~4EZXyYH`NB;~>HrehtL6P}hw4JJFricoY_K-Nn-${<_%VYT zj~p8eYO>8eg)7>|^+PT69@+NUa&FSx^Vka=?yJuP>v6>Pz|9O}h&65;Aq{E8H;mfkBqR;N1rE`W8yBBoWv7JvFEHntKmfqz5z zSKwbU>}mbc9Dpw+KnSP|r$D=Md;;K2tmM zS_US90r#O$As5c+5*{OjIR zp?!YOle-6?hTsL@{449xPcTwByz;7LUhxw=^2K#Jq4#EA46oVX{9-}(+Qa1bFKo^5 z;X4& z8iyu>-Cqy|@po7ylO2k^SS13sf(Yc}KF2UV>dPNdVW>r)h1diCI~>Le409RRL{zHGNy>szEB*eDWg&JsYUaq*lRPn2ea9+r45>3 zUH8K48eNpUnlYF zZz}gy@$}utmsH?R4I-OY0??Wkz^GAciP_rctI6;!T2pSurEsb;jZH~9i~0hyq&0x* zTC_R*eCoQ3pNzwl!M4q)!%Ji-v>$$s`6g|*LlcP?6g!pYydrx>-EU_BTcmQeuMi}v zh~)X(v1^R1-&~dO%^=$AwQQB$ImQ>BpyNSW4aEH|zLc<7?P6C-@s_GOFhm?=T1wqW zR`HzuWGQdKjh>Ep5+XiI{6`T^kGr@cif(sZ*e)+F9*KGs(ierQabK&XPf|kBS{b#R zYbvdsAFK$=bTU)g(EN_9PeIK>xDJ- z<2(=C>SrV^Z`~;uZS+NhL5j-BYjr&PSy8;P`DP&mUj939v&?tDvgM+qeNkM94cKEA zxTfg5UOmp0yepkGTo2>ZnZMR$%g#yr8ZLbWf|6_vc5%c>$rFgE!Kwjz2=l?b+d8S5n; zD}os+F&=Y*JSs6ByMkY)zE;W}p;uls;x9-DAT>}F`dl5S_*0lt*vOLQ5jv+9)PU{VdsS0b2ormQAM zw<73hrHf5w3c@~D6Zum@ETZhwcFs@SevQfOfx=Zq!c zTvnKrJa~v#9K;Bkrxd%yD{;>n*N5~SFAm&{>OXaCzw6;TMU3-qeSLO%sjtm~)M}8* zfov8k5@gAW#ZC4-Ui&x(T+3v8oCkHvo$VV=flCYAnv^p5xf*qNKU7@h5zSm9n;#3i z4_jSc?Gbd7_N%KsqVH;tVE2#%$V^vzg!WkNYRhkQiTTi+r>o53^;%^X)fO2jutjFE zZIOY7ffgB{c!i6MJ2_kA66|H|D#OJMXL0Il*V&dCM9Wb#UFw`Bk0U)78qIZwUv9;L zy|wJ-)l%C=0qq*?s_QW`@k^h_2ve89qo$I|Qx8XQ4kMg8LGK6*QmYoFnfK;GV^yUu zO(ziIV@!}uFqL1I1Ky`jgJ_f;tPu?Pv-g7@W~1aO;66?srwT0S5=>%Y~ya1(6>#9@PQ~M)b&@^Op=e;rY+)9L~A1u`v9|F`fJ- z(J}mPT)HcBVP`jvFOHKhl;MT$^~E-(y5;bb?bzUlZ7u?IbrEkIR>H0*A)3&ohWbJq zoMb&vmgh#Mc8v(Nwh42g_Pu_BH3GE>jn%s!uZ(#SgB+FXn)QI7O!zg-^!_`iO!+P4 znkCp*W=QqY9pbk`hy#Nm57x{UN()UDi`)pnY6f&vHF*y8?G6z3LWG|Pid}#TEP$Ae ztVw1#e66cdr<=4<>LZ)nysFz&kX2`r zCpgw=W-4>COA#q%wx!rph8+|4RG_9HNHGCBZexr+NTk^xU(hGhJ&{Te0e@6%Pojnpuu}vQkN@P&*16L_|oQ3lnB(04ICzOq&SF%pG$U5jdCjf~Ovw2)T z(V(!29DXw;#V%2NGb!XWKP1Rxf%LAWJngnB|2htG?0reOu|Qxi7WjnFRqH;Hx;c`h z`N40bVLpvP?>@7y*BJ-lJm^ZZo1)Pv{1OIhqHvy`&yZKgLvZQP_V|zOgB;nP_fu;lvkkR>80W+VVu8#+6FL}pEjtD zM=cG|0lV|!JFu*FF#RqJRIUWv9iVW-%(i+-U<(voSIH|`wp#>en)Dh$^^!r5e1z>E zBpYk)7+h&Fch$sPYccoM#N2E#U-dDijOG{TiZ;Je>w>7kvE?fb{VywMlmiUjZuR)V z@5^3r|6VJ(AFR_rmDxR@m#=JQugX+tfR0TiTC@P58=zylsUTV$B(r)|rcwh`*1gZl zDs|27RhJ44P}daIRT{KsmC6q2Rhdc+P+8Y2>)3(4>Y@-g9{OKAnf%HsJE&J>Dl|Y{ zllEO#sXYC2dR3-U15`F~-<6f?n%k=`6&j$fPLZ%xCEe5j_sB{S2>E_s=S1A#dy{0$ z&{8KYXaX%0Oqe3YL>f9HBi9K)Wl(7H2<>ydT{J9~b{AR+2bFpPWu{?tIb9GiTE+U~ z6!em8A}2V3gr>?Z$3uY%(-z24by>|^2`W}6V4r&I>IM!CaSVdu7A`o}HvRy5Y_&AN ztZ^{1-Bipmd-;?BFrs5BpeFb9Q^Cl(2GeXb^pviXVx!63&|rq3HWZ{IlDH=1il(Rs-14DaL|dSrP$*|k;4R&*n>Sf`1)#GP|g zIDDGbA-(`ffpH7e0hjHih$2k7(ZO;S>s)qxG#rh%2Go)c$dr(cDAq=jkPeC^uj%V> z4GJbeeevYEF}?1AwpHH5YdHayy-vip?|`imqyA{#E4)!UO0_2#fvdzlptQ=ipM*A`w3F3?;erfb70r5AYE z$;@_T?Zu_|k01%~c4^RHcYFqchK^bw9{?U$;{Q=7r~(1@TZ3F_!Eta66ll2zfP(Sm zflmM$ICrhe^2;^TOR{>b&dOtlDNd`liF*NxaCR`9;$s(TTN1D$fQk)N@71t5DS>-0_o?`mqRk1*)3F(*`7^UM)hNJ|YSGOpQM@UQV4BGO)*|c zAPMb|@1i`$l&6ZP6iCu7FPq`!nk3#^APMQHPZG8$m*PB?*TDmz2y2q%RiN zq=9-V2BGjta`{lMknP5b{;{ozU+kknQFX)Fby1{PFZV zT(bPgt>et=tp z4h5rou~v*UN7t!Kxlqb4LXxZ!&& zTk)#5t1CJ>^{Us$dH97>qYvUHE}9n29Od1_H3CSi0aGsFWER&ok^AekXvzc@O-vP1 zPvA+CC%L&qdmWR%?Q+3UvX-_%7uF8JcP(Hrn;bK2ZU&kA2WH=5KglTaC|bY?V71+I+Y<;cD5 zxac7UbQuGo(qu!{m&2!)ATVHgtCBE_GX!=ymgFQn%9C%8)#i3@B&pdg*Af?7< z-iBcF0at|cv)PN>AO9^nYX5DwZH4vVD4IVH@owr^Mc;iKtB9e=Z**t>dvw?^7ER)@ zAVI-%CO>!H;r{jN=zs=9`bY42;~nmbk3^FiX37sSmribX4__Va7jAfAtNZKK(P_cs zfjjmJ=4iXS_PS_%w%grv9qv%|`0``d!Hb>0`8S{ByOWw79xL_+ZisJwMP2?HBC0;~!a?VQReh(zs+zpVkEsw7zCd zbZ`J*011=avumQd;A5Ly({<5_e;YLPX>vDDFZ3BOXEF`=JD(Fs9vpo0a~>8C^su<@ zbA1N<Z!M*o^fHKpxH_q1S-7h_?peN_IcnJe&GfYOQZLZec z=}OmQ9w@|^JQz<7ejT{!_r>#q{C0Q4gRvoxMK?qf!jIf#$YZj*_=czmzI^uKxN}_D zp*svda#cS#l(qrafAZ(MuiO`p+q~*q@krs((Kklp5ATgB=nkFyR1inXGvrlYcsZ zN>-zK`bS;SKkDNaU$e6Pa| z0YAqTq01>E*1X*L&{p@%Ez$Ryer%jnHc2t_o2J{$Qck>q3VNiBpEtVV{UZ}Qi4Qcr z?xYRTd?QX_U*ZHnWZbPAqA^w>ubaW8l&=O-K|}>!ZN=>uNt{xA|D#)@|20W|)D58J z?q6rHJ-<|hfAK@Ko#T&t_)Z?2TXTCY3rU4665-()gXI@TchfhE?f{8+c??LnQ< z>eJs5bhMx6pYTaDet%yXIW1Lc{NBDYa(1d@d}Pp!(RrMtszd5O0}oo!ni&|n&+J?J zW*@T8?05Ff-m=f^*Z0ldT$8=nZ#mZX$?oQEj1CD`|MGsPSRauyP0^C z9@(mEwqARlGN+r5IX$|yy>4SR$d;lD-P6Tz@mo0&a*Y(WoS!`A4*ZNnyw2fe#Zoha z%jl;-1WMbS)HkewUT8yyue)`enu*jQ8dSH0&&=dM&1O&S+4#CqazFa))4@pnHaru|Cw9z< zo!R|+4mojTcK^*6J`>!Ubxog(Cp7(D#6=?6rf1!p&&9LG1Q#Z|FMfbtWR8O{CVPDt z)4V+wyAOUY?k*8g$W9HrJBQG5%j+Fo5?5&AW`xdNe(3VE-kC|RzsSySg=}G{O6*Yu zLziYR&}3va>^wUrwFA01U9tttItb2Cu#`=<6W-rPb2%xo%fGmy zAjoM=neQez%LnfyINJvyI0>gaWe~wVzz4a$k-%6h_IiT&HC6B$f*3a_xR&4?A6!GQ zG}nhOCp^yw(S^v0LYXB=neT%yU6d|Js6|QSfmKV*i#+eq=$UuFS3lF$qa-x6rACuCUM%gkJoTYC4F}HhyRE`&E9Y z^ZVcYcJs@$P2%Tr+@tFHwA|dgrn}t zi(|~dUoXMTdcS1H7qJ=WmQbXS;XZe=WdqS%Bv0=7Ac5!j%D*qu^d)!b!tjjXh0t9w zD}1}FUxXw1yWGs#;U@RuqVTrh7t!Y17Kf{I*+00|^TRH8@?l|z-d;e$jj+Pqad+H4 zydnl*eZ))e`T=~~L-C=;(2n|IJSF>GcgA(m!dG_C@58~1LG9B_r*GyHJOA0uY`r&b zYi2ZN0hHWL{g2%n9~pc%6gw_C#XIhcC8rSIJz|#;jQJw3Dc>!9()pX=xJ_sQvpsfr zFWi?hY8U-BI6C|?y#9{g2CoZm7t{YzFxegbyTH%bM}HSgppn~u7jzj(eD*KFc!VKC zUI@ktuU_#$Jer^Ve;?@Q$lp`P)i3^YDjW5Da6#q1qFv?(H<6nZ2uXsdfyhvr+ zspFm(gJY~#dNVmc3-zdWC)Nx20`^UuX|;dmrC=VlKk-sJUoC&N`I`P$rm@<`biQu? znr83HYeU}#OYrIz$a7k+#z5D{yLV;7W#JF_dgY6O^iRwe2oOT>jBDN&ziqgXo%Xh> z7qZ*?#jWn?t#P+Ids{p`+|8FQ{g1c6H66b-?wUkiY-NMQ@BlJhSp#vlc|mv}mCx6^ zZ*AkfnE$mkp5lJ7Egl;D{EKer)_DFTz4qptx`?K{k4jy-D+ftD)9wCx+`(k!|2y`; zRrm%Feg5XN?~ezaEVt>K@wjw!yKQt&+vtXAbo*5Ych{HxZyOvJS<5T8`~S0pV+%a= z&3L>-fgZ16mo08|#~=D|qkl0p*I(-J>p!GYhu~ZB-z#-6q+XRz4uI6HSLC3v-n8Q{ ze*^6>rnf4IR5O{TL6}~K+l%R4^T%|U-+K6O80G*>@4S9YZ__RHp6}l4g+P+8B7ydAw z>K1)3K4#2z$dN=GaM9htbgu4zKDse=j(uSk`UVkBxn(o$?Xc z^BuE2Zu5yh0Wq^zIW~=*SY{h~P5M|^Q@rscPdqI~&Ly9XN5%?{amgvsh}=C2xBBo6 z&k!E%!{1W;2p_&e@p%h(d|BaEK+hgf$E>L}lWF>cJNVRSc5u_r-8)Z>W@fM4e9fs* zL(uZ2Y)c?3dU}xmvisbdq7}i{GH%?Pqw&M9hmjN$8%TpWou73Z+-u$(jp7i0=9{C5 z!>)v!=|)6kdb9e3s;_->^uGNr<;+au+2jL{Z9%5UIW1gatUt%MmH7|q@;V0rNa@p& zOHK}t&PMK|Cx`n_!H7m$HvMQiGMy01<+8uQ5Sh?>xs?$dUI^WzCx_!=%;xiZ+>0lN zo!QV8P6<2f(XV1;Px`A*;n?}{(7p4NaMbJMG?J2mc1y5~rh{eYNQhV9f~oAl{2TM| zcWDR_F*}Re@z3u~=y}jg>SmZ?vg5U@Cv-nNC7f5XnxiFB=~kGFw zyY49XAh(Uuk#bRjlM6Rj8tu0c5oi{5rJn$4d>A^#d;sHgx#eT2n4Lo1F&&H|gEf>c zK45T=6VuMA**$P-*b}S`-ASi~Q#!c3jKzVJ%RF0U_v<4bly+C17ETYY4BZ2#g$F9{ z^QVQg+t+eMAVK74*)6lO9`dGe1Ba3)-xU6I?4LuOSC+6Ea)(I1-H2ULovz6LIdngJ zb9j8f@0`=aITToVdbs?wY`{YWc1~fox$Gd>ie0GAnc`n-fW|J3Mfg&;{2U^9;1#T< zd)Ib}0iEZv7So&qIl9uD7I1|#!uDZ%m{=>vi;2FRn|nq$@tw47j-*ut*k+oF*>H&h zE7KI3cegGKj63S%mf|NJx&G#TRZ?s((ti8v5 z_LOK$?&@D{$t0oTM#jG+2#~XhgQtG!7AtwRlAA0py#7~PT=A4>bneib+#Syx z_T24Y1=&k*6XE$QI3s@Fy>)l|*8{#z*y1OwNOoAf*wljFpkx-B^VdYl<#&*!j>%j7 zaVxj>v3O4K$KCGXe+kBfJ9y;dmyg9=V7UCx;*MbN6|Vbd@tmC1wadNrXYt{|EkAc_ z-p7;g_x&tx3wG{y$3M$Mkk9-qZl9R8uD1xwt(ThvzI->k9*+-HbEiBWj|+CJauZ%1 zj%ov@StFLmFz4#)>0!>DRR}s%Z>xLg@p#De%Fqy;WRvGVrOq>|0%$Ftd{jly79?v4 zFd6kv_*ND_QE8>!z4L;&KDhDY?zC5jBZr!8d)DqSWR^Ew=N8V*9T;rSxcAJ>bsM40 z{ygqzdg|V-f*FbA-IwR)#=G|)5|3#8M7C)N5GAmp2l+2%-PU=zBg&akyr1W8_<8)c z!KJCsjWGG-MVn(lhb+0c(El{ysGWLznEM<_Xr>HQRJ-!AOBgHrGW>7QJ@s zRyY0Gc;YK=Y3<-GO>$HA#zXUukfXLGx8nWr{2^j*m~nfjuIWUV{Y^Y!-Va%Q|G=Si zIU+Nr%gH2@1Wv+g-9aIZny!mAmVS&Co;z6K?x369qRRMxD}p;KWL6qG80>R<Y;AF8{w|(yWbf?4hJH>oQsYB=jr8GRUdbr$t*MgH z%yy;Y-toJ5RJa{>>8anv2V!thcrKpMh=xwI3@+In^;|qHl%nmt=i&oq-LxJ2B{gKQ zB)OBY`ZcT5v~}}4qoz;%rB?I!;1%`^;2#zx{oDTEis|QDaVu z&6EBRZx5ch&vpJWo;mBOpd}kD5nG^}p!&NZ+e@=qiS)WnchMi?;Umgw&q`vd(!A}D z@f>uSkNq(|pPy5okC(k&z$dSB5SK>TAZfg*?G3s+&etz|g^rb9H3IPbi>ZNlBX#F= zbfNs5$=(?S_VRj8&gF_ciy3JKHqdjn{3-q%CPiER6ra@MO-e-QQ^n;dcgUaP9?#~> zu1!-z@l{eXnyr{OcJpz#R<=_M22jvaQ-(JDCH`^t$Ey4Uckl~wlf4{91^+^K{p*i> zNC(Q#ECUb%ZT>rtCiI*a;`wv*18z0y{Wh`{V9ziz7!>iX&ZA#nAD3WXL-r`3lq`vk_dVY?Z@auTgfDQ1f ztvl}5@zQYBXKrv;{u(ju8h7un<79a6v9OmIOzTr|VZo*1*+U87Xa$B{ck_H7`0yI% zFuDE~uW=5O5&mvd{=-qmDwExtatI{r%b40q0d#vjctblJ<|&g>bRCtVib zn{D%#!Ruv(pT1d)?ceV|9A8>Z0yw>^1z_HN>?83*?x@@1JA$1b+x)_9@#bv(^LrRq z6UUJ+Z$t#S$bElfyr3hE#3qdnqP(?dMJKzi+vBcsfw#KX-5#Gnht}U7Po#U_ygmMs z`U9lY>uLA&tVp9*-4Q=hNztVQzu8E+Xj6QOd*5N7(uKW4}8 z&;DrhA7=y9*st)Uggcu1H@vtali~(xNjX8ziE~*ioayh zbW`3FtsM}pNJl5raIFS|B-itY9*KONa!~xeMi6T~cS&aD&)U3TPP{0a-R1t*-1s9E z3&dEcO(;#C0L%h$+&n<+QMY7XJi0?|a=Dzd5>A;4P52{Tk$*IBXU&VdhHH-%b>!u_ z4PnXTLyx&z=fQvo85I-UN}Lzx)iuK~dD-OZn` zs&0~1G{4t-Bqz5UL)ak=2O~}jHt^`P4D3+_g-G|J+p%LBYfeGvJkWZPAYrz=@=H7I_g8=u4zTOagYScAq14IDqM~XP z=dL0+D4FCRLRQ`NMPmk=(~}@5$(?;d*begg&a=J=+wD0xlC5L;ABM$j@`wjSM1%@q=K(11Oyh7rCWsU^^{E1k{Exz9Z-qN| zk1vheM(R6JyNEQC>$OAf{t&=&iyQi?c;Teo^ki;;U61TgrhC@+b$qQO&)ncRLf_7~ zcfBe;v~w4elm8-yLCHO`h`?M(4|OD;`5+&=1flP9-+oox*}Fy!$iw^T)w#&rv-vsC7O-8P`+)n{VR3tD-9=^#)EO-;oxq;f zC*D%M@lLcfa{|+q+H7q4Pr4=ENR`O#C7Zdz?+0ne!0eviN7hb$Z?Fu%f4vH`rC`M| zmx9KabyV_PsirOy|AyWWK|oVeIX6AZ8@*D$-{>-kuH#4vV2PJ+y82x~M=7V#Z}D7_ zpn@sreQwYhNQAqolx*=JV7~?wKu@yGN5YybWcQzv?P(l{MRDtPiSeKreJBL*Q6+q; ziBTj&VbhvBC4=>34^zw56L3bhK@?NUaMRjua6hG)2xScOq(Z9#2zv6kf>~a4Odch) z^dfl-na9_6dwqSg*VhBRzP{Y+>+`+7Zu5P(TF|tpeZS~P9(RRy*!@Q zQ~1%yQZiaR;t(cm2&u`=m$qhRX2j_5ok!Tp_f+qSVhGEhY_I*^QvJ}bOAQUwqwoke z4?xH^)lYXK{9{Aa2F)(azJ?#p!I_ejlSAmlOQF!o$d;^r#ul|%S#ZAx!;|>hglt}$ z6SFfO4PXrX4h=5En;me%eY(gn($w&7-QZiAY3l4KQ@($plX|cS*&1Z1S?fl5j~Oi^fNYPq{gV6nySe z$zg>=7`lU#IytUe2Mru%fXY2`*ajcyW^^B$|1jWbP!!wAw;ZX`0;Y*LidPrrl+_Iod3r-9)~ zQdj|0r0S+(&D>A}=d41L7L+U{^6+SuPR&g#^LV|>6qHQk>$08MF`Zm4Ii2nW=a9X_ z&J@U6K&N8>zU&zDa~GM7Gni ztV1Qc$IEO&-B(7u1x-@lYFn^%3aL_8VT~O&4o>PF3D5ccr|eH<@vPr0#~y#6w(s3;jqIgD7%?d!~&tm(wBz_J^23L+`S2y9aWkCf2-==>b-N5 z?sRv$J4xM}ovdsLBrK`01Y~zXltmC7Apr%y8 zQP!g1+JQU%>&)*kdP5SodmM}Keai4OAn6FlHm?*qfBYbi;x!df1`pyQ5&>yM=x5;| zial{Z8lX-*$@Q1aGs3X_n8FX}qq-YyGcvAphUv}mP!f~|8jXXg7Y!|1*UJK)+%eju z%yX$PbFe`X{;AM5JWav}lv^a=NSkHnt7UB?v%!#fMNTjBlPi0@1H6_b{zZVt06p-* z7GRwm-m&$WNk7fJLKRl`C3`R1mQ=Iqh}RDWIIFaJfJ}$OYW1Mz3^V`yNXk?Ql*>PV zLu;&!aDqIIpU`Sb-mKOCq6c;sfnN)E!o)NGd8}q zFlLg*+@dkHyzJ05P}a#y*1oT&VcX&bos zA>vt%y2_|$UI1$cj|xjloqBR^h3e)I1}FeOY_DNBdvRr?aE513g5xb$3jAc@gTY=% zY)eLBb$F>)FkOGR79y4`#@%K$PDh_%_17+GpsK$xm@{atlDl09BNwP=JEV@``>gaQ z70nnD1b8*Lz_o;2K^*0)bs=#OL;cm5yDf(Ht1+92sr7b?r85GTF7u_m>@bi~arhQ9 zD0}rg%YoM`*jea)Y-iblZZ5{-)E*nay@_Zb2aeFLDjTAZRfc{Pn7`~5pFmq(R&=+V zRT$S57#08$8MfP?p~C{WmRt&L4h##-Zo~ow+YK#p18f)oR?{$mb~bO^fCN5rMq$?9 zh6E68SV1AaK2vxNg96U-j2B@Mi$i$5M$53*n_HC}{E<=_pF{|04wlqOK-v=VE@Yiz z5v?CDFzCXUKx@b^YroZ9@FH@ThisZ^e^71J_jOw&V6icay)IRcN9&Jy)#5t2Z~oE=Bnex2MW(bjVJ#o$UXvLeJRs)SA_g zxfs3dZz5g>f6nYxVmYp8OK#wlj9O@x~n^hFoggxX>0fgEVbl z^0$us2s|K7Ow;RMkD16DY^_k}&dEhNrx%)}axrNdg9Az(C3d}N#F}Bfg zcC0n8xckYe=N9_s>69eD42-#yiG#_;TOygu>;v!8R2cFXx_{)vj_^jVLLyXr{@lXY zp1ZuVdGa2%GoGg6u6^u`IpbmL*x9h8^_#<7TGGW*n7sMCLjS3#LS-2yx`AIpls}j| zVev(XZx zTN@J71iCU^8P{D|U9Z$0q$34(ZCo$ST+hLWG*C8t7=l-vjj|4I)=jpicD-Im96jn* zkIc;$6W$2K@T;lcEqNX{nRYiu=AxbeUDU2A(9n5BfJd8;A1F$|l)e#Z#mT+6F>@j@ z50Z$9MO)C+?=LL=muE=E*a=V!on(4clja0;eiABz5pDA2hhZIDBy5T>9qNXt{T<81 zKhRTTec{!1lzb#tU~%mUKXzFT1(U!;6k-e1c2Vw)Opb_^MyzS-U1S%*xfdh9V)iDy zg?`5*u#d&S0>JzbNczi`9LzMrz4L=!g8Sib+2~O(E4=P_corT_rcM)(=(`>Wl&OZH zi-zf!%7*E0()829aXbiS_64jksw?ag%?+9Xq-KSY+MF;HI3s$7F+Q_hm*V1$c_mX? zy}7H)>=vXF(=Y_LUc`1u0gkT$900hB_&TI#%UisQ(A^J#JmU46g^s8n-O& zXyMXK$IG?yDyt`UWvaWrzYiQGIjr0Yb5a_Ww7sJ+P_!eAL*O`j)|I<2 zEw?3e-%&Wd+#2H%MWY!2U4e&_x?86WaCBzI zgsD+mvi5>PU%wx)bx_!sw84#|YNce8S{uBeFm@E`5JRlN<4 zROxHfx+EI24(o=?N{cdml91UBa33oajOO)E_HD+)jyg|FxNkt9{ce!n3i_d zQ`wD~U@o-V=%OSJxJ*`5{DNc9U{Ep+t>TPgN!qDLPG1d=wv)FqQey@&=z?^N!=;P` zPVCB*`IuBM3LFGc`+G=IANBGDAz6~Kn|p?VvPtYVw{{y^76$xstlA2|=Ra-2i|&RF zM33#Bk)iHVfZ|kCjy=QKo94h?g#pDaT5devGi;-ZW_0FkBafkI*rKz1p605%lERAmof zBh^2^3-+KnV-G6EANVPI;E6q;9f&Rfr$cd5x!lOBL{I(qy|z1Z&h82)Hb$4NHCJSa zB6lq9jg=ZXC zmg3@_V!&3(BQJ}z%iog@;1M~c19)WSe0y&=Uym!$F&cdtHUm9ui{tqK?keqndCr4D zzZBz9S)Fkn9=b;O^H#x+1|E%22*bB!|*>do!*nxhGuhv-L#cKO#0Z|8w1B_>j@ay!jk0OGWf#?K&jFL*3y1w z-)WuL2H<_Fgp)nKMEyd*;KDm5RQS_;_yd@*Y?zzbmW>g^vW+?zhp!x-b*8&6u-PQ5~7lw z;tQ&1#tEJ^J&DkgAtm9SqNtIkTkmYtAs;ByUXhQxOX28(w{PTw=aUrqaFn|b61;3ST`@zXZu#u_8o2n0U%K0`EC`~?UDGdXE5fk>eo62xQ`ud+Mt0POG-cM5j!L znCX<9Vhv1_Ud@tpu$-f?X05lZ2czUG%L)@O>Qs=4ddlJmY%|s#e!SU4KVlwEm6=;I zE$g1DSGS_z)@(`lippPsiq-RyJO3WDWw)#tj6h@>&N1oF25>aT7#w}(;P9{y-o$rRSC<6V%f2*rfzo9u2YX2Cj_TFPYQ+KJT3M$6J}P1E2I zqx{SqmqK|K5KA#G$V>~?!|Lg|ckXsmiiOQe-JntZV`}P1OPJ$ta*Ro4ElSX{9idL#bU8+t9nZs>8Qs~dXhjlGsg0#}q@8W&Cy__4U5_C5nklA*$^!F$Q6 z_q4KXUY5-V-kupM9OT`X^juk(aGbMGk4&2KyTNLke(35uuKE@GEs9!TNB+IP+E!#JlQ}RAqa-d=s!LaeKuhwNgb(T1`ycO43~q zDJl8rRfWAcXgK?0g}YmKtR#ot$ZSnEPWJjX&HJaqD&Jd_Jam0w%)$SuJGIVR%4nwl zPqm+2{7jy`7nn7By-t39J^h)Cxq%C(i;}}{D2zGUd5f?-+IUxyC%vRQlAmj8HMH~d zGqs;`SFZ{ARNzqe@Jf>i~7rW&JXOxoO>*M6iB+Ya@v#hU7BKUgvUtr$9( zT<~%0(RCj$jA_13C7X!6(?$M($Vyt>`L4PJQeu8p`SQgyYQCb>A$p%i9SS#X?mBoS zb{44{8VVfJ77b>pa&PpRhO+b8qS0CEevv;VzOA9~+_q>SO9pmqp44!%@}CPm&6;<{ zetz-=ehsW@D0!gznGW&%R3|K6;D%VtMYVG z(%(|EY>f*FTM#qNuciG-|S<{=>DIMom&w+UGQCqN374rcsp%ic9Ar zjYIiYoxC&(snd_s*-oP(MWxG;M%fc;>7u1kyr<>cZmK~v?`Tz*eaTxKSYq()XMmEH z3n|YK4U*=zm9jGzjvQo-RBYa`GfmR`jq87?Nfz8uFAjjQ-$w#pO+pF%+JZi zJo1xQd}h-LYw!-k{q&1(Doh^yIYek?j!Ve;w3KGMZ07GKPQG{(n)LIMtv69)ocx>n z)p@i1ntrpTo#=jD=zjg9`?b#f+Twowl3!Fux>Eygy3emV)9yYM@Ol!z<3wapJ=3A`yKXt$U?0yZb zwY0<5TH2f3uPfZI#QnP4{d$~VbuGu)VY zN7i!8ceO02&*NqU`aic8&NZh7tzylQG~0|v!7gmml-mo%n!f{B zW#@W;YxA26$?@MlZuFxOc@SFRR zl6+(R^m&-OG0r#EHx(Z5!r%Q(Eq<-y$2rei-$)Av8wkj|Rj{H%++RmR} zphVe~So?3T&F~wFOsn}hh18MoW<`#5ZT>{zNfz$;v)Yf~UFu!&eQMK>pZ1GhfU-Dw z{%8Iq@1K+6c7KBZd%UM@_aDc5TH7=Jgej@Fm?q8#;|3{CiWsr`(#K#;cltB_=H3rU zwE7DM;-{E?Uw5{=;)n8^X8zoNo7Z;Ni|_&30Jxc2^9%oD-aC`&&*J5La&qw#IPiTg z`KM#Oa~g8J@t6KX-VMowU-@@2?=cpOO7?mum5>L za8Ud2?RJ5bCbx`C7A^=*Nj^9y7@0Z%zX|BtG-vm);LPu z69nT6oZk7BWbI0?JJ}cn`{7#X$sjne{TH+xS8&%C@3=PU&j+QDQt`%rOyYbn&ig=e zUOt#IIm-l>eC@ZT9)g=68c~^4;U`FzJOzqCzH?fXhheXTk8fG2+@^0>o0ddb4p;M@f|)RPeguk+$B*uDyrNY_6R{$BQ(N#oCVgUi zFq6+~+k@}&8SDsV@j0O*__7n6v%MkDEghY~SZ{eUy_0J|^$wqk-_t6`yRS;l>*SjL zL&-mM2IJ0Ta5>W{#yB+Gj$&q-yXC5Dsqs(he{&1=2lc;MsqfbRzPI+n$HJqSBs)8U zbL4JW?oQ%^Oh4(x%XcK_jtH*e(Y{}d2-*XG+fS38RK6|87F26aq z78iow&z~mCx`Ov8?{B+;0e#!LgMNLdbO$r_J-s`aqHm=;cr4YKGVjRPTBhXu(ZNzC z?E9mG1JEODPfSsF-1)3^j1{{?D>&7^$dr6j41LgVbPmvp#>tUhqkeL9LR>#NI-9MZ zoFJ}Ej$~t-oojpQW(Q|EKo##eJeT}ePq3s@zvxS9HJ`kzH<;3w>Xg~%fXjwLi2nt@i5!Lh77T{vNEFj?Psj}1;4J6W@4?x6TmuQ*_=CIXbBRQ9v6 z!9W*N`^~^_;?)(0knm=dbc_oIE3~bvF*5G~gKBfLXPx1deNbxJoe+Pa_Ppa!bR;61 z4}(;F^D^quN}4wa%o5txU0RZQ$~n7ek)P49iulK=HZ$|+9MJ-F% zf#vq7<3r^(jsr2+xqiDprlN!VHZB{<9&nL&&DD$Q%zsbS^%u_LfVwgUG|e<9uCVP2 zq<}UZueDuGm$)&vj)T$&n~vs7vEZ!QrP@&ngAQX1ZkAe#RB22>YC?prY?7>0oi9V# zoH<`{o-Ck2ZCWXI6>o!|JuaA7xmILAX;N9p_F+WbM*BqIw^pYf+Ya`Y2^#7;jS3hT zi!;4{$%zg$(H+%^Zi+gXXq}@T>t-6iRx;4)*vm{~L?IwCiwW);F|&EBoHXs7(TER~ zJ2dSbZrZgb9h!EWQSEiwxe=~uZ#Tm%xzma|uHe=_#N-1}$JKOD_M}Cdc$te}*HoK$ znFI3#8`B;xwRoF$JT*JZEmq_W`<`}~TFtyp=**4t-dm7mHq&P9?5w|{dV(@#o_3@L?PCmJ5;iRD8iQQT}Ik>6y_d$7V)OYo|az0r& zI~cdAeM&IVc&`Je245BL_57@0E~QGdgLW^!o|3D)FZHb2GTu}3*yZ*SKJ=~%0g~^EHf_Y=%&s;tTEh97qBvUnXm6h#0zFM{?S$aI& z-&U0^sO%x(HrK${jt{EZ@K$k|>IKekQHYO~6Wl!%%yu_MjWPqo_I|z zX=x4T_g{C-efkYAl!hQ8+do5x?n};Y4W~oDKHM5kl!LUkzpK{aw$Pf@$+ug>1#@y za8~6;xGGk<43Y*^VLi>?lK8dY*nzST>~Q}~YQcOpId2}`rPvpNfrj5N}On?HDFQMXtouca&^`)LCoOd7e?bzL>&vXmUqm7(O=KmYo%Em4i(A ztZ8um#MEaeGGb<&*PX}Ykb<+NCzAOc;om_ZZ{<@Q`tq&K&Op)V&oxPJC&rS$$|v(X z!-Zph1#UApR>G=UB}@QBrfy7b>(ui0`(zv^)#|qKozcj%Re6l<2??>i|S*6^`N+AbZhG9ORFRn}; z?G6t}tEo3;V;5 zDQ={T`^)Xg=7F%^-vJ6fRe{+RG?MYgzt>u!eqZ@$f13%*QZX$vi^QDTp^5Ufl~ z_#e8>nh5`ND~WC_;fo5VUHSE`t_x4QZ}_0ndR-;oxYacqd@&99H{I$+`0-k8!L=l+ z{os#lU3UM4wKgxoPl&jl6#vn+u8|jRao>B_x^aHh#fM+QPdXICCi;%Go0boTr+6b? z+yE@HkxJ}}_{Gm{`uW)KQm>~8Jq57G$#J{17mG0Jinra6TsS`bH9Pcm5exl9vLOnm zj85HSt;Qj*p_(Cf*d@u1D11G-qQgsJzxV6pj1sgWOqQ3z*LE~Gz)5~l3J)S*UpXvO z;ev8_Q12cUni3-pS$qUG&*8D(zzaC44`ZoH;o>n=yTDa<~{Jo;L-o zxGpJA2@m%^pPV}-JT}9Po9>(v<~<_6Jhc{?{ADWUaCg*g%ePMpXOrpU)52r-Ge*hS zCB}lgOdVzmNi)9u;=0%7zX0--C;R$(&e$)UKu6xcU-$;=fgCz-+b=9laVVzF&Dm2B zZOlQkw;F&U(@{p#!|ucO$b8QyEHgM8hT1Z6p$p9nf0&uvG1x?0Ca@C&c**qeJ-sXc z&t__;IhoZ=jYRa!E&pGphkCAH@{I8E3@uswx*6d~ZJBtFb}9MGjBwE3c~dfWX856o zoOjN22@lN-k2xqS;S8482y#VFCjlW~YUpP5+9U`foHO^Ko0Fqwg|q$dZgx*0{L`#( zbR~VD0TyI4Q1BxoGqXVV{xZ<~cH*?pbe;{o#y5UD`(2E8eF5Nc1TWrAxUp<5-twI+ zFNZqxX!nEJ@4oExnu!6xUEyT<>~N2>=+Vh1W@9P2Jb7|?qWf%A|kTm?hUUo@N zo)eyR^xo58qwGMZipilUDNaxEd{lc@V<`FUoN$c4>*-|rzZWL%^__rcx7#>tZyj)x zaJR+n^{s;g$Lx5fx(vn~=iFlicl|7xc>sI^ny3T9gEFQ=&dXOG5ca;}rmv%RPVx8p z%tE^5vq-f&QO)v%WX#P-sK-y9Uq+Iz~(gTq4&6Ug}7Nl@g! z{NQlj-t*skaM;z1A8X|uk$4A(edWfXxfV?l(;ExyUFz$Z%QEciQH{r*Gv*5<=F~@b)wKC78xIhV-!t2F!?W@B@LsYF4a>%}!{Zn2 z(dLW4ZfsM!9^*Q-w$d1PP;%OWu**BpdJ+zK z5c}&>Ze}IZ~s6q@I@E)ZQMhwW+$q#x8-9=0m5XcparGmIN#h!*40{(my zi`4;+5)_)Q5H5#u?HCy3;?W9CQ>aHFEDYd@6vD6oWv@cm6L2i3(4^!YhlTrh4vA1i z%#eE7uU?i~Cc1gmf!1N+*ptP%#Gdmt7s$F?3cfl`8s_Qy)}(>s>Qu0L!OJG%%)`U| z7fz^OzlVH(AuBmUINdQzz67#MMB{zk7Kg@p@j*&1TBqZ||B1tEhd|ZWZc~EVwa|;x>oBC1m3@Vt0 zr|FCo8m|z>5}a@6N*ZVswlukJE5lRVddJt3?|-!MOSHa-|*7`^1&*M)-@!5^xz?Kv2!3{>2KlIg%% zlc#W~_^^Ww4BcN6H~^9wbcl@wInZG{@q(F5PAL_RI=3DB69|YVU#=(PNeW?Yl8YxR zgpmpUBo*Q&DK>G0_)wXUObTFJKF-C{lxK831b8j82h_Yb# zo18YL(4GAG@NiD@)G^pfk5Y{@m3^c_vuw*JM;;p%yxA5GQ3d4UIWF9(@czlI6L{0= z0GIXqw3obgLSZ!ey@khyV?umF<>G@~{uYJjTKEF<)G<#j$xmB+h(ee*;D8X`j}F8eFq@j2$E~{F7_VGz3JtlP zC_a;q*P`FRMMV6Q95?CWt!Op`+QLlnQ~X#|kxJ_^g@%TfV@L9e4* zw1EHH3IZyb5lk-C5>o4H-xwY^Mi~rq#zP8e3OM?VcVC^{{KoJ?fBiK{%NgN&{1wZS ztIr6p_K9zPQ@D!wO*g$M9L;kQ*CcnnIXpwX>pU}@tc-Kd3@;v`+B7s9@O8_RFP|As zYPTkA{fYU-ndpkuyaN-ZSxCFgZUf3`oXx9E5l#)6+T`T3!v1!fYy%x)mYo&OsHEUY zo^5VTBw@ZJm@-)IyDy0^xisGPxyL_OcsC=D_X4%?&``du44u=-R36XsTtk;5RoP3# zb2MG8ZT?8q!>(Q3li|Y1waJ{b!@(K#nc}<1A#O2$sXXJzjp0_L%6ldql~&g-mJPEP9n9Q4T8BR@;gHZ=|*nE2I-Esg2S;vT3cFf^KzWzghvg&)P_&Kcy4%%zkGS} z`*XwSwR_E(LMtP->Tz1*@PgnpovbK#Lc=66akwh*1sWHe$2{>}dtP|mNa1O>Wwj63 zA<5xy4aW|qTU}V7aZ|Iim7_QL=v%`h2i8(%$+76X22Z7lh?s>&cGZ&bu5oFXbo*3^VLF)t zCRO$JrQs7=x%eWKF#JC2qHs&ATQm=FNM>D(W`q@9d~tYSyMc$MR*-Sc#VChT2s|E~ zz{X+mpemI5!^L5_3NUcl0vN9zVCKHl0nER>vkqX|-UXqc=9TXXj~Gmu3Kg;y)vhw6 zF1UUEU19%`Dcs`V$ViZ*28y&0TxB7nVyeXYZj~6ppqZmC36HPqB<>T2b#mP$;gOD}Q2O~$>f zUY_(X3r~hYyl`1KP!8Uh$)Jf!#w16+FPu{aDRk-9XH97~N&omhH%at(AoUG z@84gAD;{;Rx-#^LzSz$Y>1#g_el^9RO+b~yIKl~1D%-YiaB@7P<}MG{ z_{RkiY|GM89-5Cp&S8DbISPnKOnD&nf=OsG)JrMFfW)PlFj12piUgFs3 zrjHf+l8;;;zP*FjIA-QH7COQ>EOjP-x;{K;;qG5<2FvS`L@#&BOn-)UZexLVH{#5v zG1-)AjmgQSH-uyT-Mr|We!s|fYGbj9ZE+L6Hc?HP>aVWyx31#EVfD)7sa4^WGx}`4jaj5PI?NZC8A5u{a|dEt)GqXfEdc+wxW^0bF35!@ zdX6Qfu~|y&m73ztQZJ4>$MFBiVAaSc4s4}(!DcDc`vXhs+oIyd9evUxhS~E2c-+C_ z1EA6q1U3q6l5C!MU?Gp9F`j|#TW9(L!LZ8UZ*5i5_L7As2R$Q$Xjm?dy}yOZCUcZk zYD(VwagbiVeG=EalAmpaH6NRNm#E5pzq}W{s@~`}V zQ(PBa#L)s6K|s`e41R*5{$rd6>VBulpX%RJD2-E|y9?Nl@x7~1>Syj+q{?wW^X(Jc z_KSM$>R0En9UWrS?P(F_^;l-7dS49V<2&V#>z~6L4#xr^Y8hY&sEQmoe;f<2#a~gs zn|XF1-#$SPMDmL}g8VAA#pw|FmAorK)tOH|oP-Bf@*UtP!KNF~V=Qz!BEIzAx=HVO zJH~n+w4*V~XLVzG)*jJOy)9auq4D(M=lMWA=d zvaGa-s1~u>BBs_N)>_1zTEu#bIHVeZJ%wu939+*=@aDv9@5==}dr+B~`x0(9dDEb} z98ujJy_Rg+&Sw(GR;N_I^!$j`mPZSi&Abw%33Lg9xj