From 86535f161292ff43111f602dab3edecabfdac5db Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Wed, 25 Dec 2024 20:26:27 +0100 Subject: [PATCH] fix(layout-applier): logical index pane sorting (#3893) * initial draft * working with floating panes as well * use the same method for applying an initial layout to tiled panes * some refactoring * all code paths working with logical positioning fallback! * get tests to compile * get e2e tests to pass * fix e2e remote runner * breadth-first layout sorting * fix some bugs * style(fmt): rustfmt * style(fmt): remove comments --- src/tests/e2e/remote_runner.rs | 8 + .../floating_panes/floating_pane_grid.rs | 5 + zellij-server/src/panes/floating_panes/mod.rs | 3 + zellij-server/src/panes/plugin_pane.rs | 3 + zellij-server/src/panes/terminal_pane.rs | 3 + zellij-server/src/panes/tiled_panes/mod.rs | 21 + .../src/panes/tiled_panes/tiled_pane_grid.rs | 2 + zellij-server/src/screen.rs | 34 +- zellij-server/src/tab/layout_applier.rs | 1208 +++++++++-------- zellij-server/src/tab/mod.rs | 140 +- zellij-server/src/tab/swap_layouts.rs | 16 +- ...se_layout_is_included_in_swap_layouts.snap | 6 +- ...ize_into_pane_stack_non_directionally.snap | 8 +- ...rease_size_into_pane_stack_vertically.snap | 8 +- ..._main_pane_in_stack_non_directionally.snap | 8 +- ...size_of_main_pane_in_stack_vertically.snap | 8 +- ...ease_stack_size_beyond_minimum_height.snap | 2 +- ...ne_liner_stacked_pane_above_main_pane.snap | 4 +- ...ne_with_previously_focused_other_pane.snap | 2 +- ...focus_next_pane_expands_stacked_panes.snap | 2 +- ...ane_over_flexible_pane_with_the_mouse.snap | 2 +- ...ne_under_flexible_pane_with_the_mouse.snap | 2 +- ..._plugins_and_commands_swaped_properly.snap | 14 +- ...s__new_floating_pane_in_auto_layout-3.snap | 4 +- ...tion_tests__new_pane_in_auto_layout-5.snap | 8 +- ...tion_tests__new_pane_in_auto_layout-6.snap | 12 +- ...tion_tests__new_pane_in_auto_layout-7.snap | 8 +- ...__stacked_panes_can_become_fullscreen.snap | 4 +- ...mand_panes_present_in_existing_layout.snap | 4 +- ...and_panes_absent_from_existing_layout.snap | 6 +- ...mand_panes_present_in_existing_layout.snap | 22 +- ...ugin_panes_present_in_existing_layout.snap | 20 +- ...gration_tests__tab_with_nested_layout.snap | 6 +- ..._tests__tab_with_nested_uneven_layout.snap | 8 +- ...ed_state_pane_focuses_on_focused_node.snap | 24 +- ...cus_node_pane_focuses_on_deepest_node.snap | 20 +- ...ed_state_pane_focuses_on_focused_node.snap | 4 +- ...cus_node_pane_focuses_on_deepest_node.snap | 4 +- .../src/tab/unit/tab_integration_tests.rs | 101 +- zellij-server/src/tab/unit/tab_tests.rs | 2 +- zellij-server/src/unit/screen_tests.rs | 13 +- ...een_can_move_pane_to_a_new_tab_left-4.snap | 4 +- ...en_can_move_pane_to_a_new_tab_right-4.snap | 4 +- ..._new_pane_action_with_command_and_cwd.snap | 6 +- ...send_cli_toggle_pane_embed_or_float-3.snap | 4 +- zellij-utils/assets/layouts/classic.swap.kdl | 6 +- zellij-utils/assets/layouts/compact.swap.kdl | 6 +- zellij-utils/assets/layouts/default.swap.kdl | 6 +- zellij-utils/src/input/layout.rs | 18 +- ...__layout_with_tabs_and_floating_panes.snap | 3 + zellij-utils/src/pane_size.rs | 4 +- zellij-utils/src/session_serialization.rs | 26 + ...efault_config_with_no_cli_arguments-2.snap | 32 +- 53 files changed, 1056 insertions(+), 842 deletions(-) diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs index c2b94cc6..9882781f 100644 --- a/src/tests/e2e/remote_runner.rs +++ b/src/tests/e2e/remote_runner.rs @@ -457,6 +457,7 @@ impl RemoteRunner { cols, is_stacked: false, is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); start_zellij(&mut channel); @@ -494,6 +495,7 @@ impl RemoteRunner { cols, is_stacked: false, is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); start_zellij_mirrored_session(&mut channel); @@ -531,6 +533,7 @@ impl RemoteRunner { cols, is_stacked: false, is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); start_zellij_mirrored_session_with_layout(&mut channel, layout_file_name); @@ -571,6 +574,7 @@ impl RemoteRunner { cols, is_stacked: false, is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); start_zellij_mirrored_session_with_layout_and_viewport_serialization( @@ -618,6 +622,7 @@ impl RemoteRunner { cols, is_stacked: false, is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); start_zellij_in_session(&mut channel, session_name, mirrored); @@ -655,6 +660,7 @@ impl RemoteRunner { cols, is_stacked: false, is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); attach_to_existing_session(&mut channel, session_name); @@ -692,6 +698,7 @@ impl RemoteRunner { cols, is_stacked: false, is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); start_zellij_without_frames(&mut channel); @@ -730,6 +737,7 @@ impl RemoteRunner { cols, is_stacked: false, is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); start_zellij_with_config(&mut channel, &remote_path.to_string_lossy()); 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 d8d9e64e..127b9b37 100644 --- a/zellij-server/src/panes/floating_panes/floating_pane_grid.rs +++ b/zellij-server/src/panes/floating_panes/floating_pane_grid.rs @@ -862,6 +862,7 @@ pub fn half_size_middle_geom(space: &Viewport, offset: usize) -> PaneGeom { rows: Dimension::fixed(space.rows / 2), is_stacked: false, is_pinned: false, + logical_position: None, }; geom.cols.set_inner(space.cols / 2); geom.rows.set_inner(space.rows / 2); @@ -876,6 +877,7 @@ fn half_size_top_left_geom(space: &Viewport, offset: usize) -> PaneGeom { rows: Dimension::fixed(space.rows / 3), is_stacked: false, is_pinned: false, + logical_position: None, }; geom.cols.set_inner(space.cols / 3); geom.rows.set_inner(space.rows / 3); @@ -890,6 +892,7 @@ fn half_size_top_right_geom(space: &Viewport, offset: usize) -> PaneGeom { rows: Dimension::fixed(space.rows / 3), is_stacked: false, is_pinned: false, + logical_position: None, }; geom.cols.set_inner(space.cols / 3); geom.rows.set_inner(space.rows / 3); @@ -904,6 +907,7 @@ fn half_size_bottom_left_geom(space: &Viewport, offset: usize) -> PaneGeom { rows: Dimension::fixed(space.rows / 3), is_stacked: false, is_pinned: false, + logical_position: None, }; geom.cols.set_inner(space.cols / 3); geom.rows.set_inner(space.rows / 3); @@ -918,6 +922,7 @@ fn half_size_bottom_right_geom(space: &Viewport, offset: usize) -> PaneGeom { rows: Dimension::fixed(space.rows / 3), is_stacked: false, is_pinned: false, + logical_position: None, }; 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 d0ce41e8..27eda096 100644 --- a/zellij-server/src/panes/floating_panes/mod.rs +++ b/zellij-server/src/panes/floating_panes/mod.rs @@ -282,6 +282,9 @@ impl FloatingPanes { if let Some(is_pinned) = &floating_pane_layout.pinned { position.is_pinned = *is_pinned; } + if let Some(logical_position) = &floating_pane_layout.logical_position { + position.logical_position = Some(*logical_position); + } if position.cols.as_usize() > viewport.cols { position.cols = Dimension::fixed(viewport.cols); } diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs index 7bc2a972..c879cfef 100644 --- a/zellij-server/src/panes/plugin_pane.rs +++ b/zellij-server/src/panes/plugin_pane.rs @@ -722,6 +722,9 @@ impl Pane for PluginPane { } false } + fn reset_logical_position(&mut self) { + self.geom.logical_position = None; + } } impl PluginPane { diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index fe1a96ae..2e825ac8 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -842,6 +842,9 @@ impl Pane for TerminalPane { } false } + fn reset_logical_position(&mut self) { + self.geom.logical_position = None; + } } impl TerminalPane { diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs index 0223a79e..f93f3156 100644 --- a/zellij-server/src/panes/tiled_panes/mod.rs +++ b/zellij-server/src/panes/tiled_panes/mod.rs @@ -183,6 +183,27 @@ impl TiledPanes { .is_some(); has_room_for_new_pane || pane_grid.has_room_for_new_stacked_pane() || self.panes.is_empty() } + + pub fn assign_geom_for_pane_with_run(&mut self, run: Option) { + // here we're removing the first pane we find with this run instruction and re-adding it so + // that it gets a new geom similar to how it would when being added to the tab originally + if let Some(pane_id) = self + .panes + .iter() + .find_map(|(pid, p)| { + if p.invoked_with() == &run { + Some(pid) + } else { + None + } + }) + .copied() + { + if let Some(pane) = self.panes.remove(&pane_id) { + self.add_pane(pane.pid(), pane, true); + } + } + } fn add_pane(&mut self, pane_id: PaneId, mut pane: Box, should_relayout: bool) { if self.panes.is_empty() { self.panes.insert(pane_id, pane); 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 f5eda453..fee6f567 100644 --- a/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs +++ b/zellij-server/src/panes/tiled_panes/tiled_pane_grid.rs @@ -1407,11 +1407,13 @@ pub fn split(direction: SplitDirection, rect: &PaneGeom) -> Option<(PaneGeom, Pa SplitDirection::Vertical => PaneGeom { x: first_rect.x + 1, cols: first_rect.cols, + logical_position: None, ..*rect }, SplitDirection::Horizontal => PaneGeom { y: first_rect.y + 1, rows: first_rect.rows, + logical_position: None, ..*rect }, }; diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index 82c1a341..b4195e37 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -2038,8 +2038,7 @@ impl Screen { if let Some(plugin_pane_id) = tab.find_plugin(&run_plugin) { tab_index_and_plugin_pane_id = Some((*tab_index, plugin_pane_id)); if move_to_focused_tab && focused_tab_index != *tab_index { - plugin_pane_to_move_to_active_tab = - tab.extract_pane(plugin_pane_id, true, Some(client_id)); + plugin_pane_to_move_to_active_tab = tab.extract_pane(plugin_pane_id, true); } break; @@ -2055,7 +2054,6 @@ impl Screen { plugin_pane_to_move_to_active_tab, pane_id, None, - Some(client_id), )?; } else { new_active_tab.hide_floating_panes(); @@ -2156,7 +2154,7 @@ impl Screen { .with_context(err_context)?; let pane_to_break_is_floating = active_tab.are_floating_panes_visible(); let active_pane = active_tab - .extract_pane(active_pane_id, false, Some(client_id)) + .extract_pane(active_pane_id, false) .with_context(err_context)?; let active_pane_run_instruction = active_pane.invoked_with().clone(); let tab_index = self.get_new_tab_index(); @@ -2169,7 +2167,7 @@ impl Screen { let (mut tiled_panes_layout, mut floating_panes_layout) = default_layout.new_tab(); if pane_to_break_is_floating { tab.show_floating_panes(); - tab.add_floating_pane(active_pane, active_pane_id, None, Some(client_id))?; + tab.add_floating_pane(active_pane, active_pane_id, None)?; if let Some(already_running_layout) = floating_panes_layout .iter_mut() .find(|i| i.run == active_pane_run_instruction) @@ -2221,7 +2219,7 @@ impl Screen { for tab in all_tabs.values_mut() { // here we pass None instead of the client_id we have because we do not need to // necessarily trigger a relayout for this tab - if let Some(pane) = tab.extract_pane(pane_id, true, None).take() { + if let Some(pane) = tab.extract_pane(pane_id, true).take() { extracted_panes.push(pane); break; } @@ -2276,7 +2274,7 @@ impl Screen { .with_context(err_context)?; let pane_to_break_is_floating = active_tab.are_floating_panes_visible(); let active_pane = active_tab - .extract_pane(active_pane_id, false, Some(client_id)) + .extract_pane(active_pane_id, false) .with_context(err_context)?; (active_pane_id, active_pane, pane_to_break_is_floating) }; @@ -2293,12 +2291,7 @@ impl Screen { if pane_to_break_is_floating { new_active_tab.show_floating_panes(); - new_active_tab.add_floating_pane( - active_pane, - active_pane_id, - None, - Some(client_id), - )?; + new_active_tab.add_floating_pane(active_pane, active_pane_id, None)?; } else { new_active_tab.hide_floating_panes(); new_active_tab.add_tiled_pane(active_pane, active_pane_id, Some(client_id))?; @@ -2348,7 +2341,7 @@ impl Screen { } // here we pass None instead of the client_id we have because we do not need to // necessarily trigger a relayout for this tab - if let Some(pane) = tab.extract_pane(pane_id, true, None).take() { + if let Some(pane) = tab.extract_pane(pane_id, true).take() { extracted_panes.push(pane); break; } @@ -3372,16 +3365,13 @@ 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, - Some(client_id) - )); + active_tab!(screen, client_id, |tab: &mut Tab| tab + .close_pane(id, false,)); }, None => { for tab in screen.tabs.values_mut() { if tab.get_all_pane_ids().contains(&id) { - tab.close_pane(id, false, None); + tab.close_pane(id, false); break; } } @@ -3904,7 +3894,7 @@ pub(crate) fn screen_thread_main( active_tab_and_connected_client_id!( screen, client_id, - |tab: &mut Tab, client_id: ClientId| tab.previous_swap_layout(Some(client_id)), + |tab: &mut Tab, client_id: ClientId| tab.previous_swap_layout(), ? ); screen.render(None)?; @@ -3915,7 +3905,7 @@ pub(crate) fn screen_thread_main( active_tab_and_connected_client_id!( screen, client_id, - |tab: &mut Tab, client_id: ClientId| tab.next_swap_layout(Some(client_id), true), + |tab: &mut Tab, client_id: ClientId| tab.next_swap_layout(), ? ); screen.render(None)?; diff --git a/zellij-server/src/tab/layout_applier.rs b/zellij-server/src/tab/layout_applier.rs index 3b02d373..e2bb5ccb 100644 --- a/zellij-server/src/tab/layout_applier.rs +++ b/zellij-server/src/tab/layout_applier.rs @@ -122,76 +122,65 @@ impl<'a> LayoutApplier<'a> { pub fn apply_tiled_panes_layout_to_existing_panes( &mut self, layout: &TiledPaneLayout, - refocus_pane: bool, - client_id: Option, ) -> Result<()> { - let free_space = self.total_space_for_tiled_panes(); - let tiled_panes_count = self.tiled_panes.visible_panes_count(); - let positions_in_layout = - match layout.position_panes_in_space(&free_space, Some(tiled_panes_count), false) { - Ok(positions_in_layout) => positions_in_layout, - // in the error branch, we try to recover by positioning the panes in the space but - // ignoring the percentage sizes (passing true as the third argument), this is a hack - // around some issues with the constraint system that should be addressed in a systemic - // manner - Err(_e) => layout - .position_panes_in_space(&free_space, Some(tiled_panes_count), true) - .map_err(|e| anyhow!(e))?, - }; - 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); - let mut positions_left = vec![]; + let positions_in_layout = self.flatten_layout(layout, true)?; + + let mut existing_tab_state = ExistingTabState::new(self.tiled_panes.drain()); + + let mut pane_applier = PaneApplier::new( + &mut self.tiled_panes, + &mut self.floating_panes, + &self.senders, + &self.character_cell_size, + ); + let mut positions_left_without_exact_matches = vec![]; + + // look for exact matches (eg. panes that expect a specific command or plugin to run in them) for (layout, position_and_size) in positions_in_layout { - // first try to find panes with contents matching the layout exactly - match existing_tab_state.find_and_extract_exact_match_pane( - &layout.run, - &position_and_size, - true, - ) { - Some(mut pane) => { - self.apply_layout_properties_to_pane( - &mut pane, - &layout, - Some(position_and_size), + match existing_tab_state + .find_and_extract_exact_match_pane(&layout.run, position_and_size.logical_position) + { + Some(pane) => { + pane_applier.apply_position_and_size_to_tiled_pane( + pane, + position_and_size, + layout, ); - pane_focuser.set_pane_id_in_focused_location(layout.focus, &pane); - pane_focuser.set_expanded_stacked_pane(layout.is_expanded_in_stack, &pane); - resize_pty!(pane, self.os_api, self.senders, self.character_cell_size)?; - self.tiled_panes - .add_pane_with_existing_geom(pane.pid(), pane); }, None => { - positions_left.push((layout, position_and_size)); + positions_left_without_exact_matches.push((layout, position_and_size)); }, } } + + // look for matches according to the logical position in the layout + let mut positions_left = vec![]; + for (layout, position_and_size) in positions_left_without_exact_matches { + if let Some(pane) = existing_tab_state.find_and_extract_pane_with_same_logical_position( + position_and_size.logical_position, + ) { + pane_applier.apply_position_and_size_to_tiled_pane(pane, position_and_size, layout); + } else { + positions_left.push((layout, position_and_size)); + } + } + + // fill the remaining panes by order of their logical position for (layout, position_and_size) in positions_left { // now let's try to find panes on a best-effort basis - 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); - pane_focuser.set_expanded_stacked_pane(layout.is_expanded_in_stack, &pane); - resize_pty!(pane, self.os_api, self.senders, self.character_cell_size)?; - self.tiled_panes - .add_pane_with_existing_geom(pane.pid(), pane); + if let Some(pane) = + existing_tab_state.find_and_extract_pane(position_and_size.logical_position) + { + pane_applier.apply_position_and_size_to_tiled_pane(pane, position_and_size, layout); } } + + // add the rest of the panes where tiled_panes finds room for them (eg. if the layout had + // less panes than we've got in our state) 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); + pane_applier.handle_remaining_tiled_pane_ids(remaining_pane_ids, existing_tab_state); + pane_applier.finalize_tiled_state(); + LayoutApplier::offset_viewport( self.viewport.clone(), self.tiled_panes, @@ -199,291 +188,432 @@ impl<'a> LayoutApplier<'a> { ); Ok(()) } + fn flatten_layout( + &self, + layout: &TiledPaneLayout, + has_existing_panes: bool, + ) -> Result> { + let free_space = self.total_space_for_tiled_panes(); + let tiled_panes_count = if has_existing_panes { + Some(self.tiled_panes.visible_panes_count()) + } else { + None + }; + let focus_layout_if_not_focused = if has_existing_panes { false } else { true }; + let mut positions_in_layout = layout + .position_panes_in_space( + &free_space, + tiled_panes_count, + false, + focus_layout_if_not_focused, + ) + .or_else(|_e| { + // in the error branch, we try to recover by positioning the panes in the space but + // ignoring the percentage sizes (passing true as the third argument), this is a hack + // around some issues with the constraint system that should be addressed in a systemic + // manner + layout.position_panes_in_space( + &free_space, + tiled_panes_count, + true, + focus_layout_if_not_focused, + ) + }) + .map_err(|e| anyhow!(e))?; + let mut logical_position = 0; + for (_layout, position_and_size) in positions_in_layout.iter_mut() { + position_and_size.logical_position = Some(logical_position); + logical_position += 1; + } + Ok(positions_in_layout) + } fn apply_tiled_panes_layout( &mut self, layout: TiledPaneLayout, - new_terminal_ids: Vec<(u32, HoldForCommand)>, - new_plugin_ids: &mut HashMap>, + mut new_terminal_ids: Vec<(u32, HoldForCommand)>, + mut new_plugin_ids: &mut HashMap>, client_id: ClientId, ) -> Result<()> { let err_context = || format!("failed to apply tiled panes layout"); - let free_space = self.total_space_for_tiled_panes(); - let mut positions_in_layout = match layout.position_panes_in_space(&free_space, None, false) - { - Ok(positions_in_layout) => positions_in_layout, - // in the error branch, we try to recover by positioning the panes in the space but - // ignoring the percentage sizes (passing true as the third argument), this is a hack - // around some issues with the constraint system that should be addressed in a systemic - // manner - Err(_e) => layout - .position_panes_in_space(&free_space, None, true) - .map_err(|e| anyhow!(e))?, - }; - let mut run_instructions_to_ignore = layout.run_instructions_to_ignore.clone(); - let mut new_terminal_ids = new_terminal_ids.iter(); - + let mut positions_in_layout = self.flatten_layout(&layout, false)?; + let run_instructions_without_a_location = self.position_run_instructions_to_ignore( + &layout.run_instructions_to_ignore, + &mut positions_in_layout, + ); + let focus_pane_id = self.position_new_panes( + &mut new_terminal_ids, + &mut new_plugin_ids, + &mut positions_in_layout, + )?; + self.handle_run_instructions_without_a_location( + run_instructions_without_a_location, + &mut new_terminal_ids, + ); + self.adjust_viewport().with_context(err_context)?; + self.set_focused_tiled_pane(focus_pane_id, client_id); + Ok(()) + } + fn position_run_instructions_to_ignore( + &mut self, + run_instructions_to_ignore: &Vec>, + positions_in_layout: &mut Vec<(TiledPaneLayout, PaneGeom)>, + ) -> Vec> { + // here we try to find rooms for the panes that are already running (represented by + // run_instructions_to_ignore), we try to either find an explicit position (the new + // layout has a pane with the exact run instruction) or an otherwise free position + // (the new layout has a pane with None as its run instruction, eg. just `pane` in the + // layout) + let mut run_instructions_without_a_location = vec![]; + for run_instruction in run_instructions_to_ignore.clone().drain(..) { + if self + .place_running_pane_in_exact_match_location(&run_instruction, positions_in_layout) + { + // found exact match + } else if self + .place_running_pane_in_empty_location(&run_instruction, positions_in_layout) + { + // found empty location + } else { + // no room! we'll add it below after we place everything else + run_instructions_without_a_location.push(run_instruction); + } + } + run_instructions_without_a_location + } + fn position_new_panes( + &mut self, + new_terminal_ids: &mut Vec<(u32, HoldForCommand)>, + new_plugin_ids: &mut HashMap>, + positions_in_layout: &mut Vec<(TiledPaneLayout, PaneGeom)>, + ) -> Result> { + // here we open new panes for each run instruction in the layout with the details + // we got from the plugin thread and pty thread + // let positions_and_size = positions_in_layout.iter(); let mut focus_pane_id: Option = None; 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); } }; - - // first, try to find rooms for the panes that are already running (represented by - // run_instructions_to_ignore), we try to either find an explicit position (the new - // layout has a pane with the exact run instruction) or an otherwise free position - // (the new layout has a pane with None as its run instruction) - for run_instruction in run_instructions_to_ignore.drain(..) { - if let Some(position) = positions_in_layout - .iter() - .position(|(layout, _position_and_size)| &layout.run == &run_instruction) - { - let (layout, position_and_size) = positions_in_layout.remove(position); - self.tiled_panes.set_geom_for_pane_with_run( - layout.run, - position_and_size, - layout.borderless, - ); - } else if let Some(position) = positions_in_layout - .iter() - .position(|(layout, _position_and_size)| layout.run.is_none()) - { - let (layout, position_and_size) = positions_in_layout.remove(position); - self.tiled_panes.set_geom_for_pane_with_run( - run_instruction, - position_and_size, - layout.borderless, - ); - } else if let Some(position) = - positions_in_layout - .iter() - .position(|(layout, _position_and_size)| { - Run::is_terminal(&layout.run) && Run::is_terminal(&run_instruction) - }) - { - let (layout, position_and_size) = positions_in_layout.remove(position); - self.tiled_panes.set_geom_for_pane_with_run( - run_instruction, - position_and_size, - layout.borderless, - ); - } else { - log::error!( - "Failed to find room for run instruction: {:?}", - run_instruction - ); + for (layout, position_and_size) in positions_in_layout { + if let Some(Run::Plugin(run)) = layout.run.clone() { + let pid = + self.new_tiled_plugin_pane(run, new_plugin_ids, &position_and_size, &layout)?; + set_focus_pane_id(&layout, PaneId::Plugin(pid)); + } else if !new_terminal_ids.is_empty() { + // there are still panes left to fill, use the pids we received in this method + let (pid, hold_for_command) = new_terminal_ids.remove(0); + self.new_terminal_pane(pid, &hold_for_command, &position_and_size, &layout)?; + set_focus_pane_id(&layout, PaneId::Terminal(pid)); } } - - // then, we open new panes for each run instruction in the layout with the details - // we got from the plugin thread and pty thread - let positions_and_size = positions_in_layout.iter(); - for (layout, position_and_size) in positions_and_size { - if let Some(Run::Plugin(run)) = layout.run.clone() { - let pane_title = run.location_string(); - let pid = new_plugin_ids - .get_mut(&run) - .and_then(|ids| ids.pop()) - .with_context(err_context)?; - let mut new_plugin = PluginPane::new( - pid, - *position_and_size, - self.senders - .to_plugin - .as_ref() - .with_context(err_context)? - .clone(), - pane_title, - layout.name.clone().unwrap_or_default(), - self.sixel_image_store.clone(), - self.terminal_emulator_colors.clone(), - self.terminal_emulator_color_codes.clone(), - self.link_handler.clone(), - self.character_cell_size.clone(), - self.connected_clients.borrow().iter().copied().collect(), - self.style, - layout.run.clone(), - self.debug, - self.arrow_fonts, - self.styled_underlines, - ); - if let Some(pane_initial_contents) = &layout.pane_initial_contents { - new_plugin.handle_pty_bytes(pane_initial_contents.as_bytes().into()); - new_plugin.handle_pty_bytes("\n\r".as_bytes().into()); - } - - new_plugin.set_borderless(layout.borderless); - if let Some(exclude_from_sync) = layout.exclude_from_sync { - new_plugin.set_exclude_from_sync(exclude_from_sync); - } - self.tiled_panes - .add_pane_with_existing_geom(PaneId::Plugin(pid), Box::new(new_plugin)); - set_focus_pane_id(layout, PaneId::Plugin(pid)); - } else { - // there are still panes left to fill, use the pids we received in this method - if let Some((pid, hold_for_command)) = new_terminal_ids.next() { - let next_terminal_position = - get_next_terminal_position(&self.tiled_panes, &self.floating_panes); - let initial_title = match &layout.run { - Some(Run::Command(run_command)) => Some(run_command.to_string()), - _ => None, - }; - let mut new_pane = TerminalPane::new( - *pid, - *position_and_size, - self.style, - next_terminal_position, - layout.name.clone().unwrap_or_default(), - self.link_handler.clone(), - self.character_cell_size.clone(), - self.sixel_image_store.clone(), - self.terminal_emulator_colors.clone(), - self.terminal_emulator_color_codes.clone(), - initial_title, - layout.run.clone(), - self.debug, - self.arrow_fonts, - self.styled_underlines, - self.explicitly_disable_kitty_keyboard_protocol, - ); - if let Some(pane_initial_contents) = &layout.pane_initial_contents { - new_pane.handle_pty_bytes(pane_initial_contents.as_bytes().into()); - new_pane.handle_pty_bytes("\n\r".as_bytes().into()); - } - new_pane.set_borderless(layout.borderless); - if let Some(exclude_from_sync) = layout.exclude_from_sync { - new_pane.set_exclude_from_sync(exclude_from_sync); - } - if let Some(held_command) = hold_for_command { - new_pane.hold(None, true, held_command.clone()); - } - self.tiled_panes - .add_pane_with_existing_geom(PaneId::Terminal(*pid), Box::new(new_pane)); - set_focus_pane_id(layout, PaneId::Terminal(*pid)); - } - } + Ok(focus_pane_id) + } + fn handle_run_instructions_without_a_location( + &mut self, + run_instructions_without_a_location: Vec>, + new_terminal_ids: &mut Vec<(u32, HoldForCommand)>, + ) { + for run_instruction in run_instructions_without_a_location { + self.tiled_panes + .assign_geom_for_pane_with_run(run_instruction); } for (unused_pid, _) in new_terminal_ids { - self.senders - .send_to_pty(PtyInstruction::ClosePane(PaneId::Terminal(*unused_pid))) - .with_context(err_context)?; + let _ = self + .senders + .send_to_pty(PtyInstruction::ClosePane(PaneId::Terminal(*unused_pid))); } - self.adjust_viewport().with_context(err_context)?; - self.set_focused_tiled_pane(focus_pane_id, client_id); + } + fn new_tiled_plugin_pane( + &mut self, + run: RunPluginOrAlias, + new_plugin_ids: &mut HashMap>, + position_and_size: &PaneGeom, + layout: &TiledPaneLayout, + ) -> Result { + let err_context = || format!("Failed to start new plugin pane"); + let pane_title = run.location_string(); + let pid = new_plugin_ids + .get_mut(&run) + .and_then(|ids| ids.pop()) + .with_context(err_context)?; + let mut new_plugin = PluginPane::new( + pid, + *position_and_size, + self.senders + .to_plugin + .as_ref() + .with_context(err_context)? + .clone(), + pane_title, + layout.name.clone().unwrap_or_default(), + self.sixel_image_store.clone(), + self.terminal_emulator_colors.clone(), + self.terminal_emulator_color_codes.clone(), + self.link_handler.clone(), + self.character_cell_size.clone(), + self.connected_clients.borrow().iter().copied().collect(), + self.style, + layout.run.clone(), + self.debug, + self.arrow_fonts, + self.styled_underlines, + ); + if let Some(pane_initial_contents) = &layout.pane_initial_contents { + new_plugin.handle_pty_bytes(pane_initial_contents.as_bytes().into()); + new_plugin.handle_pty_bytes("\n\r".as_bytes().into()); + } + + new_plugin.set_borderless(layout.borderless); + if let Some(exclude_from_sync) = layout.exclude_from_sync { + new_plugin.set_exclude_from_sync(exclude_from_sync); + } + self.tiled_panes + .add_pane_with_existing_geom(PaneId::Plugin(pid), Box::new(new_plugin)); + Ok(pid) + } + fn new_floating_plugin_pane( + &mut self, + run: RunPluginOrAlias, + new_plugin_ids: &mut HashMap>, + position_and_size: PaneGeom, + floating_pane_layout: &FloatingPaneLayout, + ) -> Result> { + let mut pid_to_focus = None; + let err_context = || format!("Failed to create new floating plugin pane"); + let pane_title = run.location_string(); + let pid = new_plugin_ids + .get_mut(&run) + .and_then(|ids| ids.pop()) + .with_context(err_context)?; + let mut new_pane = PluginPane::new( + pid, + position_and_size, + self.senders + .to_plugin + .as_ref() + .with_context(err_context)? + .clone(), + pane_title, + floating_pane_layout.name.clone().unwrap_or_default(), + self.sixel_image_store.clone(), + self.terminal_emulator_colors.clone(), + self.terminal_emulator_color_codes.clone(), + self.link_handler.clone(), + self.character_cell_size.clone(), + self.connected_clients.borrow().iter().copied().collect(), + self.style, + floating_pane_layout.run.clone(), + self.debug, + self.arrow_fonts, + self.styled_underlines, + ); + if let Some(pane_initial_contents) = &floating_pane_layout.pane_initial_contents { + new_pane.handle_pty_bytes(pane_initial_contents.as_bytes().into()); + new_pane.handle_pty_bytes("\n\r".as_bytes().into()); + } + new_pane.set_borderless(false); + new_pane.set_content_offset(Offset::frame(1)); + resize_pty!( + new_pane, + self.os_api, + self.senders, + self.character_cell_size + )?; + self.floating_panes + .add_pane(PaneId::Plugin(pid), Box::new(new_pane)); + if floating_pane_layout.focus.unwrap_or(false) { + pid_to_focus = Some(PaneId::Plugin(pid)); + } + Ok(pid_to_focus) + } + fn new_floating_terminal_pane( + &mut self, + pid: &u32, + hold_for_command: &HoldForCommand, + position_and_size: PaneGeom, + floating_pane_layout: &FloatingPaneLayout, + ) -> Result> { + let mut pane_id_to_focus = None; + let next_terminal_position = + get_next_terminal_position(&self.tiled_panes, &self.floating_panes); + let initial_title = match &floating_pane_layout.run { + Some(Run::Command(run_command)) => Some(run_command.to_string()), + _ => None, + }; + let mut new_pane = TerminalPane::new( + *pid, + position_and_size, + self.style, + next_terminal_position, + floating_pane_layout.name.clone().unwrap_or_default(), + self.link_handler.clone(), + self.character_cell_size.clone(), + self.sixel_image_store.clone(), + self.terminal_emulator_colors.clone(), + self.terminal_emulator_color_codes.clone(), + initial_title, + floating_pane_layout.run.clone(), + self.debug, + self.arrow_fonts, + self.styled_underlines, + self.explicitly_disable_kitty_keyboard_protocol, + ); + if let Some(pane_initial_contents) = &floating_pane_layout.pane_initial_contents { + new_pane.handle_pty_bytes(pane_initial_contents.as_bytes().into()); + new_pane.handle_pty_bytes("\n\r".as_bytes().into()); + } + new_pane.set_borderless(false); + new_pane.set_content_offset(Offset::frame(1)); + if let Some(held_command) = hold_for_command { + new_pane.hold(None, true, held_command.clone()); + } + resize_pty!( + new_pane, + self.os_api, + self.senders, + self.character_cell_size + )?; + self.floating_panes + .add_pane(PaneId::Terminal(*pid), Box::new(new_pane)); + if floating_pane_layout.focus.unwrap_or(false) { + pane_id_to_focus = Some(PaneId::Terminal(*pid)); + } + Ok(pane_id_to_focus) + } + fn new_terminal_pane( + &mut self, + pid: u32, + hold_for_command: &HoldForCommand, + position_and_size: &PaneGeom, + layout: &TiledPaneLayout, + ) -> Result<()> { + let next_terminal_position = + get_next_terminal_position(&self.tiled_panes, &self.floating_panes); + let initial_title = match &layout.run { + Some(Run::Command(run_command)) => Some(run_command.to_string()), + _ => None, + }; + let mut new_pane = TerminalPane::new( + pid, + *position_and_size, + self.style, + next_terminal_position, + layout.name.clone().unwrap_or_default(), + self.link_handler.clone(), + self.character_cell_size.clone(), + self.sixel_image_store.clone(), + self.terminal_emulator_colors.clone(), + self.terminal_emulator_color_codes.clone(), + initial_title, + layout.run.clone(), + self.debug, + self.arrow_fonts, + self.styled_underlines, + self.explicitly_disable_kitty_keyboard_protocol, + ); + if let Some(pane_initial_contents) = &layout.pane_initial_contents { + new_pane.handle_pty_bytes(pane_initial_contents.as_bytes().into()); + new_pane.handle_pty_bytes("\n\r".as_bytes().into()); + } + new_pane.set_borderless(layout.borderless); + if let Some(exclude_from_sync) = layout.exclude_from_sync { + new_pane.set_exclude_from_sync(exclude_from_sync); + } + if let Some(held_command) = hold_for_command { + new_pane.hold(None, true, held_command.clone()); + } + self.tiled_panes + .add_pane_with_existing_geom(PaneId::Terminal(pid), Box::new(new_pane)); Ok(()) } + fn place_running_pane_in_exact_match_location( + &mut self, + run_instruction: &Option, + positions_in_layout: &mut Vec<(TiledPaneLayout, PaneGeom)>, + ) -> bool { + let mut found_exact_match = false; + + if let Some(position) = positions_in_layout + .iter() + .position(|(layout, _position_and_size)| &layout.run == run_instruction) + { + let (layout, position_and_size) = positions_in_layout.remove(position); + self.tiled_panes.set_geom_for_pane_with_run( + layout.run, + position_and_size, + layout.borderless, + ); + found_exact_match = true; + } + found_exact_match + } + fn place_running_pane_in_empty_location( + &mut self, + run_instruction: &Option, + positions_in_layout: &mut Vec<(TiledPaneLayout, PaneGeom)>, + ) -> bool { + let mut found_empty_location = false; + if let Some(position) = positions_in_layout + .iter() + .position(|(layout, _position_and_size)| layout.run.is_none()) + { + let (layout, position_and_size) = positions_in_layout.remove(position); + self.tiled_panes.set_geom_for_pane_with_run( + run_instruction.clone(), + position_and_size, + layout.borderless, + ); + found_empty_location = true; + } + found_empty_location + } fn apply_floating_panes_layout( &mut self, - floating_panes_layout: Vec, + mut floating_panes_layout: Vec, new_floating_terminal_ids: Vec<(u32, HoldForCommand)>, - new_plugin_ids: &mut HashMap>, + mut new_plugin_ids: &mut HashMap>, ) -> Result { - // true => has floating panes - let err_context = || format!("Failed to apply_floating_panes_layout"); - let mut layout_has_floating_panes = false; + let layout_has_floating_panes = !floating_panes_layout.is_empty(); + + let mut logical_position = 0; + for floating_pane_layout in floating_panes_layout.iter_mut() { + floating_pane_layout.logical_position = Some(logical_position); + logical_position += 1; + } + let floating_panes_layout = floating_panes_layout.iter(); let mut focused_floating_pane = None; let mut new_floating_terminal_ids = new_floating_terminal_ids.iter(); for floating_pane_layout in floating_panes_layout { - layout_has_floating_panes = true; let position_and_size = self .floating_panes .position_floating_pane_layout(&floating_pane_layout); - if floating_pane_layout.already_running { + let pid_to_focus = if floating_pane_layout.already_running { self.floating_panes.set_geom_for_pane_with_run( floating_pane_layout.run.clone(), position_and_size, ); + None } else if let Some(Run::Plugin(run)) = floating_pane_layout.run.clone() { - let pane_title = run.location_string(); - let pid = new_plugin_ids - .get_mut(&run) - .and_then(|ids| ids.pop()) - .with_context(err_context)?; - let mut new_pane = PluginPane::new( - pid, + self.new_floating_plugin_pane( + run, + &mut new_plugin_ids, position_and_size, - self.senders - .to_plugin - .as_ref() - .with_context(err_context)? - .clone(), - pane_title, - floating_pane_layout.name.clone().unwrap_or_default(), - self.sixel_image_store.clone(), - self.terminal_emulator_colors.clone(), - self.terminal_emulator_color_codes.clone(), - self.link_handler.clone(), - self.character_cell_size.clone(), - self.connected_clients.borrow().iter().copied().collect(), - self.style, - floating_pane_layout.run.clone(), - self.debug, - self.arrow_fonts, - self.styled_underlines, - ); - if let Some(pane_initial_contents) = &floating_pane_layout.pane_initial_contents { - new_pane.handle_pty_bytes(pane_initial_contents.as_bytes().into()); - new_pane.handle_pty_bytes("\n\r".as_bytes().into()); - } - new_pane.set_borderless(false); - new_pane.set_content_offset(Offset::frame(1)); - resize_pty!( - new_pane, - self.os_api, - self.senders, - self.character_cell_size - )?; - self.floating_panes - .add_pane(PaneId::Plugin(pid), Box::new(new_pane)); - if floating_pane_layout.focus.unwrap_or(false) { - focused_floating_pane = Some(PaneId::Plugin(pid)); - } + &floating_pane_layout, + )? } else if let Some((pid, hold_for_command)) = new_floating_terminal_ids.next() { - let next_terminal_position = - get_next_terminal_position(&self.tiled_panes, &self.floating_panes); - let initial_title = match &floating_pane_layout.run { - Some(Run::Command(run_command)) => Some(run_command.to_string()), - _ => None, - }; - let mut new_pane = TerminalPane::new( - *pid, + self.new_floating_terminal_pane( + pid, + hold_for_command, position_and_size, - self.style, - next_terminal_position, - floating_pane_layout.name.clone().unwrap_or_default(), - self.link_handler.clone(), - self.character_cell_size.clone(), - self.sixel_image_store.clone(), - self.terminal_emulator_colors.clone(), - self.terminal_emulator_color_codes.clone(), - initial_title, - floating_pane_layout.run.clone(), - self.debug, - self.arrow_fonts, - self.styled_underlines, - self.explicitly_disable_kitty_keyboard_protocol, - ); - if let Some(pane_initial_contents) = &floating_pane_layout.pane_initial_contents { - new_pane.handle_pty_bytes(pane_initial_contents.as_bytes().into()); - new_pane.handle_pty_bytes("\n\r".as_bytes().into()); - } - new_pane.set_borderless(false); - new_pane.set_content_offset(Offset::frame(1)); - if let Some(held_command) = hold_for_command { - new_pane.hold(None, true, held_command.clone()); - } - resize_pty!( - new_pane, - self.os_api, - self.senders, - self.character_cell_size - )?; - self.floating_panes - .add_pane(PaneId::Terminal(*pid), Box::new(new_pane)); - if floating_pane_layout.focus.unwrap_or(false) { - focused_floating_pane = Some(PaneId::Terminal(*pid)); - } + floating_pane_layout, + )? + } else { + None + }; + if let Some(pid_to_focus) = pid_to_focus { + focused_floating_pane = Some(pid_to_focus); } } if let Some(focused_floating_pane) = focused_floating_pane { @@ -499,72 +629,68 @@ impl<'a> LayoutApplier<'a> { 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.character_cell_size)?; - self.floating_panes.add_pane(pane.pid(), pane); - } + let layout_has_floating_panes = self.floating_panes.has_panes(); + let mut positions_in_layout = floating_panes_layout.clone(); + let mut logical_position = 0; + for floating_pane_layout in positions_in_layout.iter_mut() { + floating_pane_layout.logical_position = Some(logical_position); + logical_position += 1; } - 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.character_cell_size)?; - self.floating_panes.add_pane(pane.pid(), pane); - } + let mut existing_tab_state = ExistingTabState::new(self.floating_panes.drain()); + let mut pane_applier = PaneApplier::new( + &mut self.tiled_panes, + &mut self.floating_panes, + &self.senders, + &self.character_cell_size, + ); + let mut panes_to_apply = vec![]; + let mut positions_left = vec![]; + + // look for exact matches, first by pane contents and then by logical position + for floating_pane_layout in positions_in_layout { + match existing_tab_state + .find_and_extract_exact_match_pane( + &floating_pane_layout.run, + floating_pane_layout.logical_position, + ) + .or_else(|| { + existing_tab_state.find_and_extract_pane_with_same_logical_position( + floating_pane_layout.logical_position, + ) + }) { + Some(pane) => { + panes_to_apply.push((pane, floating_pane_layout)); }, None => { - log::error!("could not find room for pane!") + positions_left.push(floating_pane_layout); }, } } + // fill the remaining panes by order of their logical position + for floating_pane_layout in positions_left { + if let Some(pane) = + existing_tab_state.find_and_extract_pane(floating_pane_layout.logical_position) + { + panes_to_apply.push((pane, floating_pane_layout)); + } + } + + // here we apply positioning to all panes by the order we found them + // this is because the positioning decisions themselves rely on this order for geoms that + // contain partial positioning information (eg. just x coords with no y or size) or no + // positioning information at all + for (pane, floating_pane_layout) in panes_to_apply.drain(..) { + pane_applier.apply_floating_panes_layout_to_floating_pane(pane, floating_pane_layout); + } + + // here we apply positioning on a best-effort basis to any remaining panes we've got (these + // are panes that exist in the tab state but not in the desired layout) + pane_applier.handle_remaining_floating_pane_ids(existing_tab_state, logical_position); + pane_applier.finalize_floating_panes_state(); + if layout_has_floating_panes { - pane_focuser.focus_floating_pane(&mut self.floating_panes, &mut self.os_api); Ok(true) } else { Ok(false) @@ -660,33 +786,6 @@ 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 @@ -704,28 +803,20 @@ impl<'a> LayoutApplier<'a> { 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 new(existing_panes: BTreeMap>) -> Self { + ExistingTabState { existing_panes } } pub fn find_and_extract_exact_match_pane( &mut self, run: &Option, - position_and_size: &PaneGeom, - default_to_closest_position: bool, + logical_position: Option, ) -> Option> { - let candidates = self.pane_candidates(run, position_and_size, default_to_closest_position); + let candidates = self.pane_candidates(); if let Some(current_pane_id_with_same_contents) = - self.find_pane_id_with_same_contents_and_location(&candidates, run, position_and_size) + self.find_pane_id_with_same_contents(&candidates, run, logical_position) { return self .existing_panes @@ -733,37 +824,38 @@ impl ExistingTabState { } None } - pub fn find_and_extract_pane( + pub fn find_and_extract_pane_with_same_logical_position( &mut self, - run: &Option, - position_and_size: &PaneGeom, - is_focused: bool, - default_to_closest_position: bool, + logical_position: Option, ) -> 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) + let candidates = self.pane_candidates(); + if let Some(current_pane_id_with_same_logical_position) = + self.find_pane_id_with_same_logical_position(&candidates, logical_position) { 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); + .remove(¤t_pane_id_with_same_logical_position); + } else { + return None; + } + } + pub fn find_and_extract_pane( + &mut self, + logical_position: Option, + ) -> Option> { + let candidates = self.pane_candidates(); + if let Some(current_pane_id_with_same_logical_position) = + self.find_pane_id_with_same_logical_position(&candidates, logical_position) + { + return self + .existing_panes + .remove(¤t_pane_id_with_same_logical_position); + } else { + match candidates.iter().next().map(|(pid, _p)| *pid).copied() { + Some(first_candidate) => self.existing_panes.remove(&first_candidate), + None => None, + } } - None } pub fn pane_ids(&self) -> Vec { self.existing_panes.keys().copied().collect() @@ -771,150 +863,194 @@ impl ExistingTabState { 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)> { + fn pane_candidates(&self) -> 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 + let a_logical_position = a.position_and_size().logical_position; + let b_logical_position = b.position_and_size().logical_position; + if a_logical_position != b_logical_position { + a_logical_position.cmp(&b_logical_position) } 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 { - a_id.cmp(&b_id) // just so it's a stable sort - } + a_id.cmp(&b_id) } }); 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, + pane_logical_position: Option, ) -> Option { - candidates + if run.is_none() { + return None; + } + let panes_with_same_contents = candidates .iter() - .find(|(_pid, p)| p.invoked_with() == run) - .map(|(pid, _p)| *pid) - .copied() + .filter(|(_pid, p)| p.invoked_with() == run) + .collect::>(); + if panes_with_same_contents.len() > 1 { + panes_with_same_contents + .iter() + .find(|(_pid, p)| p.position_and_size().logical_position == pane_logical_position) + .map(|(pid, _p)| *pid) + .copied() + .or_else(|| { + panes_with_same_contents + .iter() + .next() + .map(|(pid, _p)| *pid) + .copied() + }) + } else { + panes_with_same_contents + .iter() + .next() + .map(|(pid, _p)| *pid) + .copied() + } } - fn find_pane_id_with_same_contents_and_location( + fn find_pane_id_with_same_logical_position( &self, candidates: &Vec<(&PaneId, &Box)>, - run: &Option, - position: &PaneGeom, + logical_position: Option, ) -> Option { candidates .iter() - .find(|(_pid, p)| p.invoked_with() == run && p.position_and_size() == *position) + .find(|(_pid, p)| p.position_and_size().logical_position == logical_position) .map(|(pid, _p)| *pid) .copied() } } -#[derive(Default, Debug)] -struct PaneFocuser { - refocus_pane: bool, - pane_id_in_focused_location: Option, - expanded_stacked_pane_ids: Vec, +struct PaneApplier<'a> { + new_focused_pane_id: Option, + pane_ids_expanded_in_stack: Vec, + tiled_panes: &'a mut TiledPanes, + floating_panes: &'a mut FloatingPanes, + senders: ThreadSenders, + character_cell_size: Rc>>, } -impl PaneFocuser { - pub fn new(refocus_pane: bool) -> Self { - PaneFocuser { - refocus_pane, - ..Default::default() +impl<'a> PaneApplier<'a> { + pub fn new( + tiled_panes: &'a mut TiledPanes, + floating_panes: &'a mut FloatingPanes, + senders: &ThreadSenders, + character_cell_size: &Rc>>, + ) -> Self { + PaneApplier { + new_focused_pane_id: None, + pane_ids_expanded_in_stack: vec![], + tiled_panes, + floating_panes, + senders: senders.clone(), + character_cell_size: character_cell_size.clone(), } } - pub fn set_pane_id_in_focused_location( + pub fn apply_position_and_size_to_tiled_pane( &mut self, - is_focused: Option, - pane: &Box, + mut pane: Box, + position_and_size: PaneGeom, + layout: TiledPaneLayout, ) { - if is_focused.unwrap_or(false) && pane.selectable() { - self.pane_id_in_focused_location = Some(pane.pid()); + self.apply_layout_properties_to_pane(&mut pane, &layout, Some(position_and_size)); + if layout.focus.unwrap_or(false) { + self.new_focused_pane_id = Some(pane.pid()); } + if layout.is_expanded_in_stack { + self.pane_ids_expanded_in_stack.push(pane.pid()); + } + let _ = resize_pty!(pane, self.os_api, self.senders, self.character_cell_size); + self.tiled_panes + .add_pane_with_existing_geom(pane.pid(), pane); } - pub fn set_expanded_stacked_pane(&mut self, is_expanded_in_stack: bool, pane: &Box) { - if is_expanded_in_stack && pane.selectable() { - self.expanded_stacked_pane_ids.push(pane.pid()); - } - } - pub fn focus_tiled_pane(&self, tiled_panes: &mut TiledPanes) { - let mut panes_in_stack = vec![]; - for pane_id in &self.expanded_stacked_pane_ids { - panes_in_stack.append(&mut tiled_panes.expand_pane_in_stack(*pane_id)); - } - match self.pane_id_in_focused_location { - Some(pane_id_in_focused_location) => { - if self.refocus_pane { - tiled_panes.reapply_pane_focus(); - if !panes_in_stack.contains(&pane_id_in_focused_location) { - // we do not change stacked panes locations because this has already been done above - tiled_panes.switch_active_pane_with(pane_id_in_focused_location); - } - } else { - tiled_panes.reapply_pane_focus(); - } - }, - None => { - tiled_panes.reapply_pane_focus(); - }, - } - for pane_id in &self.expanded_stacked_pane_ids { - tiled_panes.expand_pane_in_stack(*pane_id); - } - } - pub fn focus_floating_pane( - &self, - floating_panes: &mut FloatingPanes, - os_api: &mut Box, + pub fn apply_floating_panes_layout_to_floating_pane( + &mut self, + mut pane: Box, + floating_panes_layout: FloatingPaneLayout, ) { - 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); + let position_and_size = self + .floating_panes + .position_floating_pane_layout(&floating_panes_layout); + if let Some(pane_title) = floating_panes_layout.name.as_ref() { + pane.set_title(pane_title.into()); + } + if floating_panes_layout.focus.unwrap_or(false) { + self.new_focused_pane_id = Some(pane.pid()); + } + self.apply_position_and_size_to_floating_pane(pane, position_and_size) + } + pub fn apply_position_and_size_to_floating_pane( + &mut self, + mut pane: Box, + position_and_size: PaneGeom, + ) { + pane.set_geom(position_and_size); + let _ = resize_pty!(pane, self.os_api, self.senders, self.character_cell_size); + self.floating_panes.add_pane(pane.pid(), pane); + } + + pub fn handle_remaining_tiled_pane_ids( + &mut self, + remaining_pane_ids: Vec, + mut existing_tab_state: ExistingTabState, + ) { + for pane_id in remaining_pane_ids { + if let Some(pane) = existing_tab_state.remove_pane(&pane_id) { + self.tiled_panes.insert_pane(pane.pid(), pane); } } } + pub fn handle_remaining_floating_pane_ids( + &mut self, + mut existing_tab_state: ExistingTabState, + logical_position: usize, + ) { + 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(mut position_and_size) => { + if let Some(pane) = existing_tab_state.remove_pane(&pane_id) { + position_and_size.logical_position = Some(logical_position); + self.apply_position_and_size_to_floating_pane(pane, position_and_size); + } + }, + None => { + log::error!("could not find room for pane!") + }, + } + } + } + pub fn finalize_tiled_state(&mut self) { + // do some housekeeping to apply various layout properties to panes + for pane_id in &self.pane_ids_expanded_in_stack { + self.tiled_panes.expand_pane_in_stack(*pane_id); + } + if let Some(pane_id) = self.new_focused_pane_id { + self.tiled_panes.focus_pane_for_all_clients(pane_id); + } + self.tiled_panes.reapply_pane_focus(); + } + pub fn finalize_floating_panes_state(&mut self) { + // do some housekeeping to apply various layout properties to panes + if let Some(pane_id) = self.new_focused_pane_id { + self.floating_panes.focus_pane_for_all_clients(pane_id); + } + self.floating_panes.reapply_pane_focus(); + } + 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()); + } + } } diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index de5bba65..3284203c 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -508,7 +508,8 @@ pub trait Pane { None } fn toggle_pinned(&mut self) {} - fn set_pinned(&mut self, should_be_pinned: bool) {} + fn set_pinned(&mut self, _should_be_pinned: bool) {} + fn reset_logical_position(&mut self) {} } #[derive(Clone, Debug)] @@ -731,12 +732,7 @@ impl Tab { } } } - fn relayout_floating_panes( - &mut self, - client_id: Option, - search_backwards: bool, - refocus_pane: bool, - ) -> Result<()> { + fn relayout_floating_panes(&mut self, search_backwards: bool) -> Result<()> { if let Some(layout_candidate) = self .swap_layouts .swap_floating_panes(&self.floating_panes, search_backwards) @@ -762,41 +758,18 @@ impl Tab { self.styled_underlines, self.explicitly_disable_kitty_keyboard_protocol, ) - .apply_floating_panes_layout_to_existing_panes( - &layout_candidate, - refocus_pane, - client_id, - )?; + .apply_floating_panes_layout_to_existing_panes(&layout_candidate)?; } self.set_force_render(); Ok(()) } - fn relayout_tiled_panes( - &mut self, - client_id: Option, - search_backwards: bool, - refocus_pane: bool, - best_effort: bool, - ) -> Result<()> { + fn relayout_tiled_panes(&mut self, search_backwards: 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, @@ -819,11 +792,7 @@ impl Tab { self.styled_underlines, self.explicitly_disable_kitty_keyboard_protocol, ) - .apply_tiled_panes_layout_to_existing_panes( - &layout_candidate, - refocus_pane, - client_id, - )?; + .apply_tiled_panes_layout_to_existing_panes(&layout_candidate)?; } self.tiled_panes.reapply_pane_frames(); let display_area = *self.display_area.borrow(); @@ -832,28 +801,24 @@ impl Tab { self.set_should_clear_display_before_rendering(); Ok(()) } - pub fn previous_swap_layout(&mut self, client_id: Option) -> Result<()> { + pub fn previous_swap_layout(&mut self) -> Result<()> { let search_backwards = true; if self.floating_panes.panes_are_visible() { - self.relayout_floating_panes(client_id, search_backwards, true)?; + self.relayout_floating_panes(search_backwards)?; } else { - self.relayout_tiled_panes(client_id, search_backwards, true, false)?; + self.relayout_tiled_panes(search_backwards)?; } self.senders .send_to_pty_writer(PtyWriteInstruction::ApplyCachedResizes) .with_context(|| format!("failed to update plugins with mode info"))?; Ok(()) } - pub fn next_swap_layout( - &mut self, - client_id: Option, - refocus_pane: bool, - ) -> Result<()> { + pub fn next_swap_layout(&mut self) -> Result<()> { let search_backwards = false; if self.floating_panes.panes_are_visible() { - self.relayout_floating_panes(client_id, search_backwards, refocus_pane)?; + self.relayout_floating_panes(search_backwards)?; } else { - self.relayout_tiled_panes(client_id, search_backwards, refocus_pane, false)?; + self.relayout_tiled_panes(search_backwards)?; } self.senders .send_to_pty_writer(PtyWriteInstruction::ApplyCachedResizes) @@ -1008,7 +973,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 - .extract_pane(focused_floating_pane_id, true, Some(client_id)) + .extract_pane(focused_floating_pane_id, true) .with_context(|| format!( "failed to find floating pane (ID: {focused_floating_pane_id:?}) to embed for client {client_id}", )) @@ -1026,16 +991,9 @@ impl Tab { // don't close the only pane on screen... return Ok(()); } - if let Some(embedded_pane_to_float) = - self.extract_pane(focused_pane_id, true, Some(client_id)) - { + if let Some(embedded_pane_to_float) = self.extract_pane(focused_pane_id, true) { self.show_floating_panes(); - self.add_floating_pane( - embedded_pane_to_float, - focused_pane_id, - None, - Some(client_id), - )?; + self.add_floating_pane(embedded_pane_to_float, focused_pane_id, None)?; } } Ok(()) @@ -1053,7 +1011,7 @@ impl Tab { if self.floating_panes.panes_contain(&pane_id) { if self.tiled_panes.has_room_for_new_pane() { let floating_pane_to_embed = self - .extract_pane(pane_id, true, None) + .extract_pane(pane_id, true) .with_context(|| { format!("failed to find floating pane (ID: {pane_id:?}) to embed",) }) @@ -1066,8 +1024,8 @@ impl Tab { // don't close the only pane on screen... return Ok(()); } - if let Some(embedded_pane_to_float) = self.extract_pane(pane_id, true, None) { - self.add_floating_pane(embedded_pane_to_float, pane_id, None, None)?; + if let Some(embedded_pane_to_float) = self.extract_pane(pane_id, true) { + self.add_floating_pane(embedded_pane_to_float, pane_id, None)?; } } Ok(()) @@ -1212,7 +1170,7 @@ impl Tab { .insert(pid, (is_scrollback_editor, new_pane)); Ok(()) } else if self.floating_panes.panes_are_visible() { - self.add_floating_pane(new_pane, pid, floating_pane_coordinates, client_id) + self.add_floating_pane(new_pane, pid, floating_pane_coordinates) } else { self.add_tiled_pane(new_pane, pid, client_id) } @@ -1914,7 +1872,7 @@ impl Tab { should_update_ui = true; }, Some(AdjustedInput::CloseThisPane) => { - self.close_pane(PaneId::Terminal(active_terminal_id), false, None); + self.close_pane(PaneId::Terminal(active_terminal_id), false); should_update_ui = true; }, Some(AdjustedInput::DropToShellInThisPane { working_dir }) => { @@ -2326,12 +2284,12 @@ impl Tab { // 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); + let _ = self.relayout_floating_panes(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); + let _ = self.relayout_tiled_panes(false); } self.set_should_clear_display_before_rendering(); self.senders @@ -2673,7 +2631,7 @@ impl Tab { self.senders .send_to_pty(PtyInstruction::ClosePane(pid)) .context("failed to close down to max terminals")?; - self.close_pane(pid, false, None); + self.close_pane(pid, false); } } Ok(()) @@ -2729,12 +2687,7 @@ impl Tab { self.draw_pane_frames, ); } - pub fn close_pane( - &mut self, - id: PaneId, - ignore_suppressed_panes: bool, - client_id: Option, - ) { + pub fn close_pane(&mut self, id: PaneId, ignore_suppressed_panes: bool) { // 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 // pane, we're moving it @@ -2763,7 +2716,7 @@ impl Tab { 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); + let _ = self.next_swap_layout(); } } else { if self.tiled_panes.fullscreen_is_active() { @@ -2776,7 +2729,7 @@ impl Tab { 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); + let _ = self.next_swap_layout(); } }; let _ = self.senders.send_to_plugin(PluginInstruction::Update(vec![( @@ -2789,12 +2742,17 @@ impl Tab { &mut self, id: PaneId, dont_swap_if_suppressed: bool, - client_id: Option, ) -> Option> { if !dont_swap_if_suppressed && self.suppressed_panes.contains_key(&id) { // this is done for the scrollback editor return match self.replace_pane_with_suppressed_pane(id) { - Ok(pane) => pane, + Ok(mut pane) => { + // we do this so that the logical index will not affect ordering in the target tab + if let Some(pane) = pane.as_mut() { + pane.reset_logical_position(); + } + pane + }, Err(e) => { Err::<(), _>(e) .with_context(|| format!("failed to close pane {:?}", id)) @@ -2804,7 +2762,7 @@ impl Tab { }; } if self.floating_panes.panes_contain(&id) { - let closed_pane = self.floating_panes.remove_pane(id); + let mut closed_pane = self.floating_panes.remove_pane(id); self.floating_panes.move_clients_out_of_pane(id); if !self.floating_panes.has_panes() { self.hide_floating_panes(); @@ -2818,21 +2776,29 @@ impl Tab { 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); + let _ = self.next_swap_layout(); + } + // we do this so that the logical index will not affect ordering in the target tab + if let Some(closed_pane) = closed_pane.as_mut() { + closed_pane.reset_logical_position(); } closed_pane } else if self.tiled_panes.panes_contain(&id) { if self.tiled_panes.fullscreen_is_active() { self.tiled_panes.unset_fullscreen(); } - let closed_pane = self.tiled_panes.remove_pane(id); + let mut closed_pane = self.tiled_panes.remove_pane(id); self.set_force_render(); self.tiled_panes.set_force_render(); if self.auto_layout && !self.swap_layouts.is_tiled_damaged() { 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); + let _ = self.next_swap_layout(); + } + // we do this so that the logical index will not affect ordering in the target tab + if let Some(closed_pane) = closed_pane.as_mut() { + closed_pane.reset_logical_position(); } closed_pane } else if self.suppressed_panes.contains_key(&id) { @@ -2923,7 +2889,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, Some(client_id)); + self.close_pane(active_floating_pane_id, false); self.senders .send_to_pty(PtyInstruction::ClosePane(active_floating_pane_id)) .with_context(|| err_context(active_floating_pane_id))?; @@ -2931,7 +2897,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, Some(client_id)); + self.close_pane(active_pane_id, false); self.senders .send_to_pty(PtyInstruction::ClosePane(active_pane_id)) .with_context(|| err_context(active_pane_id))?; @@ -4144,7 +4110,7 @@ impl Tab { pane.1.set_selectable(true); if should_float { self.show_floating_panes(); - self.add_floating_pane(pane.1, pane_id, None, Some(client_id)) + self.add_floating_pane(pane.1, pane_id, None) } else { self.hide_floating_panes(); self.add_tiled_pane(pane.1, pane_id, Some(client_id)) @@ -4157,8 +4123,7 @@ impl Tab { match self.suppressed_panes.remove(&pane_id) { Some(pane) => { self.show_floating_panes(); - self.add_floating_pane(pane.1, pane_id, None, None) - .non_fatal(); + self.add_floating_pane(pane.1, pane_id, None).non_fatal(); self.floating_panes.focus_pane_for_all_clients(pane_id); }, None => { @@ -4171,7 +4136,7 @@ impl Tab { // not take it out of there when another pane is closed (eg. like happens with the // scrollback editor), but it has to take itself out on its own (eg. a plugin using the // show_self() method) - if let Some(pane) = self.extract_pane(pane_id, true, client_id) { + if let Some(pane) = self.extract_pane(pane_id, true) { let is_scrollback_editor = false; self.suppressed_panes .insert(pane_id, (is_scrollback_editor, pane)); @@ -4198,7 +4163,6 @@ impl Tab { mut pane: Box, pane_id: PaneId, floating_pane_coordinates: Option, - client_id: Option, ) -> Result<()> { let err_context = || format!("failed to add floating pane"); if let Some(mut new_pane_geom) = self.floating_panes.find_room_for_new_pane() { @@ -4223,7 +4187,7 @@ impl Tab { // 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)?; + self.next_swap_layout()?; } Ok(()) } @@ -4256,7 +4220,7 @@ impl Tab { // 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)?; + self.next_swap_layout()?; } Ok(()) } diff --git a/zellij-server/src/tab/swap_layouts.rs b/zellij-server/src/tab/swap_layouts.rs index 9b37eede..e61fb241 100644 --- a/zellij-server/src/tab/swap_layouts.rs +++ b/zellij-server/src/tab/swap_layouts.rs @@ -244,12 +244,18 @@ impl SwapLayouts { Some(swap_layout) => { for (constraint, layout) in swap_layout.0.iter() { if self.state_fits_tiled_panes_constraint(constraint, tiled_panes) { + let focus_layout_if_not_focused = true; 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), false) + .position_panes_in_space( + &display_area, + Some(pane_count), + false, + focus_layout_if_not_focused, + ) .is_ok() { return Some(layout.clone()); @@ -274,12 +280,18 @@ impl SwapLayouts { ) -> Option { for swap_layout in self.swap_tiled_layouts.iter() { for (_constraint, layout) in swap_layout.0.iter() { + let focus_layout_if_not_focused = true; 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), false) + .position_panes_in_space( + &display_area, + Some(pane_count), + false, + focus_layout_if_not_focused, + ) .is_ok() { return Some(layout.clone()); 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 index 440d15cb..c5f32f9c 100644 --- 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 @@ -1,17 +1,17 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5109 +assertion_line: 6660 expression: snapshot --- 00 (C): I am a tab bar -01 (C): ┌ command2 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐┌ command1 ────────────────────────────┐ +01 (C): ┌ command1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐┌ command2 ────────────────────────────┐ 02 (C): │ ││ ││ │ 03 (C): │ ││ ││ │ 04 (C): │ ││ ││ │ 05 (C): │ ││ ││ │ 06 (C): │ ││ ││ │ 07 (C): │ ││ ││ │ -08 (C): │ Waiting to run: command2 ││ ││ Waiting to run: command1 │ +08 (C): │ Waiting to run: command1 ││ ││ Waiting to run: command2 │ 09 (C): │ ││ ││ │ 10 (C): │ run, drop to shell, run, drop to shell, exit ││ ││l-c> exit │ 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 index bb6bcaab..988e2e8c 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 4299 +assertion_line: 5546 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -17,8 +17,8 @@ expression: snapshot 11 (C): │ │ 12 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 13 (C): ┌ Pane #2 ────────────────────────────────────────────────────────┐┌ Pane #4 ───────────────────────────────────────────┐ -14 (C): │ │┌ Pane #3 ───────────────────────────────────────────┐ -15 (C): │ │┌ Pane #5 ───────────────────────────────────────────┐ +14 (C): │ │┌ Pane #5 ───────────────────────────────────────────┐ +15 (C): │ │┌ Pane #6 ───────────────────────────────────────────┐ 16 (C): │ ││ │ 17 (C): │ ││ │ 18 (C): │ ││ │ @@ -31,7 +31,7 @@ expression: snapshot 25 (C): │ ││ │ 26 (C): │ ││ │ 27 (C): └─────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────────┘ -28 (C): ┌ Pane #6 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +28 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 29 (C): │ │ 30 (C): │ │ 31 (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 index 644233cd..60b735fc 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 4237 +assertion_line: 5446 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -17,8 +17,8 @@ expression: snapshot 11 (C): │ │ 12 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 13 (C): ┌ Pane #2 ──────────────────────────────────────────────────┐┌ Pane #4 ─────────────────────────────────────────────────┐ -14 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐ -15 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐ +14 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐ +15 (C): │ │┌ Pane #6 ─────────────────────────────────────────────────┐ 16 (C): │ ││ │ 17 (C): │ ││ │ 18 (C): │ ││ │ @@ -28,7 +28,7 @@ expression: snapshot 22 (C): │ ││ │ 23 (C): │ ││ │ 24 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ -25 (C): ┌ Pane #6 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +25 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 26 (C): │ │ 27 (C): │ │ 28 (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 index ac85d9c1..7807f491 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 4024 +assertion_line: 5240 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -17,8 +17,8 @@ expression: snapshot 11 (C): │ │ 12 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 13 (C): ┌ Pane #2 ───────────────────────────────────────────┐┌ Pane #4 ────────────────────────────────────────────────────────┐ -14 (C): │ │┌ Pane #3 ────────────────────────────────────────────────────────┐ -15 (C): │ │┌ Pane #5 ────────────────────────────────────────────────────────┐ +14 (C): │ │┌ Pane #5 ────────────────────────────────────────────────────────┐ +15 (C): │ │┌ Pane #6 ────────────────────────────────────────────────────────┐ 16 (C): │ ││ │ 17 (C): │ ││ │ 18 (C): │ ││ │ @@ -31,7 +31,7 @@ expression: snapshot 25 (C): │ ││ │ 26 (C): │ ││ │ 27 (C): └────────────────────────────────────────────────────┘└─────────────────────────────────────────────────────────────────┘ -28 (C): ┌ Pane #6 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +28 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 29 (C): │ │ 30 (C): │ │ 31 (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 index a18772ac..8f0c5f6b 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 3961 +assertion_line: 5139 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -17,8 +17,8 @@ expression: snapshot 11 (C): │ │ 12 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 13 (C): ┌ Pane #2 ──────────────────────────────────────────────────┐┌ Pane #4 ─────────────────────────────────────────────────┐ -14 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐ -15 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐ +14 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐ +15 (C): │ │┌ Pane #6 ─────────────────────────────────────────────────┐ 16 (C): │ ││ │ 17 (C): │ ││ │ 18 (C): │ ││ │ @@ -31,7 +31,7 @@ expression: snapshot 25 (C): │ ││ │ 26 (C): │ ││ │ 27 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ -28 (C): ┌ Pane #6 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +28 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 29 (C): │ │ 30 (C): │ │ 31 (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 index 8416d6e0..88fbd458 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 4346 +assertion_line: 5855 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐ 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 index 17d9500e..5902f8ba 100644 --- 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 @@ -1,9 +1,9 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 3699 +assertion_line: 4932 expression: snapshot --- -00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐ +00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ 01 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐ 02 (C): │ ││ │ 03 (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 index b065d0bc..3804d05b 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 4517 +assertion_line: 6163 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐ 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 index fec3d753..dcf4f402 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 4628 +assertion_line: 6366 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐ 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 index 77530c7c..5ce1e558 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 4399 +assertion_line: 5954 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐ 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 index 41100f1e..9d2ada26 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 4454 +assertion_line: 6055 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐ 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 index 738ed813..1c5ae4cf 100644 --- 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 @@ -1,22 +1,22 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5007 +assertion_line: 6564 expression: snapshot --- 00 (C): I am a 01 (C): status bar -02 (C): ┌ command1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +02 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 03 (C): │ │ -04 (C): │ Waiting to run: command1 │ +04 (C): │ Waiting to run: command2 │ 05 (C): │ │ 06 (C): │ run, drop to shell, exit │ -07 (C): └─ run, drop to shell, exit ─────────────────────────────────────────────────────────────────────┘ -08 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +07 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +08 (C): ┌ command1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 09 (C): │ │ -10 (C): │ Waiting to run: command2 │ +10 (C): │ Waiting to run: command1 │ 11 (C): │ │ 12 (C): │ run, drop to shell, exit │ -13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +13 (C): └─ run, drop to shell, exit ─────────────────────────────────────────────────────────────────────┘ 14 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 15 (C): │ │ 16 (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 index e84b8fc6..13848a2b 100644 --- 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 @@ -1,10 +1,10 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 8040 +assertion_line: 8043 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -01 (C): │ ┌ Pane #3 ─────────────────────────────────── PIN [ ] ┐ ┌ Pane #2 ─────────────────────────────────── PIN [ ] ┐ │ +01 (C): │ ┌ Pane #2 ─────────────────────────────────── PIN [ ] ┐ ┌ Pane #3 ─────────────────────────────────── PIN [ ] ┐ │ 02 (C): │ │ │ │ │ │ 03 (C): │ │ │ │ │ │ 04 (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 index 469f2b26..2d9209ab 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5099 +assertion_line: 7117 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ @@ -8,17 +8,17 @@ expression: snapshot 02 (C): │ ││ │ 03 (C): │ ││ │ 04 (C): │ │└──────────────────────────────────────────────────────────┘ -05 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐ +05 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐ 06 (C): │ ││ │ 07 (C): │ ││ │ 08 (C): │ ││ │ 09 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ -10 (C): ┌ Pane #6 ──────────────────────────────────────────────────┐┌ Pane #4 ─────────────────────────────────────────────────┐ +10 (C): ┌ Pane #3 ──────────────────────────────────────────────────┐┌ Pane #5 ─────────────────────────────────────────────────┐ 11 (C): │ ││ │ 12 (C): │ ││ │ 13 (C): │ ││ │ 14 (C): │ │└──────────────────────────────────────────────────────────┘ -15 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐ +15 (C): │ │┌ Pane #6 ─────────────────────────────────────────────────┐ 16 (C): │ ││ │ 17 (C): │ ││ │ 18 (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 index caf0b98a..316e6587 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5099 +assertion_line: 7119 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ @@ -8,17 +8,17 @@ expression: snapshot 02 (C): │ ││ │ 03 (C): │ ││ │ 04 (C): │ │└──────────────────────────────────────────────────────────┘ -05 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐ +05 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐ 06 (C): └───────────────────────────────────────────────────────────┘│ │ -07 (C): ┌ Pane #6 ──────────────────────────────────────────────────┐│ │ +07 (C): ┌ Pane #3 ──────────────────────────────────────────────────┐│ │ 08 (C): │ ││ │ 09 (C): │ │└──────────────────────────────────────────────────────────┘ -10 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐ +10 (C): │ │┌ Pane #6 ─────────────────────────────────────────────────┐ 11 (C): │ ││ │ 12 (C): │ ││ │ 13 (C): └───────────────────────────────────────────────────────────┘│ │ -14 (C): ┌ Pane #7 ──────────────────────────────────────────────────┐└──────────────────────────────────────────────────────────┘ -15 (C): │ │┌ Pane #5 ─────────────────────────────────────────────────┐ +14 (C): ┌ Pane #4 ──────────────────────────────────────────────────┐└──────────────────────────────────────────────────────────┘ +15 (C): │ │┌ Pane #7 ─────────────────────────────────────────────────┐ 16 (C): │ ││ │ 17 (C): │ ││ │ 18 (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 index 8956fb0f..4df0ed53 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5099 +assertion_line: 7119 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ @@ -8,17 +8,17 @@ expression: snapshot 02 (C): │ ││ │ 03 (C): │ ││ │ 04 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ -05 (C): ┌ Pane #6 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐ +05 (C): ┌ Pane #3 ──────────────────────────────────────────────────┐┌ Pane #6 ─────────────────────────────────────────────────┐ 06 (C): │ ││ │ 07 (C): │ ││ │ 08 (C): │ ││ │ 09 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ -10 (C): ┌ Pane #7 ──────────────────────────────────────────────────┐┌ Pane #4 ─────────────────────────────────────────────────┐ +10 (C): ┌ Pane #4 ──────────────────────────────────────────────────┐┌ Pane #7 ─────────────────────────────────────────────────┐ 11 (C): │ ││ │ 12 (C): │ ││ │ 13 (C): │ ││ │ 14 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ -15 (C): ┌ Pane #8 ──────────────────────────────────────────────────┐┌ Pane #5 ─────────────────────────────────────────────────┐ +15 (C): ┌ Pane #5 ──────────────────────────────────────────────────┐┌ Pane #8 ─────────────────────────────────────────────────┐ 16 (C): │ ││ │ 17 (C): │ ││ │ 18 (C): │ ││ │ 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 index 746d110e..a19c592b 100644 --- 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 @@ -1,9 +1,9 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 4667 +assertion_line: 6466 expression: snapshot --- -00 (C): ┌ Pane #5 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ 03 (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 index 8d591ff0..9c36e796 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 7793 +assertion_line: 7796 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -18,7 +18,7 @@ expression: snapshot 12 (C): │ │ │ │ │ 13 (C): │ │ │ │ │ 14 (C): │ └──────────────────────────────────────────────────────────┘ │ │ -15 (C): │ │ │ run, drop to shell, exit │ │ +15 (C): │ │ │ │ │ 16 (C): │ └─│ │ │ 17 (C): │ │ │ │ 18 (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 index 5b7bd24e..c0f8de17 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 4831 +assertion_line: 6753 expression: snapshot --- 00 (C): I am a @@ -11,13 +11,13 @@ expression: snapshot 05 (C): │ │ 06 (C): │ │ 07 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -08 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +08 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 09 (C): │ │ 10 (C): │ │ 11 (C): │ │ 12 (C): │ │ 13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -14 (C): ┌ Pane #3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +14 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 15 (C): │ │ 16 (C): │ │ 17 (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 index 3ec04981..29e05b28 100644 --- 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 @@ -1,26 +1,26 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5307 +assertion_line: 6849 expression: snapshot --- 00 (C): I am a 01 (C): status bar -02 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +02 (C): ┌ command1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 03 (C): │ │ -04 (C): │ │ +04 (C): │ Waiting to run: command1 │ 05 (C): │ │ -06 (C): │ │ -07 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -08 (C): ┌ command1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +06 (C): │ run, drop to shell, exit │ +07 (C): └─ run, drop to shell, exit ─────────────────────────────────────────────────────────────────────┘ +08 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 09 (C): │ │ -10 (C): │ Waiting to run: command1 │ +10 (C): │ Waiting to run: command2 │ 11 (C): │ │ 12 (C): │ run, drop to shell, exit │ -13 (C): └─ run, drop to shell, exit ─────────────────────────────────────────────────────────────────────┘ -14 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -15 (C): │ Waiting to run: command2 │ +13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +14 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +15 (C): │ │ 16 (C): │ │ -17 (C): │ run, drop to shell, exit │ +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_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 index 9a5f4867..48031c36 100644 --- 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 @@ -1,9 +1,9 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5510 +assertion_line: 7019 expression: snapshot --- -00 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +00 (C): ┌ zellij:tab-bar ───────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 02 (C): ┌ command1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 03 (C): │ │ @@ -11,16 +11,16 @@ expression: snapshot 05 (C): │ │ 06 (C): │ run, drop to shell, exit │ 07 (C): └─ run, drop to shell, exit ─────────────────────────────────────────────────────────────────────┘ -08 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -09 (C): │ │ -10 (C): │ Waiting to run: command2 │ +08 (C): ┌ zellij:status-bar ────────────────────────────────────────────────────────────────────────────────────────────────────┐ +09 (C): │I am a │ +10 (C): │status bar │ 11 (C): │ │ -12 (C): │ run, drop to shell, exit │ +12 (C): │ │ 13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -14 (C): ┌ zellij:status-bar ────────────────────────────────────────────────────────────────────────────────────────────────────┐ -15 (C): │I am a │ -16 (C): │status bar │ +14 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +15 (C): │ │ +16 (C): │ │ 17 (C): │ │ 18 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ -19 (C): ┌ zellij:tab-bar ───────────────────────────────────────────────────────────────────────────────────────────────────────┐ +19 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_layout.snap index 2d185efe..a8a050a3 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_layout.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_layout.snap @@ -1,9 +1,9 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 2170 +assertion_line: 3375 expression: snapshot --- -00 (C): ┌ Pane #1 ──────────────────────────────┐┌ Pane #2 ─────────────────────────────┐┌ Pane #6 ─────────────────────────────┐ +00 (C): ┌ Pane #1 ──────────────────────────────┐┌ Pane #2 ─────────────────────────────┐┌ Pane #3 ─────────────────────────────┐ 01 (C): │ ││ ││ │ 02 (C): │ ││ ││ │ 03 (C): │ ││ ││ │ @@ -13,7 +13,7 @@ expression: snapshot 07 (C): │ ││ ││ │ 08 (C): │ ││ ││ │ 09 (C): │ │└──────────────────────────────────────┘│ │ -10 (C): │ │┌ Pane #3 ───┐┌ Pane #4 ──┐┌ Pane #5 ──┐│ │ +10 (C): │ │┌ Pane #4 ───┐┌ Pane #5 ──┐┌ Pane #6 ──┐│ │ 11 (C): │ ││ ││ ││ ││ │ 12 (C): │ ││ ││ ││ ││ │ 13 (C): │ ││ ││ ││ ││ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_uneven_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_uneven_layout.snap index 6ac556ba..20fa9ad2 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_uneven_layout.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_nested_uneven_layout.snap @@ -1,19 +1,19 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 2204 +assertion_line: 3409 expression: snapshot --- -00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ +00 (C): ┌ Pane #1 ──────────────────────────────────────────────────┐┌ Pane #3 ─────────────────────────────────────────────────┐ 01 (C): │ ││ │ 02 (C): │ ││ │ 03 (C): │ ││ │ 04 (C): │ │└──────────────────────────────────────────────────────────┘ -05 (C): │ │┌ Pane #3 ─────────────────────────────────────────────────┐ +05 (C): │ │┌ Pane #4 ─────────────────────────────────────────────────┐ 06 (C): │ ││ │ 07 (C): │ ││ │ 08 (C): │ ││ │ 09 (C): └───────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ -10 (C): ┌ Pane #4 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +10 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 11 (C): │ │ 12 (C): │ │ 13 (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 index d72b4f8c..e780fafa 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 8192 +assertion_line: 8199 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,18 +8,18 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #4 ──────────────────────────────────────── PIN [ ] ┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ -07 (C): │ │ │ ┐ │ -08 (C): │ │ │ │ │ -09 (C): │ │ │ │ ┐ │ -10 (C): │ │ │ │ │ │ -11 (C): │ │ │ │ │ │ -12 (C): │ │ │ │ │ │ -13 (C): │ │ │ │ │ │ -14 (C): │ └──────────────────────────────────────────────────────────┘ │ │ │ -15 (C): │ │ │ │ │ -16 (C): │ └──────────────────────────────────────────────────────────┘ │ │ +07 (C): │ │ ┌ Pane #3 ──────────────────────────────────────── PIN [ ] ┐ │ +08 (C): │ │ │ │ │ +09 (C): │ │ │ ┌ Pane #4 ──────────────────────────────────────── PIN [ ] ┐ │ +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 index 4614d7e6..812d985e 100644 --- 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 @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 8266 +assertion_line: 8267 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,16 +8,16 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #4 ──────────────────────────────────────── PIN [ ] ┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ -07 (C): │ │ │ ┐ │ -08 (C): │ │ │ │ │ -09 (C): │ │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ -10 (C): │ │ │ │ │ -11 (C): │ │ │ │ │ -12 (C): │ │ │ │ │ -13 (C): │ │ │ │ │ -14 (C): │ └───│ │ │ +07 (C): │ │ ┌ Pane #3 ──────────────────────────────────────── PIN [ ] ┐ │ +08 (C): │ │ │ │ │ +09 (C): │ │ │ ┌ Pane #4 ──────────────────────────────────────── PIN [ ] ┐ │ +10 (C): │ │ │ │ │ │ +11 (C): │ │ │ │ │ │ +12 (C): │ │ │ │ │ │ +13 (C): │ │ │ │ │ │ +14 (C): │ └─│ │ │ │ 15 (C): │ │ │ │ │ 16 (C): │ └─│ │ │ 17 (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 index ba1a4e3f..af7ba028 100644 --- 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 @@ -1,9 +1,9 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5216 +assertion_line: 7268 expression: snapshot --- -00 (C): ┌ Pane #2 ──────────────────────────────┐┌ Pane #1 ─────────────────────────────┐┌ Pane #3 ─────────────────────────────┐ +00 (C): ┌ Pane #1 ──────────────────────────────┐┌ Pane #2 ─────────────────────────────┐┌ Pane #3 ─────────────────────────────┐ 01 (C): │ ││ ││ │ 02 (C): │ ││ ││ │ 03 (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 index d5f33377..4841269b 100644 --- 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 @@ -1,9 +1,9 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5274 +assertion_line: 7345 expression: snapshot --- -00 (C): ┌ Pane #1 ──────────────────────────────┐┌ Pane #3 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ +00 (C): ┌ Pane #1 ──────────────────────────────┐┌ Pane #2 ─────────────────────────────┐┌ Pane #3 ─────────────────────────────┐ 01 (C): │ ││ ││ │ 02 (C): │ ││ ││ │ 03 (C): │ ││ ││ │ diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs index fa937eae..76b4474b 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -2754,7 +2754,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, None); + tab.close_pane(new_pane_id, false); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -2786,7 +2786,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, None); + tab.close_pane(editor_pane_id, false); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -2814,7 +2814,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, None); + tab.close_pane(new_pane_id, false); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -2847,7 +2847,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, None); + tab.close_pane(editor_pane_id, false); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -3757,7 +3757,7 @@ fn can_swap_tiled_layout_at_runtime() { Some(client_id), ) .unwrap(); - tab.next_swap_layout(Some(client_id), false).unwrap(); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -3830,7 +3830,7 @@ fn can_swap_floating_layout_at_runtime() { Some(client_id), ) .unwrap(); - tab.next_swap_layout(Some(client_id), false).unwrap(); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -3889,10 +3889,10 @@ fn swapping_layouts_after_resize_snaps_to_current_layout() { Some(client_id), ) .unwrap(); - tab.next_swap_layout(Some(client_id), false).unwrap(); + tab.next_swap_layout().unwrap(); tab.resize(client_id, ResizeStrategy::new(Resize::Increase, None)) .unwrap(); - tab.next_swap_layout(Some(client_id), false).unwrap(); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -4502,7 +4502,7 @@ fn move_focus_down_into_stacked_panes() { tab { pane pane split_direction="vertical" { - pane focus=true + pane pane stacked=true { children; } } pane @@ -4620,7 +4620,7 @@ fn close_main_stacked_pane() { Some(client_id), ) .unwrap(); - tab.close_pane(new_pane_id_2, false, None); + tab.close_pane(new_pane_id_2, false); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -4644,7 +4644,7 @@ fn close_main_stacked_pane_in_mid_stack() { swap_tiled_layout { tab { pane split_direction="vertical" { - pane focus=true + pane pane stacked=true { children; } } } @@ -4720,7 +4720,7 @@ fn close_main_stacked_pane_in_mid_stack() { 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.close_pane(new_pane_id_3, false); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -4744,7 +4744,7 @@ fn close_one_liner_stacked_pane_below_main_pane() { swap_tiled_layout { tab { pane split_direction="vertical" { - pane focus=true + pane pane stacked=true { children; } } } @@ -4821,7 +4821,7 @@ fn close_one_liner_stacked_pane_below_main_pane() { 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.close_pane(new_pane_id_2, false); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -4845,7 +4845,7 @@ fn close_one_liner_stacked_pane_above_main_pane() { swap_tiled_layout { tab { pane split_direction="vertical" { - pane focus=true + pane pane stacked=true { children; } } } @@ -4921,7 +4921,7 @@ fn close_one_liner_stacked_pane_above_main_pane() { 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.close_pane(new_pane_id_2, false); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -5226,7 +5226,6 @@ fn can_increase_size_of_main_pane_in_stack_non_directionally() { Some(client_id), ) .unwrap(); - let _ = tab.move_focus_up(client_id); let _ = tab.move_focus_right(client_id); tab.resize(client_id, ResizeStrategy::new(Resize::Increase, None)) .unwrap(); @@ -5534,7 +5533,6 @@ fn can_increase_size_into_pane_stack_non_directionally() { Some(client_id), ) .unwrap(); - let _ = tab.move_focus_up(client_id); tab.resize(client_id, ResizeStrategy::new(Resize::Increase, None)) .unwrap(); tab.render(&mut output).unwrap(); @@ -6069,7 +6067,7 @@ fn close_stacked_pane_with_previously_focused_other_pane() { swap_tiled_layout { tab { pane split_direction="vertical" { - pane focus=true + pane pane stacked=true { children; } } pane @@ -6147,7 +6145,7 @@ fn close_stacked_pane_with_previously_focused_other_pane() { .unwrap(); tab.handle_left_click(&Position::new(1, 71), client_id) .unwrap(); - tab.close_pane(PaneId::Terminal(4), false, None); + tab.close_pane(PaneId::Terminal(4), false); tab.render(&mut output).unwrap(); let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position( output.serialize().unwrap().get(&client_id).unwrap(), @@ -6250,7 +6248,7 @@ fn close_pane_near_stacked_panes() { Some(client_id), ) .unwrap(); - tab.close_pane(PaneId::Terminal(6), false, None); + tab.close_pane(PaneId::Terminal(6), false); tab.render(&mut output).unwrap(); let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position( output.serialize().unwrap().get(&client_id).unwrap(), @@ -6518,8 +6516,10 @@ fn layout_with_plugins_and_commands_swaped_properly() { let mut command_1 = RunCommand::default(); command_1.command = PathBuf::from("command1"); + command_1.hold_on_close = true; let mut command_2 = RunCommand::default(); command_2.command = PathBuf::from("command2"); + command_2.hold_on_close = true; 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(); @@ -6551,7 +6551,7 @@ fn layout_with_plugins_and_commands_swaped_properly() { ); 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.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -6647,8 +6647,8 @@ fn base_layout_is_included_in_swap_layouts() { ); 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.next_swap_layout().unwrap(); + tab.previous_swap_layout().unwrap(); // move back to the base layout tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -6740,7 +6740,7 @@ fn swap_layouts_including_command_panes_absent_from_existing_layout() { ); 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.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -6836,7 +6836,7 @@ fn swap_layouts_not_including_command_panes_present_in_existing_layout() { ); 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.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -6914,7 +6914,7 @@ fn swap_layouts_including_plugin_panes_absent_from_existing_layout() { )), true, ); - tab.next_swap_layout(Some(client_id), false).unwrap(); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -7006,7 +7006,7 @@ fn swap_layouts_not_including_plugin_panes_present_in_existing_layout() { ); 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.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -7080,9 +7080,9 @@ fn new_pane_in_auto_layout() { (62, 11), (62, 15), (62, 16), - (1, 11), - (1, 15), - (1, 16), + (62, 16), + (62, 16), + (62, 16), ]; for i in 0..7 { let new_pane_id = i + 2; @@ -7175,7 +7175,7 @@ fn when_swapping_tiled_layouts_in_a_damaged_state_layout_and_pane_focus_are_unch ResizeStrategy::new(Resize::Increase, Some(Direction::Down)), ) .unwrap(); - tab.next_swap_layout(Some(client_id), false).unwrap(); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position( @@ -7249,7 +7249,7 @@ fn when_swapping_tiled_layouts_in_an_undamaged_state_pane_focuses_on_focused_nod true, ); tab.move_focus_down(client_id); - tab.next_swap_layout(Some(client_id), true).unwrap(); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position( @@ -7324,7 +7324,8 @@ fn when_swapping_tiled_layouts_in_an_undamaged_state_with_no_focus_node_pane_foc true, ); tab.move_focus_down(client_id); - tab.next_swap_layout(Some(client_id), true).unwrap(); + tab.move_focus_down(client_id); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position( @@ -7399,7 +7400,7 @@ fn when_closing_a_pane_in_auto_layout_the_focus_goes_to_last_focused_pane() { ); let _ = tab.move_focus_down(client_id); let _ = tab.move_focus_down(client_id); - tab.close_pane(PaneId::Terminal(3), false, Some(client_id)); + tab.close_pane(PaneId::Terminal(3), false); tab.render(&mut output).unwrap(); let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position( @@ -7498,7 +7499,7 @@ fn floating_layout_with_plugins_and_commands_swaped_properly() { ); 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.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -7592,8 +7593,8 @@ fn base_floating_layout_is_included_in_swap_layouts() { ); 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.next_swap_layout().unwrap(); + tab.previous_swap_layout().unwrap(); // move back to the base layout tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -7685,7 +7686,7 @@ fn swap_floating_layouts_including_command_panes_absent_from_existing_layout() { ); 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.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -7781,7 +7782,7 @@ fn swap_floating_layouts_not_including_command_panes_present_in_existing_layout( ); 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.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -7852,7 +7853,7 @@ fn swap_floating_layouts_including_plugin_panes_absent_from_existing_layout() { )), true, ); - tab.next_swap_layout(Some(client_id), false).unwrap(); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -7940,7 +7941,7 @@ fn swap_floating_layouts_not_including_plugin_panes_present_in_existing_layout() ); 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.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let snapshot = take_snapshot( output.serialize().unwrap().get(&client_id).unwrap(), @@ -7974,9 +7975,9 @@ fn new_floating_pane_in_auto_layout() { 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%"; } + pane { y "55%"; width "45%"; height "45%"; } } } } @@ -8101,7 +8102,7 @@ fn when_swapping_floating_layouts_in_a_damaged_state_layout_and_pane_focus_are_u ResizeStrategy::new(Resize::Increase, Some(Direction::Down)), ) .unwrap(); - tab.next_swap_layout(Some(client_id), true).unwrap(); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position( @@ -8140,7 +8141,7 @@ fn when_swapping_floating_layouts_in_an_undamaged_state_pane_focuses_on_focused_ layout { swap_floating_layout { floating_panes { - pane focus=true + pane pane pane } @@ -8174,7 +8175,7 @@ fn when_swapping_floating_layouts_in_an_undamaged_state_pane_focuses_on_focused_ )), true, ); - tab.next_swap_layout(Some(client_id), true).unwrap(); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position( @@ -8185,7 +8186,7 @@ fn when_swapping_floating_layouts_in_an_undamaged_state_pane_focuses_on_focused_ ); assert_eq!( cursor_coordinates, - Some((31, 6)), + Some((35, 10)), "cursor coordinates moved to the new pane", ); @@ -8204,7 +8205,7 @@ fn when_swapping_floating_layouts_in_an_undamaged_state_with_no_focus_node_pane_ let base_layout = r#" layout { floating_panes { - pane focus=true + pane pane pane } @@ -8248,7 +8249,7 @@ fn when_swapping_floating_layouts_in_an_undamaged_state_with_no_focus_node_pane_ )), true, ); - tab.next_swap_layout(Some(client_id), true).unwrap(); + tab.next_swap_layout().unwrap(); tab.render(&mut output).unwrap(); let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position( @@ -8323,7 +8324,7 @@ fn when_closing_a_floating_pane_in_auto_layout_the_focus_goes_to_last_focused_pa ); tab.move_focus_up(client_id); tab.move_focus_up(client_id); - tab.close_pane(PaneId::Terminal(1), false, Some(client_id)); + tab.close_pane(PaneId::Terminal(1), false); tab.render(&mut output).unwrap(); let (snapshot, cursor_coordinates) = take_snapshot_and_cursor_position( diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs index b664910f..438046fd 100644 --- a/zellij-server/src/tab/unit/tab_tests.rs +++ b/zellij-server/src/tab/unit/tab_tests.rs @@ -14429,7 +14429,7 @@ fn correctly_resize_frameless_panes_on_pane_close() { tab.new_pane(PaneId::Terminal(2), None, None, None, None, false, Some(1)) .unwrap(); - tab.close_pane(PaneId::Terminal(2), true, None); + tab.close_pane(PaneId::Terminal(2), true); // 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/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index c80a796f..38140b04 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -2324,7 +2324,18 @@ pub fn send_cli_new_pane_action_with_command_and_cwd() { send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![pty_thread, screen_thread]); - assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); + + let new_pane_instruction = received_pty_instructions + .lock() + .unwrap() + .iter() + .find(|instruction| match instruction { + PtyInstruction::SpawnTerminalVertically(..) => true, + _ => false, + }) + .cloned(); + + assert_snapshot!(format!("{:?}", new_pane_instruction)); } #[test] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_move_pane_to_a_new_tab_left-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_move_pane_to_a_new_tab_left-4.snap index 593dd95b..112a5705 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_move_pane_to_a_new_tab_left-4.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_move_pane_to_a_new_tab_left-4.snap @@ -1,9 +1,9 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 3079 +assertion_line: 3636 expression: "format!(\"{}\", snapshot)" --- -00 (C): ┌ pane_to_stay ────────────────────────┐┌ pane_to_break_free ──────────────────┐ +00 (C): ┌ pane_to_break_free ──────────────────┐┌ pane_to_stay ────────────────────────┐ 01 (C): │ ││ │ 02 (C): │ ││ │ 03 (C): │ ││ │ diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_move_pane_to_a_new_tab_right-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_move_pane_to_a_new_tab_right-4.snap index e9f22eb3..8a3cfe42 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_move_pane_to_a_new_tab_right-4.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_move_pane_to_a_new_tab_right-4.snap @@ -1,9 +1,9 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 3032 +assertion_line: 3587 expression: "format!(\"{}\", snapshot)" --- -00 (C): ┌ pane_to_stay ────────────────────────┐┌ pane_to_break_free ──────────────────┐ +00 (C): ┌ pane_to_break_free ──────────────────┐┌ pane_to_stay ────────────────────────┐ 01 (C): │ ││ │ 02 (C): │ ││ │ 03 (C): │ ││ │ diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap index 0f9b59e1..57042301 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2306 -expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" +assertion_line: 2339 +expression: "format!(\"{:?}\", new_pane_instruction)" --- -[SpawnTerminalVertically(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None })), None, 10), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] +Some(SpawnTerminalVertically(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None })), None, 10)) diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-3.snap index b612c671..f2bcd76f 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-3.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-3.snap @@ -1,9 +1,9 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2131 +assertion_line: 2569 expression: "format!(\"{}\", snapshot)" --- -00 (C): ┌ Pane #2 ─────────────────────────────┐┌ Pane #1 ─────────────────────────────┐ +00 (C): ┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────┐ 01 (C): │ ││ │ 02 (C): │ ││ │ 03 (C): │ ││ │ diff --git a/zellij-utils/assets/layouts/classic.swap.kdl b/zellij-utils/assets/layouts/classic.swap.kdl index ae1091cb..85fcb398 100644 --- a/zellij-utils/assets/layouts/classic.swap.kdl +++ b/zellij-utils/assets/layouts/classic.swap.kdl @@ -78,7 +78,7 @@ swap_floating_layout name="enlarged" { pane { x "5%"; y 7; width "90%"; height "90%"; } pane { x "5%"; y 8; width "90%"; height "90%"; } pane { x "5%"; y 9; width "90%"; height "90%"; } - pane focus=true { x 10; y 10; width "90%"; height "90%"; } + pane { x 10; y 10; width "90%"; height "90%"; } } } @@ -91,13 +91,13 @@ swap_floating_layout name="spread" { pane { x "50%"; y "25%"; width "45%"; } } floating_panes max_panes=3 { - pane focus=true { y "55%"; width "45%"; height "45%"; } + pane { y "55%"; width "45%"; height "45%"; } pane { x "1%"; y "1%"; width "45%"; } pane { x "50%"; y "1%"; width "45%"; } } floating_panes max_panes=4 { pane { x "1%"; y "55%"; width "45%"; height "45%"; } - pane focus=true { x "50%"; y "55%"; width "45%"; height "45%"; } + pane { x "50%"; y "55%"; width "45%"; height "45%"; } pane { x "1%"; y "1%"; width "45%"; height "45%"; } pane { x "50%"; y "1%"; width "45%"; height "45%"; } } diff --git a/zellij-utils/assets/layouts/compact.swap.kdl b/zellij-utils/assets/layouts/compact.swap.kdl index 300b4bdf..6045e12b 100644 --- a/zellij-utils/assets/layouts/compact.swap.kdl +++ b/zellij-utils/assets/layouts/compact.swap.kdl @@ -71,7 +71,7 @@ swap_floating_layout name="enlarged" { pane { x "5%"; y 7; width "90%"; height "90%"; } pane { x "5%"; y 8; width "90%"; height "90%"; } pane { x "5%"; y 9; width "90%"; height "90%"; } - pane focus=true { x 10; y 10; width "90%"; height "90%"; } + pane { x 10; y 10; width "90%"; height "90%"; } } } @@ -84,13 +84,13 @@ swap_floating_layout name="spread" { pane { x "50%"; y "25%"; width "45%"; } } floating_panes max_panes=3 { - pane focus=true { y "55%"; width "45%"; height "45%"; } + pane { y "55%"; width "45%"; height "45%"; } pane { x "1%"; y "1%"; width "45%"; } pane { x "50%"; y "1%"; width "45%"; } } floating_panes max_panes=4 { pane { x "1%"; y "55%"; width "45%"; height "45%"; } - pane focus=true { x "50%"; y "55%"; width "45%"; height "45%"; } + pane { x "50%"; y "55%"; width "45%"; height "45%"; } pane { x "1%"; y "1%"; width "45%"; height "45%"; } pane { x "50%"; y "1%"; width "45%"; height "45%"; } } diff --git a/zellij-utils/assets/layouts/default.swap.kdl b/zellij-utils/assets/layouts/default.swap.kdl index 27475819..66aeaf7c 100644 --- a/zellij-utils/assets/layouts/default.swap.kdl +++ b/zellij-utils/assets/layouts/default.swap.kdl @@ -74,7 +74,7 @@ swap_floating_layout name="enlarged" { pane { x "5%"; y 7; width "90%"; height "90%"; } pane { x "5%"; y 8; width "90%"; height "90%"; } pane { x "5%"; y 9; width "90%"; height "90%"; } - pane focus=true { x 10; y 10; width "90%"; height "90%"; } + pane { x 10; y 10; width "90%"; height "90%"; } } } @@ -87,13 +87,13 @@ swap_floating_layout name="spread" { pane { x "50%"; y "25%"; width "45%"; } } floating_panes max_panes=3 { - pane focus=true { y "55%"; width "45%"; height "45%"; } + pane { y "55%"; width "45%"; height "45%"; } pane { x "1%"; y "1%"; width "45%"; } pane { x "50%"; y "1%"; width "45%"; } } floating_panes max_panes=4 { pane { x "1%"; y "55%"; width "45%"; height "45%"; } - pane focus=true { x "50%"; y "55%"; width "45%"; height "45%"; } + pane { x "50%"; y "55%"; width "45%"; height "45%"; } pane { x "1%"; y "1%"; width "45%"; height "45%"; } pane { x "50%"; y "1%"; width "45%"; height "45%"; } } diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index 33c8a7c1..b4110f73 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -743,6 +743,7 @@ pub struct FloatingPaneLayout { pub focus: Option, pub already_running: bool, pub pane_initial_contents: Option, + pub logical_position: Option, } impl FloatingPaneLayout { @@ -758,6 +759,7 @@ impl FloatingPaneLayout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, } } pub fn add_cwd_to_layout(&mut self, cwd: &PathBuf) { @@ -877,6 +879,7 @@ impl TiledPaneLayout { space: &PaneGeom, max_panes: Option, ignore_percent_split_sizes: bool, + focus_layout_if_not_focused: bool, ) -> Result, &'static str> { let layouts = match max_panes { Some(max_panes) => { @@ -889,7 +892,7 @@ impl TiledPaneLayout { // because we really should support that let children_count = (max_panes - pane_count_in_layout) + 1; let mut extra_children = vec![TiledPaneLayout::default(); children_count]; - if !layout_to_split.has_focused_node() { + if !layout_to_split.has_focused_node() && focus_layout_if_not_focused { if let Some(last_child) = extra_children.last_mut() { last_child.focus = Some(true); } @@ -898,7 +901,7 @@ impl TiledPaneLayout { } else { layout_to_split.truncate(max_panes); } - if !layout_to_split.has_focused_node() { + if !layout_to_split.has_focused_node() && focus_layout_if_not_focused { layout_to_split.focus_deepest_pane(); } @@ -1700,6 +1703,7 @@ fn split_space( rows: inherited_dimension, is_stacked: layout.children_are_stacked, is_pinned: false, + logical_position: None, }, SplitDirection::Horizontal => PaneGeom { x: space_to_split.x, @@ -1708,6 +1712,7 @@ fn split_space( rows: split_dimension, is_stacked: layout.children_are_stacked, is_pinned: false, + logical_position: None, }, }; split_geom.push(geom); @@ -1720,6 +1725,7 @@ fn split_space( layout.children_split_direction, ); let mut pane_positions = Vec::new(); + let mut pane_positions_with_children = Vec::new(); for (i, part) in layout.children.iter().enumerate() { let part_position_and_size = split_geom.get(i).unwrap(); if !part.children.is_empty() { @@ -1729,12 +1735,18 @@ fn split_space( total_space_to_split, ignore_percent_split_sizes, )?; - pane_positions.append(&mut part_positions); + // add the only first child to pane_positions only adding the others after all the + // childfree panes have been added so that the returned vec will be sorted breadth-first + if !part_positions.is_empty() { + pane_positions.push(part_positions.remove(0)); + } + pane_positions_with_children.append(&mut part_positions); } else { let part = part.clone(); pane_positions.push((part, *part_position_and_size)); } } + pane_positions.append(&mut pane_positions_with_children); if pane_positions.is_empty() { let layout = layout.clone(); pane_positions.push((layout, space_to_split.clone())); diff --git a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap index 69d57c30..95f60225 100644 --- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap @@ -52,6 +52,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], ), @@ -102,6 +103,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -114,6 +116,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], ), diff --git a/zellij-utils/src/pane_size.rs b/zellij-utils/src/pane_size.rs index aa258fd9..ba2ac8ed 100644 --- a/zellij-utils/src/pane_size.rs +++ b/zellij-utils/src/pane_size.rs @@ -17,13 +17,13 @@ pub struct PaneGeom { pub rows: Dimension, pub cols: Dimension, pub is_stacked: bool, - pub is_pinned: bool, // only relevant to floating panes + pub is_pinned: bool, // only relevant to floating panes + pub logical_position: Option, // relevant when placing this pane in a layout } impl PartialEq for PaneGeom { fn eq(&self, other: &Self) -> bool { // compare all except is_pinned - // TODO: add is_stacked? self.x == other.x && self.y == other.y && self.rows == other.rows diff --git a/zellij-utils/src/session_serialization.rs b/zellij-utils/src/session_serialization.rs index 3cb7c5eb..ae252952 100644 --- a/zellij-utils/src/session_serialization.rs +++ b/zellij-utils/src/session_serialization.rs @@ -787,6 +787,7 @@ fn get_floating_panes_layout_from_panegeoms( focus: Some(m.is_focused), already_running: false, pane_initial_contents: m.pane_contents.clone(), + logical_position: None, } }) .collect() @@ -1285,6 +1286,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1297,6 +1299,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1313,6 +1316,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1328,6 +1332,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1348,6 +1353,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1362,6 +1368,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1378,6 +1385,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1390,6 +1398,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1404,6 +1413,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1434,6 +1444,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1446,6 +1457,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1462,6 +1474,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1477,6 +1490,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1497,6 +1511,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1511,6 +1526,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1527,6 +1543,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1541,6 +1558,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1555,6 +1573,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1583,6 +1602,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: true, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1594,6 +1614,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: true, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1605,6 +1626,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: true, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1629,6 +1651,7 @@ mod tests { cols: Dimension::percent(100.0), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }], @@ -1644,6 +1667,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1655,6 +1679,7 @@ mod tests { cols: Dimension::fixed(10), is_stacked: false, is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1787,6 +1812,7 @@ mod tests { cols: get_dim(&data["cols"]), is_stacked: data["is_stacked"].to_string().parse().unwrap(), is_pinned: false, + logical_position: None, } } diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap index 4c124f27..cd0558c5 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap @@ -1681,6 +1681,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1709,6 +1710,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1737,6 +1739,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1765,6 +1768,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1793,6 +1797,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1821,6 +1826,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1849,6 +1855,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1877,6 +1884,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1905,6 +1913,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1930,11 +1939,10 @@ Layout { ), pinned: None, run: None, - focus: Some( - true, - ), + focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], }, @@ -1966,6 +1974,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], MaxPanes( @@ -1994,6 +2003,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2018,6 +2028,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], MaxPanes( @@ -2043,11 +2054,10 @@ Layout { ), pinned: None, run: None, - focus: Some( - true, - ), + focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2072,6 +2082,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2096,6 +2107,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], MaxPanes( @@ -2128,6 +2140,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2153,11 +2166,10 @@ Layout { ), pinned: None, run: None, - focus: Some( - true, - ), + focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2186,6 +2198,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2214,6 +2227,7 @@ Layout { focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], },