diff --git a/CHANGELOG.md b/CHANGELOG.md index 64c1b69185..473e090537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [Unreleased] +* fix(plugins): properly focus pane after tab was closed in the plugin API (https://github.com/zellij-org/zellij/pull/3797) +* fix(plugins): properly pad UI components background to their declared width (https://github.com/zellij-org/zellij/pull/3806) +* feat(plugins): allow plugins to change their own `/host` folder under a new FullHdAccess permission (https://github.com/zellij-org/zellij/pull/3827) +* fix(plugins): do not detach if using `/` in session name (https://github.com/zellij-org/zellij/pull/3839) +* fix(plugins): properly focus plugin pane after it was hidden (https://github.com/zellij-org/zellij/pull/3841) +* fix(layouts): off by 1 when focusing a specific tab through a layout (https://github.com/zellij-org/zellij/pull/3844) +* fix(multiplayer): properly clear fake cursors (https://github.com/zellij-org/zellij/pull/3845) +* feat(ux): pin floating panes (https://github.com/zellij-org/zellij/pull/3876) +* fix(layout-applier): logical index pane sorting (https://github.com/zellij-org/zellij/pull/3893) +* fix(terminal): synchronized rendering detection query response (https://github.com/zellij-org/zellij/pull/3884) +* fix(terminal): cursor overflow issue (https://github.com/zellij-org/zellij/pull/3894) +* feat(ux): stack panes command (https://github.com/zellij-org/zellij/pull/3905) ## [0.41.2] - 2024-11-19 * fix(input): keypresses not being identified properly with kitty keyboard protocol in some terminals (https://github.com/zellij-org/zellij/pull/3725) diff --git a/default-plugins/configuration/src/presets.rs b/default-plugins/configuration/src/presets.rs index b703ef99db..eb9a55bbb5 100644 --- a/default-plugins/configuration/src/presets.rs +++ b/default-plugins/configuration/src/presets.rs @@ -37,6 +37,7 @@ keybinds clear-defaults=true {{ bind "w" {{ ToggleFloatingPanes; SwitchToMode "Locked"; }} bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Locked"; }} bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + bind "i" {{ TogglePanePinned; SwitchToMode "Locked"; }} }} move {{ bind "m" {{ SwitchToMode "Normal"; }} @@ -233,6 +234,7 @@ keybinds clear-defaults=true {{ bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + bind "i" {{ TogglePanePinned; SwitchToMode "Normal"; }} }} move {{ bind "{primary_modifier} h" {{ SwitchToMode "Normal"; }} @@ -440,6 +442,7 @@ keybinds clear-defaults=true {{ bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + bind "i" {{ TogglePanePinned; SwitchToMode "Normal"; }} }} move {{ bind "n" "Tab" {{ MovePane; }} @@ -618,6 +621,7 @@ keybinds clear-defaults=true {{ bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + bind "i" {{ TogglePanePinned; SwitchToMode "Normal"; }} }} move {{ bind "{primary_modifier} h" {{ SwitchToMode "Normal"; }} @@ -805,6 +809,7 @@ keybinds clear-defaults=true {{ bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + bind "i" {{ TogglePanePinned; SwitchToMode "Normal"; }} }} move {{ bind "n" "Tab" {{ MovePane; }} @@ -967,6 +972,7 @@ keybinds clear-defaults=true {{ bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + bind "i" {{ TogglePanePinned; SwitchToMode "Normal"; }} }} move {{ bind "{primary_modifier} m" {{ SwitchToMode "Normal"; }} diff --git a/default-plugins/configuration/src/presets_screen.rs b/default-plugins/configuration/src/presets_screen.rs index 9a29b790be..d783c00faf 100644 --- a/default-plugins/configuration/src/presets_screen.rs +++ b/default-plugins/configuration/src/presets_screen.rs @@ -533,13 +533,7 @@ impl PresetsScreen { } else { (rows.saturating_sub(ui_size) / 2) + 2 }; - print_nested_list_with_coordinates( - list_items, - left_padding, - top_coordinates, - Some(max_width), - None, - ); + print_nested_list_with_coordinates(list_items, left_padding, top_coordinates, None, None); } fn render_second_bulletin( &self, @@ -672,13 +666,7 @@ impl PresetsScreen { } else { (rows.saturating_sub(ui_size) / 2) + 6 }; - print_nested_list_with_coordinates( - list_items, - left_padding, - top_coordinates, - Some(max_width), - None, - ); + print_nested_list_with_coordinates(list_items, left_padding, top_coordinates, None, None); } fn render_leader_keys_indication( &self, diff --git a/default-plugins/configuration/src/rebind_leaders_screen.rs b/default-plugins/configuration/src/rebind_leaders_screen.rs index f87f3cfa98..4e17722836 100644 --- a/default-plugins/configuration/src/rebind_leaders_screen.rs +++ b/default-plugins/configuration/src/rebind_leaders_screen.rs @@ -304,6 +304,7 @@ impl RebindLeadersScreen { } else { (format!("{}", primary_modifier_key_text), 0) }; + let primary_modifier_menu_width = primary_modifier_text.chars().count(); print_text_with_coordinates( Text::new(primary_modifier_text).color_range(3, primary_modifier_start_position..), base_x, @@ -330,7 +331,7 @@ impl RebindLeadersScreen { .collect(), base_x, base_y + 6, - Some(screen_width / 2), + Some(primary_modifier_menu_width), None, ); } @@ -504,6 +505,7 @@ impl RebindLeadersScreen { (format!("{}", secondary_modifier_key_text), 0) }; let secondary_modifier_menu_x_coords = base_x + (screen_width / 2); + let secondary_modifier_menu_width = secondary_modifier_text.chars().count(); print_text_with_coordinates( Text::new(secondary_modifier_text).color_range(0, secondary_modifier_start_position..), secondary_modifier_menu_x_coords, @@ -530,7 +532,7 @@ impl RebindLeadersScreen { .collect(), secondary_modifier_menu_x_coords, base_y + 6, - Some(screen_width / 2), + Some(secondary_modifier_menu_width), None, ); } diff --git a/default-plugins/session-manager/src/main.rs b/default-plugins/session-manager/src/main.rs index 3d4848af6d..8dd6da87f6 100644 --- a/default-plugins/session-manager/src/main.rs +++ b/default-plugins/session-manager/src/main.rs @@ -462,6 +462,9 @@ impl State { // through the package) self.show_error("Session name must be shorter than 108 bytes"); return; + } else if self.new_session_info.name().contains('/') { + self.show_error("Session name cannot contain '/'"); + return; } self.new_session_info.handle_selection(&self.session_name); }, @@ -483,6 +486,10 @@ impl State { self.show_error("A resurrectable session by this name already exists."); return; // s that we don't hide self } else { + if renaming_session_name.contains('/') { + self.show_error("Session names cannot contain '/'"); + return; + } self.update_current_session_name_in_ui(&renaming_session_name); rename_session(&renaming_session_name); return; // s that we don't hide self diff --git a/default-plugins/session-manager/src/ui/components.rs b/default-plugins/session-manager/src/ui/components.rs index 29eba512cc..03c4d3283c 100644 --- a/default-plugins/session-manager/src/ui/components.rs +++ b/default-plugins/session-manager/src/ui/components.rs @@ -891,6 +891,16 @@ pub fn render_renaming_session_screen( 33 + new_session_name.width()..40 + new_session_name.width(), ); print_text_with_coordinates(text, x, y, None, None); + if new_session_name.contains('/') { + let error_text = "Error: session name cannot contain '/'"; + print_text_with_coordinates( + Text::new(error_text).color_range(3, ..), + x, + y + 2, + None, + None, + ); + } } pub fn render_controls_line( diff --git a/example/default.kdl b/example/default.kdl index e7dfcf5da9..15f1fd54a5 100644 --- a/example/default.kdl +++ b/example/default.kdl @@ -36,6 +36,7 @@ keybinds { bind "w" { ToggleFloatingPanes; SwitchToMode "Normal"; } bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "Normal"; } bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0;} + bind "i" { TogglePanePinned; SwitchToMode "Normal"; } } move { bind "Ctrl h" { SwitchToMode "Normal"; } diff --git a/funding.json b/funding.json new file mode 100644 index 0000000000..9a6a2a09cd --- /dev/null +++ b/funding.json @@ -0,0 +1,50 @@ +{ + "version": "v1.0.0", + "entity": { + "type": "individual", + "role": "owner", + "name": "Aram Drevekenin", + "email": "aram@poor.dev", + "description": "An indie developer rethinking our terminal experience", + "webpageUrl": { + "url": "https://zellij.dev", + "wellKnown": "https://zellij.dev/.well-known/funding-manifest-urls" + } + }, + "projects": [{ + "guid": "zellij", + "name": "Zellij", + "description": "A terminal workspace with batteries included", + "webpageUrl": { + "url": "https://zellij.dev", + "wellKnown": "https://zellij.dev/.well-known/funding-manifest-urls" + }, + "repositoryUrl": { + "url": "https://github.com/zellij-org/zellij" + }, + "licenses": ["spdx:MIT"], + "tags": ["terminal", "linux", "macos", "developer-tools"] + }], + "funding": { + "channels": [ + { + "guid": "github-sponsors", + "type": "other", + "address": "https://github.com/sponsors/imsnif", + "description": "My Github Sponsors page." + } + ], + "plans": [ + { + "guid": "sponsorship-plan", + "status": "active", + "name": "Sponsorship Plan", + "description": "Sponsor as you wish and are able (preferably in a recurring manner) to help me pay my bills!", + "amount": 0, + "currency": "USD", + "frequency": "other", + "channels": ["github-sponsors"] + } + ] + } +} diff --git a/src/main.rs b/src/main.rs index 1be0555336..b3a5ce965a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,6 +37,7 @@ fn main() { y, width, height, + pinned, })) = opts.command { let cwd = cwd.or_else(|| std::env::current_dir().ok()); @@ -57,6 +58,7 @@ fn main() { y, width, height, + pinned, }; commands::send_action_to_session(command_cli_action, opts.session, config); std::process::exit(0); @@ -71,6 +73,7 @@ fn main() { y, width, height, + pinned, })) = opts.command { let cwd = None; @@ -90,6 +93,7 @@ fn main() { y, width, height, + pinned, }; commands::send_action_to_session(command_cli_action, opts.session, config); std::process::exit(0); @@ -105,6 +109,7 @@ fn main() { y, width, height, + pinned, })) = opts.command { let mut file = file; @@ -125,6 +130,7 @@ fn main() { y, width, height, + pinned, }; commands::send_action_to_session(command_cli_action, opts.session, config); std::process::exit(0); diff --git a/src/tests/e2e/cases.rs b/src/tests/e2e/cases.rs index bb652ef970..e8e30dd766 100644 --- a/src/tests/e2e/cases.rs +++ b/src/tests/e2e/cases.rs @@ -2423,3 +2423,100 @@ pub fn load_plugins_in_background_on_startup() { ); assert_snapshot!(last_snapshot); } + +#[test] +#[ignore] +pub fn pin_floating_panes() { + let fake_win_size = Size { + cols: 120, + rows: 24, + }; + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Toggle floating panes", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); + remote_terminal.send_key(&TOGGLE_FLOATING_PANES); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Pin floating pane", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.snapshot_contains("PIN [ ]") { + remote_terminal.send_key(&sgr_mouse_report(Position::new(8, 87), 0)); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Focus underlying pane", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.snapshot_contains("PIN [+]") { + remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); + remote_terminal.send_key(&TOGGLE_FLOATING_PANES); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Fill tiled pane with text", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(3, 2) { + remote_terminal.load_fixture("e2e/fill_for_pinned_pane"); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Move cursor behind pinned pane", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.snapshot_contains("line") { + remote_terminal + .send_key(&format!(" hide_me").as_bytes().to_vec()); + step_is_complete = true; + } + step_is_complete + }, + }); + + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { + name: "Wait for cursor to be behind pinned pane", + instruction: |remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.snapshot_contains("hide") { + // terminal has been filled with fixture text + step_is_complete = true; + } + step_is_complete + }, + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; + let last_snapshot = account_for_races_in_snapshot(last_snapshot); + assert_snapshot!(last_snapshot); +} diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs index 6b702f018b..9882781fcd 100644 --- a/src/tests/e2e/remote_runner.rs +++ b/src/tests/e2e/remote_runner.rs @@ -456,6 +456,8 @@ impl RemoteRunner { rows, cols, is_stacked: false, + is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); start_zellij(&mut channel); @@ -492,6 +494,8 @@ impl RemoteRunner { rows, cols, is_stacked: false, + is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); start_zellij_mirrored_session(&mut channel); @@ -528,6 +532,8 @@ impl RemoteRunner { rows, 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); @@ -567,6 +573,8 @@ impl RemoteRunner { rows, 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( @@ -613,6 +621,8 @@ impl RemoteRunner { rows, 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); @@ -649,6 +659,8 @@ impl RemoteRunner { rows, 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); @@ -685,6 +697,8 @@ impl RemoteRunner { rows, cols, is_stacked: false, + is_pinned: false, + logical_position: None, }; setup_remote_environment(&mut channel, win_size); start_zellij_without_frames(&mut channel); @@ -722,6 +736,8 @@ impl RemoteRunner { rows, 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/src/tests/e2e/snapshots/zellij__tests__e2e__cases__pin_floating_panes.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__pin_floating_panes.snap new file mode 100644 index 0000000000..91233bb121 --- /dev/null +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__pin_floating_panes.snap @@ -0,0 +1,29 @@ +--- +source: src/tests/e2e/cases.rs +assertion_line: 2524 +expression: last_snapshot +--- + Zellij (e2e-test)  Tab #1  +┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│$ cat /usr/src/zellij/fixtures/e2e/fill_for_pinned_pane │ +│line1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa │ +│line2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa │ +│line3aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa │ +│line4aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa │ +│line5aaaaaaaaaaaaaaaaaaaaaaaa┌ Pane #2 ──────────────────────────────────────── PIN [+] ┐aaaaaaaaaaaaaaaaaaaaaaaaaaaa │ +│line6aaaaaaaaaaaaaaaaaaaaaaaa│$ │aaaaaaaaaaaaaaaaaaaaaaaaaaaa │ +│line7aaaaaaaaaaaaaaaaaaaaaaaa│ │aaaaaaaaaaaaaaaaaaaaaaaaaaaa │ +│line8aaaaaaaaaaaaaaaaaaaaaaaa│ │aaaaaaaaaaaaaaaaaaaaaaaaaaaa │ +│line9aaaaaaaaaaaaaaaaaaaaaaaa│ │aaaaaaaaaaaaaaaaaaaaaaaaaaaa │ +│line10aaaaaaaaaaaaaaaaaaaaaaa│ │aaaaaaaaaaaaaaaaaaaaaaaaaaaaa│ +│line11aaaaaaaaaaaaaaaaaaaaaaa│ │aaaaaaaaaaaaaaaaaaaaaaaaaaaaa│ +│line12aaaaaaaaaaaaaaaaaaaaaaa│ │aaaaaaaaaaaaaaaaaaaaaaaaaaaaa│ +│line13aaaaaaaaaaaaaaaaaaaaaaa│ │aaaaaaaaaaaaaaaaaaaaaaaaaaaaa│ +│$ hide_m│ │ │ +│ └──────────────────────────────────────────────────────────┘ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__quit_and_resurrect_session.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__quit_and_resurrect_session.snap index 857f417d52..2cc662bb86 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__quit_and_resurrect_session.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__quit_and_resurrect_session.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1191 +assertion_line: 1212 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  Tab #2  Tab #3  Tab #4  @@ -9,11 +9,11 @@ expression: last_snapshot │ ││ │ │ ││ │ │ ││ │ -│ ┌ Pane #4 ───────────────────────────────────────────────┐ │ +│ ┌ Pane #4 ────────────────────────────────────── PIN [ ] ┐ │ │ │$ │ │ -│ │ ┌ top ───────────────────────────────────────────────────┐ │ +│ │ ┌ top ────────────────────────────────────────── PIN [ ] ┐ │ │ │ │ │ │ -│ │ │ │─┐ │ +│ │ │ │ ┐ │ │ │ │ │ │────────────────────────────┘ │ │ │ Waiting to run: top │ │────────────────────────────┐ │ │ │ │ │ │ diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__quit_and_resurrect_session_with_viewport_serialization.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__quit_and_resurrect_session_with_viewport_serialization.snap index dff8858bd2..0897618dce 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__quit_and_resurrect_session_with_viewport_serialization.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__quit_and_resurrect_session_with_viewport_serialization.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 1252 +assertion_line: 1273 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  Tab #2  Tab #3  Tab #4  @@ -9,11 +9,11 @@ expression: last_snapshot │$ ││$ │ │$ ││$ │ │ ││ │ -│ ┌ Pane #4 ───────────────────────────────────────────────┐ │ +│ ┌ Pane #4 ────────────────────────────────────── PIN [ ] ┐ │ │ │ │ │ -│ │$┌ top ───────────────────────────────────────────────────┐ │ +│ │$┌ top ────────────────────────────────────────── PIN [ ] ┐ │ │ │$│ │ │ -│ │ │ │─┐ │ +│ │ │ │ ┐ │ │ │ │ │ │────────────────────────────┘ │ │ │ Waiting to run: top │ │────────────────────────────┐ │ │ │ │ │ │ diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap index d5231a04b6..81bf57710c 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 2027 +assertion_line: 2049 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  Alt <[]>  STAGGERED  @@ -10,7 +10,7 @@ expression: last_snapshot │ │ │ │ │ │ -│ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +│ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ │ │$ █ │ │ │ │ │ │ │ │ │ │ diff --git a/src/tests/fixtures/e2e/fill_for_pinned_pane b/src/tests/fixtures/e2e/fill_for_pinned_pane new file mode 100644 index 0000000000..41b373c232 --- /dev/null +++ b/src/tests/fixtures/e2e/fill_for_pinned_pane @@ -0,0 +1,13 @@ +line1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line3aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line4aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line5aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line6aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line10aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line11aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line12aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +line13aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/zellij-server/src/output/mod.rs b/zellij-server/src/output/mod.rs index ccb5f66530..32192a203a 100644 --- a/zellij-server/src/output/mod.rs +++ b/zellij-server/src/output/mod.rs @@ -449,6 +449,12 @@ impl Output { self.client_character_chunks.values().any(|c| !c.is_empty()) || self.sixel_chunks.values().any(|c| !c.is_empty()) } + pub fn cursor_is_visible(&self, cursor_x: usize, cursor_y: usize) -> bool { + self.floating_panes_stack + .as_ref() + .map(|s| s.cursor_is_visible(cursor_x, cursor_y)) + .unwrap_or(true) + } } // this struct represents the geometry of a group of floating panes @@ -740,6 +746,24 @@ impl FloatingPanesStack { } uncovered_chunks } + pub fn cursor_is_visible(&self, cursor_x: usize, cursor_y: usize) -> bool { + let z_index = 0; // TODO: receive z_index + let panes_to_check = self.layers.iter().skip(z_index); + for pane_geom in panes_to_check { + let pane_top_edge = pane_geom.y; + let pane_left_edge = pane_geom.x; + let pane_bottom_edge = pane_geom.y + pane_geom.rows.as_usize().saturating_sub(1); + let pane_right_edge = pane_geom.x + pane_geom.cols.as_usize().saturating_sub(1); + if pane_top_edge <= cursor_y + && pane_bottom_edge >= cursor_y + && pane_left_edge <= cursor_x + && pane_right_edge >= cursor_x + { + return false; + } + } + true + } } #[derive(Debug, Clone, Default)] 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 75da894e27..127b9b3763 100644 --- a/zellij-server/src/panes/floating_panes/floating_pane_grid.rs +++ b/zellij-server/src/panes/floating_panes/floating_pane_grid.rs @@ -861,6 +861,8 @@ pub fn half_size_middle_geom(space: &Viewport, offset: usize) -> PaneGeom { cols: Dimension::fixed(space.cols / 2), 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); @@ -874,6 +876,8 @@ fn half_size_top_left_geom(space: &Viewport, offset: usize) -> PaneGeom { cols: Dimension::fixed(space.cols / 3), 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); @@ -887,6 +891,8 @@ fn half_size_top_right_geom(space: &Viewport, offset: usize) -> PaneGeom { cols: Dimension::fixed(space.cols / 3), 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); @@ -900,6 +906,8 @@ fn half_size_bottom_left_geom(space: &Viewport, offset: usize) -> PaneGeom { cols: Dimension::fixed(space.cols / 3), 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); @@ -913,6 +921,8 @@ fn half_size_bottom_right_geom(space: &Viewport, offset: usize) -> PaneGeom { cols: Dimension::fixed(space.cols / 3), 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 e896364bd7..27eda0964d 100644 --- a/zellij-server/src/panes/floating_panes/mod.rs +++ b/zellij-server/src/panes/floating_panes/mod.rs @@ -94,10 +94,27 @@ impl FloatingPanes { .map(|pane_id| self.panes.get(pane_id).unwrap().position_and_size()) .collect(); Some(FloatingPanesStack { layers }) + } else if self.has_pinned_panes() { + let layers = self + .z_indices + .iter() + .filter_map(|pane_id| { + self.panes + .get(pane_id) + .map(|p| p.position_and_size()) + .and_then(|p| if p.is_pinned { Some(p) } else { None }) + }) + .collect(); + Some(FloatingPanesStack { layers }) } else { None } } + pub fn has_pinned_panes(&self) -> bool { + self.panes + .iter() + .any(|(_, p)| p.position_and_size().is_pinned) + } pub fn pane_ids(&self) -> impl Iterator { self.panes.keys() } @@ -262,6 +279,12 @@ impl FloatingPanes { if let Some(height) = &floating_pane_layout.height { position.rows = Dimension::fixed(height.to_position(viewport.rows)); } + 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); } @@ -317,7 +340,21 @@ impl FloatingPanes { let err_context = || "failed to render output"; let connected_clients: Vec = { self.connected_clients.borrow().iter().copied().collect() }; - let mut floating_panes: Vec<_> = self.panes.iter_mut().collect(); + let active_panes = if self.panes_are_visible() { + self.active_panes.clone_active_panes() + } else { + Default::default() + }; + let mut floating_panes: Vec<_> = if self.panes_are_visible() { + self.panes.iter_mut().collect() + } else if self.has_pinned_panes() { + self.panes + .iter_mut() + .filter(|(_, p)| p.position_and_size().is_pinned) + .collect() + } else { + vec![] + }; floating_panes.sort_by(|(a_id, _a_pane), (b_id, _b_pane)| { self.z_indices .iter() @@ -335,7 +372,7 @@ impl FloatingPanes { }); for (z_index, (kind, pane)) in floating_panes.iter_mut().enumerate() { - let mut active_panes = self.active_panes.clone_active_panes(); + let mut active_panes = active_panes.clone(); let multiple_users_exist_in_session = { self.connected_clients_in_app.borrow().len() > 1 }; active_panes.retain(|c_id, _| self.connected_clients.borrow().contains(c_id)); @@ -357,8 +394,14 @@ impl FloatingPanes { .get(client_id) .unwrap_or(&self.default_mode_info) .mode; + let is_floating = true; pane_contents_and_ui - .render_pane_frame(*client_id, client_mode, self.session_is_mirrored) + .render_pane_frame( + *client_id, + client_mode, + self.session_is_mirrored, + is_floating, + ) .with_context(err_context)?; if let PaneId::Plugin(..) = kind { pane_contents_and_ui @@ -767,6 +810,52 @@ impl FloatingPanes { .find(|(_, p)| p.contains(point)) .map(|(&id, _)| id)) } + pub fn get_pinned_pane_id_at( + &self, + point: &Position, + search_selectable: bool, + ) -> Result> { + let _err_context = || format!("failed to determine floating pane at point {point:?}"); + + let mut panes: Vec<_> = if search_selectable { + self.panes + .iter() + .filter(|(_, p)| p.selectable()) + .filter(|(_, p)| p.current_geom().is_pinned) + .collect() + } else { + self.panes + .iter() + .filter(|(_, p)| p.current_geom().is_pinned) + .collect() + }; + panes.sort_by(|(a_id, _a_pane), (b_id, _b_pane)| { + // TODO: continue + Ord::cmp( + &self.z_indices.iter().position(|id| id == *b_id).unwrap(), + &self.z_indices.iter().position(|id| id == *a_id).unwrap(), + ) + }); + Ok(panes + .iter() + .find(|(_, p)| p.contains(point)) + .map(|(&id, _)| id)) + } + pub fn has_pinned_pane_at(&self, point: &Position) -> bool { + let mut panes: Vec<_> = self + .panes + .iter() + .filter(|(_, p)| p.current_geom().is_pinned) + .collect(); + + panes.sort_by(|(a_id, _a_pane), (b_id, _b_pane)| { + Ord::cmp( + &self.z_indices.iter().position(|id| id == *b_id).unwrap(), + &self.z_indices.iter().position(|id| id == *a_id).unwrap(), + ) + }); + panes.iter().find(|(_, p)| p.contains(point)).is_some() + } pub fn get_pane_at_mut( &mut self, position: &Position, diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs index 0cc7ba2cec..62d2e53373 100644 --- a/zellij-server/src/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -1144,7 +1144,7 @@ impl Grid { ))); } pub fn cursor_coordinates(&self) -> Option<(usize, usize)> { - if self.cursor_is_hidden { + if self.cursor_is_hidden || self.cursor.x >= self.width || self.cursor.y >= self.height { None } else { Some((self.cursor.x, self.cursor.y)) @@ -2745,7 +2745,7 @@ impl Perform for Grid { for param in params_iter.map(|param| param[0]) { match param { 2026 => { - let response = "\u{1b}[2026;2$y"; + let response = "\u{1b}[?2026;2$y"; self.pending_messages_to_pty .push(response.as_bytes().to_vec()); }, diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs index 7e16ee2d24..c879cfefc7 100644 --- a/zellij-server/src/panes/plugin_pane.rs +++ b/zellij-server/src/panes/plugin_pane.rs @@ -202,7 +202,9 @@ impl Pane for PluginPane { self.set_should_render(true); } fn set_geom(&mut self, position_and_size: PaneGeom) { + let is_pinned = self.geom.is_pinned; self.geom = position_and_size; + self.geom.is_pinned = is_pinned; self.resize_grids(); self.set_should_render(true); } @@ -394,12 +396,14 @@ impl Pane for PluginPane { .cols .set_inner(frame_geom.cols.as_usize().saturating_sub(1)); } + let is_pinned = frame_geom.is_pinned; let mut frame = PaneFrame::new( frame_geom.into(), grid.scrollback_position_and_length(), pane_title, frame_params, - ); + ) + .is_pinned(is_pinned); if let Some((frame_color_override, _text)) = self.pane_frame_color_override.as_ref() { frame.override_color(*frame_color_override); } @@ -700,6 +704,27 @@ impl Pane for PluginPane { fn query_should_be_suppressed(&self) -> bool { self.should_be_suppressed } + fn toggle_pinned(&mut self) { + self.geom.is_pinned = !self.geom.is_pinned; + } + fn set_pinned(&mut self, should_be_pinned: bool) { + self.geom.is_pinned = should_be_pinned; + } + fn intercept_left_mouse_click(&mut self, position: &Position, client_id: ClientId) -> bool { + if self.position_is_on_frame(position) { + let relative_position = self.relative_position(position); + if let Some(client_frame) = self.frame.get_mut(&client_id) { + if client_frame.clicked_on_pinned(relative_position) { + self.toggle_pinned(); + return true; + } + } + } + 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 c7e96eb602..2e825ac84c 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -177,7 +177,9 @@ impl Pane for TerminalPane { self.reflow_lines(); } fn set_geom(&mut self, position_and_size: PaneGeom) { + let is_pinned = self.geom.is_pinned; self.geom = position_and_size; + self.geom.is_pinned = is_pinned; self.reflow_lines(); self.render_full_viewport(); } @@ -376,12 +378,14 @@ impl Pane for TerminalPane { }; let frame_geom = self.current_geom(); + let is_pinned = frame_geom.is_pinned; let mut frame = PaneFrame::new( frame_geom.into(), self.grid.scrollback_position_and_length(), pane_title, frame_params, - ); + ) + .is_pinned(is_pinned); if let Some((exit_status, is_first_run, _run_command)) = &self.is_held { if *is_first_run { frame.indicate_first_run(); @@ -806,6 +810,41 @@ impl Pane for TerminalPane { self.style.rounded_corners = rounded_corners; self.frame.clear(); } + fn drain_fake_cursors(&mut self) -> Option> { + if !self.fake_cursor_locations.is_empty() { + for (y, _x) in &self.fake_cursor_locations { + // we do this because once these fake_cursor_locations + // have been drained, we have to make sure to render the line + // they appeared on so that whatever clears their location + // won't leave a hole + self.grid.update_line_for_rendering(*y); + } + Some(self.fake_cursor_locations.drain().collect()) + } else { + None + } + } + fn toggle_pinned(&mut self) { + self.geom.is_pinned = !self.geom.is_pinned; + } + fn set_pinned(&mut self, should_be_pinned: bool) { + self.geom.is_pinned = should_be_pinned; + } + fn intercept_left_mouse_click(&mut self, position: &Position, client_id: ClientId) -> bool { + if self.position_is_on_frame(position) { + let relative_position = self.relative_position(position); + if let Some(client_frame) = self.frame.get_mut(&client_id) { + if client_frame.clicked_on_pinned(relative_position) { + self.toggle_pinned(); + return true; + } + } + } + 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 7fcd7a4060..088d1b4f86 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); @@ -699,15 +720,26 @@ impl TiledPanes { .render_pane_contents_for_client(*client_id) .with_context(err_context)?; } + let is_floating = false; if self.draw_pane_frames { pane_contents_and_ui - .render_pane_frame(*client_id, client_mode, self.session_is_mirrored) + .render_pane_frame( + *client_id, + client_mode, + self.session_is_mirrored, + is_floating, + ) .with_context(err_context)?; } else if pane_is_stacked { // if we have no pane frames but the pane is stacked, we need to render its // frame which will amount to only rendering the title line pane_contents_and_ui - .render_pane_frame(*client_id, client_mode, self.session_is_mirrored) + .render_pane_frame( + *client_id, + client_mode, + self.session_is_mirrored, + is_floating, + ) .with_context(err_context)?; // we also need to render its boundaries as normal let boundaries = client_id_to_boundaries @@ -786,6 +818,16 @@ impl TiledPanes { }, } } + pub fn set_geom_for_pane_with_id(&mut self, pane_id: &PaneId, geom: PaneGeom) { + match self.panes.get_mut(pane_id) { + Some(pane) => { + pane.set_geom(geom); + }, + None => { + log::error!("Failed to find pane with id: {:?}", pane_id); + }, + } + } pub fn resize(&mut self, new_screen_size: Size) { // this is blocked out to appease the borrow checker { @@ -1795,6 +1837,9 @@ impl TiledPanes { } pane_infos } + pub fn pane_id_is_focused(&self, pane_id: &PaneId) -> bool { + self.active_panes.pane_id_is_focused(pane_id) + } pub fn update_pane_themes(&mut self, theme: Palette) { self.style.colors = theme; for pane in self.panes.values_mut() { @@ -1812,6 +1857,14 @@ impl TiledPanes { pane.update_rounded_corners(rounded_corners); } } + pub fn stack_panes( + &mut self, + root_pane_id: PaneId, + pane_count_in_stack: usize, + ) -> Vec { + StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide) + .new_stack(root_pane_id, pane_count_in_stack) + } } #[allow(clippy::borrowed_box)] diff --git a/zellij-server/src/panes/tiled_panes/stacked_panes.rs b/zellij-server/src/panes/tiled_panes/stacked_panes.rs index bc5057a5b6..400045b99c 100644 --- a/zellij-server/src/panes/tiled_panes/stacked_panes.rs +++ b/zellij-server/src/panes/tiled_panes/stacked_panes.rs @@ -310,7 +310,6 @@ impl<'a> StackedPanes<'a> { adjust_stack_geoms(new_flexible_pane_geom)?; } else { if new_rows < all_stacked_pane_positions.len() { - // TODO: test this!! we don't want crashes... return Err(anyhow!("Not enough room for stacked panes")); } let rows_deficit = current_rows - new_rows; @@ -465,6 +464,35 @@ impl<'a> StackedPanes<'a> { } Err(anyhow!("Not enough room for another pane!")) } + pub fn new_stack(&mut self, root_pane_id: PaneId, pane_count_in_stack: usize) -> Vec { + let mut stacked_geoms = vec![]; + let panes = self.panes.borrow(); + let running_stack_geom = panes.get(&root_pane_id).map(|p| p.position_and_size()); + let Some(mut running_stack_geom) = running_stack_geom else { + log::error!("Pane not found"); // TODO: better error + return stacked_geoms; + }; + running_stack_geom.is_stacked = true; + let mut pane_index_in_stack = 0; + loop { + if pane_index_in_stack == pane_count_in_stack { + break; + } + let is_last_pane_in_stack = + pane_index_in_stack == pane_count_in_stack.saturating_sub(1); + let mut geom_for_pane = running_stack_geom.clone(); + if !is_last_pane_in_stack { + geom_for_pane.rows = Dimension::fixed(1); + running_stack_geom.y += 1; + running_stack_geom + .rows + .set_inner(running_stack_geom.rows.as_usize().saturating_sub(1)); + } + stacked_geoms.push(geom_for_pane); + pane_index_in_stack += 1; + } + stacked_geoms + } fn get_all_stacks(&self) -> Result>> { let err_context = || "Failed to get positions in stack"; let panes = self.panes.borrow(); 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 a288a9539f..de37fad30c 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/plugins/mod.rs b/zellij-server/src/plugins/mod.rs index de6ae028b2..fa1fabcec2 100644 --- a/zellij-server/src/plugins/mod.rs +++ b/zellij-server/src/plugins/mod.rs @@ -158,6 +158,7 @@ pub enum PluginInstruction { }, WatchFilesystem, ListClientsToPlugin(SessionLayoutMetadata, PluginId, ClientId), + ChangePluginHostDir(PathBuf, PluginId, ClientId), Exit, } @@ -204,6 +205,7 @@ impl From<&PluginInstruction> for PluginContext { PluginContext::FailedToWriteConfigToDisk }, PluginInstruction::ListClientsToPlugin(..) => PluginContext::ListClientsToPlugin, + PluginInstruction::ChangePluginHostDir(..) => PluginContext::ChangePluginHostDir, } } } @@ -886,6 +888,11 @@ pub(crate) fn plugin_thread_main( PluginInstruction::WatchFilesystem => { wasm_bridge.start_fs_watcher_if_not_started(); }, + PluginInstruction::ChangePluginHostDir(new_host_folder, plugin_id, client_id) => { + wasm_bridge + .change_plugin_host_dir(new_host_folder, plugin_id, client_id) + .non_fatal(); + }, PluginInstruction::Exit => { break; }, diff --git a/zellij-server/src/plugins/plugin_loader.rs b/zellij-server/src/plugins/plugin_loader.rs index 760824d78e..56ae678632 100644 --- a/zellij-server/src/plugins/plugin_loader.rs +++ b/zellij-server/src/plugins/plugin_loader.rs @@ -14,7 +14,7 @@ use std::{ }; use url::Url; use wasmtime::{Engine, Instance, Linker, Module, Store}; -use wasmtime_wasi::{DirPerms, FilePerms, WasiCtxBuilder}; +use wasmtime_wasi::{preview1::WasiP1Ctx, DirPerms, FilePerms, WasiCtxBuilder}; use zellij_utils::consts::ZELLIJ_PLUGIN_ARTIFACT_DIR; use zellij_utils::prost::Message; @@ -64,7 +64,7 @@ pub struct PluginLoader<'a> { size: Size, wasm_blob_on_hd: Option<(Vec, PathBuf)>, path_to_default_shell: PathBuf, - zellij_cwd: PathBuf, + plugin_cwd: PathBuf, capabilities: PluginCapabilities, client_attributes: ClientAttributes, default_shell: Option, @@ -85,7 +85,7 @@ impl<'a> PluginLoader<'a> { connected_clients: Arc>>, loading_indication: &mut LoadingIndication, path_to_default_shell: PathBuf, - zellij_cwd: PathBuf, + plugin_cwd: PathBuf, capabilities: PluginCapabilities, client_attributes: ClientAttributes, default_shell: Option, @@ -110,7 +110,7 @@ impl<'a> PluginLoader<'a> { engine, &plugin_dir, path_to_default_shell, - Some(zellij_cwd), + Some(plugin_cwd), capabilities, client_attributes, default_shell, @@ -145,7 +145,7 @@ impl<'a> PluginLoader<'a> { connected_clients: Arc>>, loading_indication: &mut LoadingIndication, path_to_default_shell: PathBuf, - zellij_cwd: PathBuf, + plugin_cwd: PathBuf, capabilities: PluginCapabilities, client_attributes: ClientAttributes, default_shell: Option, @@ -168,7 +168,7 @@ impl<'a> PluginLoader<'a> { tab_index, size, path_to_default_shell, - zellij_cwd, + plugin_cwd, capabilities, client_attributes, default_shell, @@ -222,7 +222,7 @@ impl<'a> PluginLoader<'a> { connected_clients: Arc>>, loading_indication: &mut LoadingIndication, path_to_default_shell: PathBuf, - zellij_cwd: PathBuf, + plugin_cwd: PathBuf, capabilities: PluginCapabilities, client_attributes: ClientAttributes, default_shell: Option, @@ -246,7 +246,7 @@ impl<'a> PluginLoader<'a> { engine.clone(), &plugin_dir, path_to_default_shell.clone(), - zellij_cwd.clone(), + plugin_cwd.clone(), capabilities.clone(), client_attributes.clone(), default_shell.clone(), @@ -333,7 +333,7 @@ impl<'a> PluginLoader<'a> { tab_index: Option, size: Size, path_to_default_shell: PathBuf, - zellij_cwd: PathBuf, + plugin_cwd: PathBuf, capabilities: PluginCapabilities, client_attributes: ClientAttributes, default_shell: Option, @@ -366,7 +366,7 @@ impl<'a> PluginLoader<'a> { size, wasm_blob_on_hd: None, path_to_default_shell, - zellij_cwd, + plugin_cwd, capabilities, client_attributes, default_shell, @@ -412,7 +412,7 @@ impl<'a> PluginLoader<'a> { // prefer the explicitly given cwd, otherwise copy it from the running plugin // (when reloading a plugin, we want to copy it, when starting a new plugin instance from // meomory, we want to reset it) - let zellij_cwd = cwd.unwrap_or_else(|| running_plugin.store.data().plugin_cwd.clone()); + let plugin_cwd = cwd.unwrap_or_else(|| running_plugin.store.data().plugin_cwd.clone()); loading_indication.set_name(running_plugin.store.data().name()); PluginLoader::new( plugin_cache, @@ -426,7 +426,7 @@ impl<'a> PluginLoader<'a> { tab_index, size, path_to_default_shell, - zellij_cwd, + plugin_cwd, capabilities, client_attributes, default_shell, @@ -446,7 +446,7 @@ impl<'a> PluginLoader<'a> { engine: Engine, plugin_dir: &'a PathBuf, path_to_default_shell: PathBuf, - zellij_cwd: PathBuf, + plugin_cwd: PathBuf, capabilities: PluginCapabilities, client_attributes: ClientAttributes, default_shell: Option, @@ -483,7 +483,7 @@ impl<'a> PluginLoader<'a> { tab_index, size, path_to_default_shell, - zellij_cwd, + plugin_cwd, capabilities, client_attributes, default_shell, @@ -736,7 +736,7 @@ impl<'a> PluginLoader<'a> { self.engine.clone(), &self.plugin_dir, self.path_to_default_shell.clone(), - self.zellij_cwd.clone(), + self.plugin_cwd.clone(), self.capabilities.clone(), self.client_attributes.clone(), self.default_shell.clone(), @@ -784,18 +784,22 @@ impl<'a> PluginLoader<'a> { }, } } - fn create_plugin_instance_env(&self, module: &Module) -> Result<(Store, Instance)> { - let err_context = || { - format!( - "Failed to create instance, plugin env and subscriptions for plugin {}", - self.plugin_id - ) - }; + pub fn create_wasi_ctx( + host_dir: &PathBuf, + data_dir: &PathBuf, + cache_dir: &PathBuf, + tmp_dir: &PathBuf, + plugin_url: &String, + plugin_id: PluginId, + stdin_pipe: Arc>>, + stdout_pipe: Arc>>, + ) -> Result { + let err_context = || format!("Failed to create wasi_ctx"); let dirs = vec![ - ("/host".to_owned(), self.zellij_cwd.clone()), - ("/data".to_owned(), self.plugin_own_data_dir.clone()), - ("/cache".to_owned(), self.plugin_own_cache_dir.clone()), - ("/tmp".to_owned(), ZELLIJ_TMP_DIR.clone()), + ("/host".to_owned(), host_dir.clone()), + ("/data".to_owned(), data_dir.clone()), + ("/cache".to_owned(), cache_dir.clone()), + ("/tmp".to_owned(), tmp_dir.clone()), ]; let dirs = dirs.into_iter().filter(|(_dir_name, dir)| { // note that this does not protect against TOCTOU errors @@ -812,16 +816,35 @@ impl<'a> PluginLoader<'a> { .preopened_dir(host_path, guest_path, DirPerms::all(), FilePerms::all()) .with_context(err_context)?; } - let stdin_pipe = Arc::new(Mutex::new(VecDeque::new())); - let stdout_pipe = Arc::new(Mutex::new(VecDeque::new())); wasi_ctx_builder .stdin(VecDequeInputStream(stdin_pipe.clone())) .stdout(WriteOutputStream(stdout_pipe.clone())) .stderr(WriteOutputStream(Arc::new(Mutex::new(LoggingPipe::new( - &self.plugin.location.to_string(), - self.plugin_id, + plugin_url, plugin_id, ))))); let wasi_ctx = wasi_ctx_builder.build_p1(); + Ok(wasi_ctx) + } + fn create_plugin_instance_env(&self, module: &Module) -> Result<(Store, Instance)> { + let err_context = || { + format!( + "Failed to create instance, plugin env and subscriptions for plugin {}", + self.plugin_id + ) + }; + let stdin_pipe = Arc::new(Mutex::new(VecDeque::new())); + let stdout_pipe = Arc::new(Mutex::new(VecDeque::new())); + + let wasi_ctx = PluginLoader::create_wasi_ctx( + &self.plugin_cwd, + &self.plugin_own_data_dir, + &self.plugin_own_cache_dir, + &ZELLIJ_TMP_DIR, + &self.plugin.location.to_string(), + self.plugin_id, + stdin_pipe.clone(), + stdout_pipe.clone(), + )?; let plugin = self.plugin.clone(); let plugin_env = PluginEnv { plugin_id: self.plugin_id, @@ -838,7 +861,7 @@ impl<'a> PluginLoader<'a> { client_attributes: self.client_attributes.clone(), default_shell: self.default_shell.clone(), default_layout: self.default_layout.clone(), - plugin_cwd: self.zellij_cwd.clone(), + plugin_cwd: self.plugin_cwd.clone(), input_pipes_to_unblock: Arc::new(Mutex::new(HashSet::new())), input_pipes_to_block: Arc::new(Mutex::new(HashSet::new())), layout_dir: self.layout_dir.clone(), diff --git a/zellij-server/src/plugins/wasm_bridge.rs b/zellij-server/src/plugins/wasm_bridge.rs index eceed20211..6096cbd6e0 100644 --- a/zellij-server/src/plugins/wasm_bridge.rs +++ b/zellij-server/src/plugins/wasm_bridge.rs @@ -4,6 +4,7 @@ use crate::plugins::pipes::{ }; use crate::plugins::plugin_loader::PluginLoader; use crate::plugins::plugin_map::{AtomicEvent, PluginEnv, PluginMap, RunningPlugin, Subscriptions}; + use crate::plugins::plugin_worker::MessageToWorker; use crate::plugins::watch_filesystem::watch_filesystem; use crate::plugins::zellij_exports::{wasi_read_string, wasi_write_object}; @@ -18,7 +19,7 @@ use std::{ use wasmtime::{Engine, Module}; use zellij_utils::async_channel::Sender; use zellij_utils::async_std::task::{self, JoinHandle}; -use zellij_utils::consts::ZELLIJ_CACHE_DIR; +use zellij_utils::consts::{ZELLIJ_CACHE_DIR, ZELLIJ_TMP_DIR}; use zellij_utils::data::{InputMode, PermissionStatus, PermissionType, PipeMessage, PipeSource}; use zellij_utils::downloader::Downloader; use zellij_utils::input::keybinds::Keybinds; @@ -736,6 +737,107 @@ impl WasmBridge { } Ok(()) } + pub fn change_plugin_host_dir( + &mut self, + new_host_dir: PathBuf, + plugin_id_to_update: PluginId, + client_id_to_update: ClientId, + ) -> Result<()> { + let plugins_to_change: Vec<( + PluginId, + ClientId, + Arc>, + Arc>, + )> = self + .plugin_map + .lock() + .unwrap() + .running_plugins_and_subscriptions() + .iter() + .cloned() + .filter(|(plugin_id, _client_id, _running_plugin, _subscriptions)| { + // TODO: cache this somehow in this case... + !&self + .cached_events_for_pending_plugins + .contains_key(&plugin_id) + }) + .collect(); + task::spawn({ + let senders = self.senders.clone(); + async move { + match new_host_dir.try_exists() { + Ok(false) => { + log::error!( + "Failed to change folder to {},: folder does not exist", + new_host_dir.display() + ); + let _ = senders.send_to_plugin(PluginInstruction::Update(vec![( + Some(plugin_id_to_update), + Some(client_id_to_update), + Event::FailedToChangeHostFolder(Some(format!( + "Folder {} does not exist", + new_host_dir.display() + ))), + )])); + return; + }, + Err(e) => { + log::error!( + "Failed to change folder to {},: {}", + new_host_dir.display(), + e + ); + let _ = senders.send_to_plugin(PluginInstruction::Update(vec![( + Some(plugin_id_to_update), + Some(client_id_to_update), + Event::FailedToChangeHostFolder(Some(e.to_string())), + )])); + return; + }, + _ => {}, + } + for (plugin_id, client_id, running_plugin, _subscriptions) in &plugins_to_change { + if plugin_id == &plugin_id_to_update && client_id == &client_id_to_update { + let mut running_plugin = running_plugin.lock().unwrap(); + let plugin_env = running_plugin.store.data_mut(); + let stdin_pipe = plugin_env.stdin_pipe.clone(); + let stdout_pipe = plugin_env.stdout_pipe.clone(); + let wasi_ctx = PluginLoader::create_wasi_ctx( + &new_host_dir, + &plugin_env.plugin_own_data_dir, + &plugin_env.plugin_own_cache_dir, + &ZELLIJ_TMP_DIR, + &plugin_env.plugin.location.to_string(), + plugin_env.plugin_id, + stdin_pipe.clone(), + stdout_pipe.clone(), + ); + match wasi_ctx { + Ok(wasi_ctx) => { + drop(std::mem::replace(&mut plugin_env.wasi_ctx, wasi_ctx)); + plugin_env.plugin_cwd = new_host_dir.clone(); + + let _ = senders.send_to_plugin(PluginInstruction::Update(vec![( + Some(*plugin_id), + Some(*client_id), + Event::HostFolderChanged(new_host_dir.clone()), + )])); + }, + Err(e) => { + let _ = senders.send_to_plugin(PluginInstruction::Update(vec![( + Some(*plugin_id), + Some(*client_id), + Event::FailedToChangeHostFolder(Some(e.to_string())), + )])); + log::error!("Failed to create wasi ctx: {}", e); + }, + } + } + } + } + }); + Ok(()) + } pub fn pipe_messages( &mut self, mut messages: Vec<(Option, Option, PipeMessage)>, diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs index d308689b9f..5fba8aaaef 100644 --- a/zellij-server/src/plugins/zellij_exports.rs +++ b/zellij-server/src/plugins/zellij_exports.rs @@ -352,6 +352,15 @@ fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) { write_config_to_disk, } => rebind_keys(env, keys_to_rebind, keys_to_unbind, write_config_to_disk)?, PluginCommand::ListClients => list_clients(env), + PluginCommand::ChangeHostFolder(new_host_folder) => { + change_host_folder(env, new_host_folder) + }, + PluginCommand::SetFloatingPanePinned(pane_id, should_be_pinned) => { + set_floating_pane_pinned(env, pane_id.into(), should_be_pinned) + }, + PluginCommand::StackPanes(pane_ids) => { + stack_panes(env, pane_ids.into_iter().map(|p_id| p_id.into()).collect()) + }, }, (PermissionStatus::Denied, permission) => { log::error!( @@ -1139,21 +1148,29 @@ fn switch_session( return Err(anyhow!("Failed to deserialize layout: {}", e)); } } - let client_id = env.client_id; - let tab_position = tab_position.map(|p| p + 1); // ¯\_()_/¯ - let connect_to_session = ConnectToSession { - name: session_name, - tab_position, - pane_id, - layout, - cwd, - }; - env.senders - .send_to_server(ServerInstruction::SwitchSession( - connect_to_session, - client_id, - )) - .with_context(err_context)?; + if session_name + .as_ref() + .map(|s| s.contains('/')) + .unwrap_or(false) + { + log::error!("Session names cannot contain \'/\'"); + } else { + let client_id = env.client_id; + let tab_position = tab_position.map(|p| p + 1); // ¯\_()_/¯ + let connect_to_session = ConnectToSession { + name: session_name, + tab_position, + pane_id, + layout, + cwd, + }; + env.senders + .send_to_server(ServerInstruction::SwitchSession( + connect_to_session, + client_id, + )) + .with_context(err_context)?; + } Ok(()) } @@ -1434,8 +1451,12 @@ fn rename_tab(env: &PluginEnv, tab_index: u32, new_name: &str) { fn rename_session(env: &PluginEnv, new_session_name: String) { let error_msg = || format!("failed to rename session in plugin {}", env.name()); - let action = Action::RenameSession(new_session_name); - apply_action!(action, error_msg, env); + if new_session_name.contains('/') { + log::error!("Session names cannot contain \'/\'"); + } else { + let action = Action::RenameSession(new_session_name); + apply_action!(action, error_msg, env); + } } fn disconnect_other_clients(env: &PluginEnv) { @@ -1484,6 +1505,31 @@ fn list_clients(env: &PluginEnv) { }); } +fn change_host_folder(env: &PluginEnv, new_host_folder: PathBuf) { + let _ = env.senders.to_plugin.as_ref().map(|sender| { + sender.send(PluginInstruction::ChangePluginHostDir( + new_host_folder, + env.plugin_id, + env.client_id, + )) + }); +} + +fn set_floating_pane_pinned(env: &PluginEnv, pane_id: PaneId, should_be_pinned: bool) { + let _ = env.senders.to_screen.as_ref().map(|sender| { + sender.send(ScreenInstruction::SetFloatingPanePinned( + pane_id, + should_be_pinned, + )) + }); +} + +fn stack_panes(env: &PluginEnv, pane_ids: Vec) { + let _ = env + .senders + .send_to_screen(ScreenInstruction::StackPanes(pane_ids)); +} + fn scan_host_folder(env: &PluginEnv, folder_to_scan: PathBuf) { if !folder_to_scan.starts_with("/host") { log::error!( @@ -1902,6 +1948,8 @@ fn check_command_permission( | PluginCommand::BreakPanesToTabWithIndex(..) | PluginCommand::ReloadPlugin(..) | PluginCommand::LoadNewPlugin { .. } + | PluginCommand::SetFloatingPanePinned(..) + | PluginCommand::StackPanes(..) | PluginCommand::KillSessions(..) => PermissionType::ChangeApplicationState, PluginCommand::UnblockCliPipeInput(..) | PluginCommand::BlockCliPipeInput(..) @@ -1913,6 +1961,7 @@ fn check_command_permission( PluginCommand::RebindKeys { .. } | PluginCommand::Reconfigure(..) => { PermissionType::Reconfigure }, + PluginCommand::ChangeHostFolder(..) => PermissionType::FullHdAccess, _ => return (PermissionStatus::Granted, None), }; diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index fda6a7a8bf..d611fdcdb8 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -969,6 +969,18 @@ pub(crate) fn route_action( )) .with_context(err_context)?; }, + Action::TogglePanePinned => { + senders + .send_to_screen(ScreenInstruction::TogglePanePinned(client_id)) + .with_context(err_context)?; + }, + Action::StackPanes(pane_ids_to_stack) => { + senders + .send_to_screen(ScreenInstruction::StackPanes( + pane_ids_to_stack.iter().map(|p| PaneId::from(*p)).collect(), + )) + .with_context(err_context)?; + }, } Ok(should_break) } diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index e04ff35c49..7f1e044a2d 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -405,6 +405,9 @@ pub enum ScreenInstruction { client_id: ClientId, }, ListClientsToPlugin(PluginId, ClientId), + TogglePanePinned(ClientId), + SetFloatingPanePinned(PaneId, bool), + StackPanes(Vec), } impl From<&ScreenInstruction> for ScreenContext { @@ -617,6 +620,9 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenContext::BreakPanesToTabWithIndex }, ScreenInstruction::ListClientsToPlugin(..) => ScreenContext::ListClientsToPlugin, + ScreenInstruction::TogglePanePinned(..) => ScreenContext::TogglePanePinned, + ScreenInstruction::SetFloatingPanePinned(..) => ScreenContext::SetFloatingPanePinned, + ScreenInstruction::StackPanes(..) => ScreenContext::StackPanes, } } } @@ -2034,8 +2040,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, false, Some(client_id)); + plugin_pane_to_move_to_active_tab = tab.extract_pane(plugin_pane_id, true); } break; @@ -2051,7 +2056,6 @@ impl Screen { plugin_pane_to_move_to_active_tab, pane_id, None, - Some(client_id), )?; } else { new_active_tab.hide_floating_panes(); @@ -2090,15 +2094,16 @@ impl Screen { .tabs .iter() .find(|(_tab_index, tab)| tab.has_pane_with_pid(&pane_id)) - .map(|(tab_index, _tab)| *tab_index); + .map(|(_tab_index, tab)| tab.position); match tab_index { Some(tab_index) => { self.go_to_tab(tab_index + 1, client_id)?; self.tabs - .get_mut(&tab_index) - .with_context(err_context)? - .focus_pane_with_id(pane_id, should_float_if_hidden, client_id) - .context("failed to focus pane with id")?; + .iter_mut() + .find(|(_, t)| t.position == tab_index) + .map(|(_, t)| t.focus_pane_with_id(pane_id, should_float_if_hidden, client_id)) + .with_context(err_context) + .non_fatal(); }, None => { log::error!("Could not find pane with id: {:?}", pane_id); @@ -2151,7 +2156,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(); @@ -2164,7 +2169,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) @@ -2216,7 +2221,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; } @@ -2271,7 +2276,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) }; @@ -2288,12 +2293,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))?; @@ -2343,7 +2343,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; } @@ -2378,7 +2378,6 @@ impl Screen { pane_title: Option, client_id_tab_index_or_pane_id: ClientTabIndexOrPaneId, ) -> Result<()> { - let err_context = || format!("failed to replace pane"); let suppress_pane = |tab: &mut Tab, pane_id: PaneId, new_pane_id: PaneId| { let _ = tab.suppress_pane_and_replace_with_pid(pane_id, new_pane_id, run); if let Some(pane_title) = pane_title { @@ -2410,11 +2409,14 @@ impl Screen { .tabs .iter() .find(|(_tab_index, tab)| tab.has_pane_with_pid(&pane_id)) - .map(|(tab_index, _tab)| *tab_index); + .map(|(_tab_index, tab)| tab.position); match tab_index { Some(tab_index) => { - let tab = self.tabs.get_mut(&tab_index).with_context(err_context)?; - suppress_pane(tab, pane_id, new_pane_id); + if let Some(tab) = + self.tabs.iter_mut().find(|(_, t)| t.position == tab_index) + { + suppress_pane(tab.1, pane_id, new_pane_id); + } }, None => { log::error!("Could not find pane with id: {:?}", pane_id); @@ -2495,6 +2497,88 @@ impl Screen { } Ok(()) } + pub fn toggle_pane_pinned(&mut self, client_id: ClientId) { + active_tab_and_connected_client_id!( + self, + client_id, + |tab: &mut Tab, client_id: ClientId| { + tab.toggle_pane_pinned(client_id); + } + ); + self.unblock_input().non_fatal(); + } + pub fn set_floating_pane_pinned(&mut self, pane_id: PaneId, should_be_pinned: bool) { + let mut found = false; + for tab in self.tabs.values_mut() { + if tab.has_pane_with_pid(&pane_id) { + tab.set_floating_pane_pinned(pane_id, should_be_pinned); + found = true; + break; + } + } + if !found { + log::error!( + "Failed to find pane with id: {:?} to set as pinned", + pane_id + ); + } + } + pub fn stack_panes(&mut self, mut pane_ids_to_stack: Vec) { + if pane_ids_to_stack.is_empty() { + log::error!("Got an empty list of pane_ids to stack"); + return; + } + let stack_size = pane_ids_to_stack.len(); + let root_pane_id = pane_ids_to_stack.remove(0); + let Some(root_tab_id) = self + .tabs + .iter() + .find_map(|(tab_id, tab)| { + if tab.has_pane_with_pid(&root_pane_id) { + Some(tab_id) + } else { + None + } + }) + .copied() + else { + log::error!("Failed to find tab for root_pane_id: {:?}", root_pane_id); + return; + }; + let target_tab_has_room_for_stack = self + .tabs + .get(&root_tab_id) + .map(|t| t.has_room_for_stack(root_pane_id, stack_size)) + .unwrap_or(false); + if !target_tab_has_room_for_stack { + log::error!("No room for stack with root pane id: {:?}", root_pane_id); + return; + } + + let mut panes_to_stack = vec![]; + for (tab_id, tab) in self.tabs.iter_mut() { + if tab_id == &root_tab_id { + // we do this before we extract panes so that the extraction won't trigger a + // relayout according to the next swapped tiled pane + tab.set_tiled_panes_damaged(); + } + for pane_id in &pane_ids_to_stack { + if tab.has_pane_with_pid(&pane_id) { + match tab.extract_pane(*pane_id, false) { + Some(pane) => { + panes_to_stack.push(pane); + }, + None => { + log::error!("Failed to extract pane: {:?}", pane_id); + }, + } + } + } + } + self.tabs + .get_mut(&root_tab_id) + .map(|t| t.stack_panes(root_pane_id, panes_to_stack)); + } fn unblock_input(&self) -> Result<()> { self.bus .senders @@ -3338,16 +3422,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; } } @@ -3481,7 +3562,7 @@ pub(crate) fn screen_thread_main( pending_tab_ids.remove(&tab_index); if pending_tab_ids.is_empty() { for (tab_index, client_id) in pending_tab_switches.drain() { - screen.go_to_tab(tab_index as usize, client_id)?; + screen.go_to_tab(tab_index as usize + 1, client_id)?; } if should_change_focus_to_new_tab { screen.go_to_tab(tab_index as usize + 1, client_id)?; @@ -3870,7 +3951,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)?; @@ -3881,7 +3962,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)?; @@ -4709,6 +4790,17 @@ pub(crate) fn screen_thread_main( client_id, )?; }, + ScreenInstruction::TogglePanePinned(client_id) => { + screen.toggle_pane_pinned(client_id); + }, + ScreenInstruction::SetFloatingPanePinned(pane_id, should_be_pinned) => { + screen.set_floating_pane_pinned(pane_id, should_be_pinned); + }, + ScreenInstruction::StackPanes(pane_ids_to_stack) => { + screen.stack_panes(pane_ids_to_stack); + let _ = screen.unblock_input(); + let _ = screen.render(None); + }, } } Ok(()) diff --git a/zellij-server/src/tab/layout_applier.rs b/zellij-server/src/tab/layout_applier.rs index 3b02d373c6..e2bb5ccb4d 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)); }, } } - 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, + + // 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, ) { - 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); + pane_applier.apply_position_and_size_to_tiled_pane(pane, position_and_size, layout); + } else { + positions_left.push((layout, position_and_size)); } } - 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); + + // 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(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); } } - pane_focuser.focus_tiled_pane(&mut self.tiled_panes); + + // 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(); + 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 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 + 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) - 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()) + // (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) { - 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) - }) + // found exact match + } else if self + .place_running_pane_in_empty_location(&run_instruction, positions_in_layout) { - 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, - ); + // found empty location } else { - log::error!( - "Failed to find room for run instruction: {:?}", - run_instruction - ); + // no room! we'll add it below after we place everything else + run_instructions_without_a_location.push(run_instruction); } } - - // then, we open new panes for each run instruction in the layout with the details + 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(); - for (layout, position_and_size) in positions_and_size { + // 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); + } + }; + for (layout, position_and_size) in positions_in_layout { 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 { + 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 - 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)); - } + 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)); } } + 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 { + let _ = self + .senders + .send_to_pty(PtyInstruction::ClosePane(PaneId::Terminal(*unused_pid))); + } + } + 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 - .send_to_pty(PtyInstruction::ClosePane(PaneId::Terminal(*unused_pid))) - .with_context(err_context)?; + .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()); } - self.adjust_viewport().with_context(err_context)?; - self.set_focused_tiled_pane(focus_pane_id, client_id); + + 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() + .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(&first_candidate); + 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( + fn find_pane_id_with_same_contents( &self, - is_focused: bool, candidates: &Vec<(&PaneId, &Box)>, + run: &Option, + pane_logical_position: Option, ) -> Option { - if is_focused { - candidates + if run.is_none() { + return None; + } + let panes_with_same_contents = candidates + .iter() + .filter(|(_pid, p)| p.invoked_with() == run) + .collect::>(); + if panes_with_same_contents.len() > 1 { + panes_with_same_contents .iter() - .find(|(pid, _p)| Some(**pid) == self.currently_focused_pane_id) + .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 { - None + panes_with_same_contents + .iter() + .next() + .map(|(pid, _p)| *pid) + .copied() } } - fn find_pane_id_with_same_contents( + fn find_pane_id_with_same_logical_position( &self, candidates: &Vec<(&PaneId, &Box)>, - run: &Option, + logical_position: Option, ) -> Option { candidates .iter() - .find(|(_pid, p)| p.invoked_with() == run) - .map(|(pid, _p)| *pid) - .copied() - } - fn find_pane_id_with_same_contents_and_location( - &self, - candidates: &Vec<(&PaneId, &Box)>, - run: &Option, - position: &PaneGeom, - ) -> 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 apply_floating_panes_layout_to_floating_pane( + &mut self, + mut pane: Box, + floating_panes_layout: FloatingPaneLayout, + ) { + 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 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)); + 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); + } } - 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); + } + 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); } - } else { - tiled_panes.reapply_pane_focus(); - } - }, - None => { - tiled_panes.reapply_pane_focus(); - }, + }, + None => { + log::error!("could not find room for pane!") + }, + } } - for pane_id in &self.expanded_stacked_pane_ids { - tiled_panes.expand_pane_in_stack(*pane_id); + } + 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 focus_floating_pane( + 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, - floating_panes: &mut FloatingPanes, - os_api: &mut Box, + pane: &mut Box, + layout: &TiledPaneLayout, + position_and_size: Option, ) { - 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); - } + 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 d69a23cb84..bb3e8a7f1c 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -397,6 +397,10 @@ pub trait Pane { } false } + fn intercept_left_mouse_click(&mut self, _position: &Position, _client_id: ClientId) -> bool { + let intercepted = false; + intercepted + } fn store_pane_name(&mut self); fn load_pane_name(&mut self); fn set_borderless(&mut self, borderless: bool); @@ -500,6 +504,12 @@ pub trait Pane { fn query_should_be_suppressed(&self) -> bool { false } + fn drain_fake_cursors(&mut self) -> Option> { + None + } + fn toggle_pinned(&mut self) {} + fn set_pinned(&mut self, _should_be_pinned: bool) {} + fn reset_logical_position(&mut self) {} } #[derive(Clone, Debug)] @@ -722,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) @@ -753,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, @@ -810,41 +792,33 @@ 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(); // we do this so that the new swap layout has a chance to pass through the constraint system self.tiled_panes.resize(display_area); - self.should_clear_display_before_rendering = true; + 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) @@ -999,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}", )) @@ -1017,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(()) @@ -1044,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",) }) @@ -1057,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(()) @@ -1203,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) } @@ -1473,7 +1440,7 @@ impl Tab { ); self.tiled_panes .split_pane_horizontally(pid, Box::new(new_terminal), client_id); - self.should_clear_display_before_rendering = true; + self.set_should_clear_display_before_rendering(); self.tiled_panes.focus_pane(pid, client_id); self.swap_layouts.set_is_tiled_damaged(); } @@ -1533,7 +1500,7 @@ impl Tab { ); self.tiled_panes .split_pane_vertically(pid, Box::new(new_terminal), client_id); - self.should_clear_display_before_rendering = true; + self.set_should_clear_display_before_rendering(); self.tiled_panes.focus_pane(pid, client_id); self.swap_layouts.set_is_tiled_damaged(); } @@ -1905,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 }) => { @@ -2096,6 +2063,11 @@ impl Tab { self.tiled_panes.set_force_render(); self.floating_panes.set_force_render(); } + pub fn set_should_clear_display_before_rendering(&mut self) { + self.should_clear_display_before_rendering = true; + self.floating_panes.set_force_render(); // we do this to make sure pinned panes are + // rendered even if their surface is not visible + } pub fn is_sync_panes_active(&self) -> bool { self.synchronize_is_active } @@ -2144,7 +2116,9 @@ impl Tab { self.tiled_panes .render(output, self.floating_panes.panes_are_visible()) .with_context(err_context)?; - if self.floating_panes.panes_are_visible() && self.floating_panes.has_active_panes() { + if (self.floating_panes.panes_are_visible() && self.floating_panes.has_active_panes()) + || self.floating_panes.has_pinned_panes() + { self.floating_panes .render(output) .with_context(err_context)?; @@ -2179,7 +2153,19 @@ impl Tab { let connected_clients: Vec = { self.connected_clients.borrow().iter().copied().collect() }; for client_id in connected_clients { - match self.get_active_terminal_cursor_position(client_id) { + match self + .get_active_terminal_cursor_position(client_id) + .and_then(|(cursor_position_x, cursor_position_y)| { + // TODO: get active_pane_z_index and pass it to cursor_is_visible so we do the + // right thing if the cursor is in a floating pane + if self.floating_panes.panes_are_visible() { + Some((cursor_position_x, cursor_position_y)) + } else if output.cursor_is_visible(cursor_position_x, cursor_position_y) { + Some((cursor_position_x, cursor_position_y)) + } else { + None + } + }) { Some((cursor_position_x, cursor_position_y)) => { let desired_cursor_shape = self .get_active_pane(client_id) @@ -2298,14 +2284,14 @@ 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.should_clear_display_before_rendering = true; + self.set_should_clear_display_before_rendering(); self.senders .send_to_pty_writer(PtyWriteInstruction::ApplyCachedResizes) .with_context(|| format!("failed to update plugins with mode info"))?; @@ -2645,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(()) @@ -2701,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 @@ -2735,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() { @@ -2748,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![( @@ -2760,12 +2741,18 @@ impl Tab { pub fn extract_pane( &mut self, id: PaneId, - ignore_suppressed_panes: bool, - client_id: Option, + dont_swap_if_suppressed: bool, ) -> Option> { - if !ignore_suppressed_panes && self.suppressed_panes.contains_key(&id) { + 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)) @@ -2775,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(); @@ -2789,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) { @@ -2894,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))?; @@ -2902,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))?; @@ -3252,6 +3247,14 @@ impl Tab { { return Ok(self.floating_panes.get_pane_mut(pane_id)); } + } else if self.floating_panes.has_pinned_panes() { + if let Some(pane_id) = self + .floating_panes + .get_pinned_pane_id_at(point, search_selectable) + .with_context(err_context)? + { + return Ok(self.floating_panes.get_pane_mut(pane_id)); + } } if let Some(pane_id) = self .get_pane_id_at(point, search_selectable) @@ -3301,6 +3304,31 @@ impl Tab { ) }; + let intercepted = self + .get_pane_at(position, false) + .with_context(err_context)? + .map(|pane| pane.intercept_left_mouse_click(&position, client_id)) + .unwrap_or(false); + if intercepted { + self.set_force_render(); + return Ok(()); + } + + if !self.floating_panes.panes_are_visible() { + let search_selectable = false; + if let Ok(Some(pane_id)) = self + .floating_panes + .get_pinned_pane_id_at(position, search_selectable) + { + // here, the floating panes are not visible, but there is a pinned pane (always + // visible) that has been clicked on - so we make the entire surface visible and + // focus it + self.show_floating_panes(); + self.floating_panes.focus_pane(pane_id, client_id); + return Ok(()); + } + } + self.focus_pane_at(position, client_id) .with_context(err_context)?; @@ -3884,7 +3912,7 @@ impl Tab { pub fn set_pane_frames(&mut self, should_set_pane_frames: bool) { self.tiled_panes.set_pane_frames(should_set_pane_frames); self.draw_pane_frames = should_set_pane_frames; - self.should_clear_display_before_rendering = true; + self.set_should_clear_display_before_rendering(); self.set_force_render(); } pub fn panes_to_hide_count(&self) -> usize { @@ -4082,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)) @@ -4095,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 => { @@ -4104,12 +4131,12 @@ impl Tab { }, } } - pub fn suppress_pane(&mut self, pane_id: PaneId, client_id: Option) { + pub fn suppress_pane(&mut self, pane_id: PaneId, _client_id: Option) { // this method places a pane in the suppressed pane with its own ID - this means we'll // 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)); @@ -4136,12 +4163,14 @@ 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() { if let Some(floating_pane_coordinates) = floating_pane_coordinates { let viewport = self.viewport.borrow(); + if let Some(pinned) = floating_pane_coordinates.pinned.as_ref() { + pane.set_pinned(*pinned); + } new_pane_geom.adjust_coordinates(floating_pane_coordinates, *viewport); self.swap_layouts.set_is_floating_damaged(); } @@ -4158,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(()) } @@ -4181,7 +4210,7 @@ impl Tab { } else { self.tiled_panes.insert_pane(pane_id, pane); } - self.should_clear_display_before_rendering = true; + self.set_should_clear_display_before_rendering(); if let Some(client_id) = client_id { self.tiled_panes.focus_pane(pane_id, client_id); } @@ -4191,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(()) } @@ -4347,6 +4376,67 @@ impl Tab { self.suppressed_panes.insert(pane_id, suppressed_pane_entry); } } + pub fn toggle_pane_pinned(&mut self, client_id: ClientId) { + if let Some(pane) = self.get_active_pane_mut(client_id) { + pane.toggle_pinned(); + self.set_force_render(); + } + } + pub fn set_floating_pane_pinned(&mut self, pane_id: PaneId, should_be_pinned: bool) { + if let Some(pane) = self.get_pane_with_id_mut(pane_id) { + pane.set_pinned(should_be_pinned); + self.set_force_render(); + } + } + pub fn has_room_for_stack(&self, root_pane_id: PaneId, stack_size: usize) -> bool { + if self.floating_panes.panes_contain(&root_pane_id) + || self.suppressed_panes.contains_key(&root_pane_id) + { + log::error!("Root pane of stack cannot be floating or suppressed"); + return false; + } + self.get_pane_with_id(root_pane_id) + .map(|p| p.position_and_size().rows.as_usize() >= stack_size + MIN_TERMINAL_HEIGHT) + .unwrap_or(false) + } + pub fn set_tiled_panes_damaged(&mut self) { + self.swap_layouts.set_is_tiled_damaged(); + } + pub fn stack_panes(&mut self, root_pane_id: PaneId, mut panes_to_stack: Vec>) { + if panes_to_stack.is_empty() { + // nothing to do + return; + } + self.swap_layouts.set_is_tiled_damaged(); // TODO: verify we can do all the below first + + // + 1 for the root pane + let mut stack_geoms = self + .tiled_panes + .stack_panes(root_pane_id, panes_to_stack.len() + 1); + if stack_geoms.is_empty() { + log::error!("Failed to find room for stacked panes"); + return; + } + self.tiled_panes + .set_geom_for_pane_with_id(&root_pane_id, stack_geoms.remove(0)); + let mut focused_pane_id_in_stack = None; + for mut pane in panes_to_stack.drain(..) { + let pane_id = pane.pid(); + let stack_geom = stack_geoms.remove(0); + pane.set_geom(stack_geom); + self.tiled_panes.add_pane_with_existing_geom(pane_id, pane); + if self.tiled_panes.pane_id_is_focused(&pane_id) { + focused_pane_id_in_stack = Some(pane_id); + } + } + // if we had a focused pane in the stack, we expand it + if let Some(focused_pane_id_in_stack) = focused_pane_id_in_stack { + self.tiled_panes + .expand_pane_in_stack(focused_pane_id_in_stack); + } else if self.tiled_panes.pane_id_is_focused(&root_pane_id) { + self.tiled_panes.expand_pane_in_stack(root_pane_id); + } + } fn new_scrollback_editor_pane(&self, pid: u32) -> TerminalPane { let next_terminal_position = self.get_next_terminal_position(); let mut new_pane = TerminalPane::new( diff --git a/zellij-server/src/tab/swap_layouts.rs b/zellij-server/src/tab/swap_layouts.rs index 9b37eede9b..e61fb241eb 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_floating_layout_is_included_in_swap_layouts.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_floating_layout_is_included_in_swap_layouts.snap index e60c5fd33f..3645f69c88 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_floating_layout_is_included_in_swap_layouts.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_floating_layout_is_included_in_swap_layouts.snap @@ -1,9 +1,9 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 6089 +assertion_line: 7605 expression: snapshot --- -00 (C): ┌ zellij:tab-bar ─────────────────────────────────┌ zellij:status-bar ───────────────────────────────────────┐──────────┐ +00 (C): ┌ zellij:tab-bar ─────────────────────────────────┌ zellij:status-bar ────────────────────────────── PIN [ ] ┐──────────┐ 01 (C): │I am a tab bar │I am a │ │ 02 (C): │ │status bar │ │ 03 (C): │ │ │ │ @@ -13,7 +13,7 @@ expression: snapshot 07 (C): │ │ │ │ │ 08 (C): │ │ │ │ │ 09 (C): └─────────────────────────────│ └──────────────────────────────────────────────────────────┘ │ -10 (C): ┌ command1 ───────────────────│ ┌ command2 ────────────────────────────────────────────────┐ │ +10 (C): ┌ command1 ───────────────────│ ┌ command2 ─────────────────────────────────────── PIN [ ] ┐ │ 11 (C): │ │ │ │ │ 12 (C): │ │ │ │ │ 13 (C): │ │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_layout_is_included_in_swap_layouts.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_layout_is_included_in_swap_layouts.snap index 440d15cb87..c5f32f9ce5 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 bb6bcaab9d..988e2e8c3a 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 644233cd1c..60b735fcfc 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 ac85d9c1a9..7807f4910c 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 a18772aca4..8f0c5f6b89 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__can_swap_floating_layout_at_runtime.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_floating_layout_at_runtime.snap index 04fa9400c5..663d3c5123 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_floating_layout_at_runtime.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__can_swap_floating_layout_at_runtime.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 3022 +assertion_line: 3841 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,7 +8,7 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): ┌ Pane #2 ─────────────────────────────────────────────────┐ ┌ Pane #3 ─────────────────────────────────────────────────┐ +05 (C): ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ ┌ Pane #3 ──────────────────────────────────────── PIN [ ] ┐ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (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 8416d6e0da..88fbd45850 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 17d9500e99..5902f8ba2b 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 b065d0bcc2..3804d05b51 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__close_suppressing_floating_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_floating_pane.snap index 91910115e1..09127ecfc0 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_floating_pane.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_floating_pane.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1352 +assertion_line: 2797 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,7 +8,7 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__decrease_floating_pane_size.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__decrease_floating_pane_size.snap index 65011a6769..af28471d67 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__decrease_floating_pane_size.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__decrease_floating_pane_size.snap @@ -1,7 +1,7 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 1104 expression: snapshot - --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ @@ -9,7 +9,7 @@ expression: snapshot 03 (C): │ │ 04 (C): │ │ 05 (C): │ │ -06 (C): │ ┌ Pane #2 ─────────────────────────────────────────────┐ │ +06 (C): │ ┌ Pane #2 ──────────────────────────────────── PIN [ ] ┐ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ 09 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__drag_pane_with_mouse.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__drag_pane_with_mouse.snap index bdb531d2e9..7450c0fd60 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__drag_pane_with_mouse.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__drag_pane_with_mouse.snap @@ -1,16 +1,16 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1252 +assertion_line: 1944 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐ │ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐ │ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -04 (C): │ │E┌ Pane #6 ─────────────── SCROLL: 0/1 ┐ │ +04 (C): │ │E┌ Pane #6 ───── SCROLL: 0/1 | PIN [ ] ┐ │ 05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 06 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEE┌ Pane #2 ─────────────────────────────────────────────────┐ │ +07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEE┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 08 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ │ 09 (C): │ └─────────────────────────────│ │ │ 10 (C): │ │E│ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__five_new_floating_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__five_new_floating_panes.snap index a2cc23382b..ddb4f10029 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__five_new_floating_panes.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__five_new_floating_panes.snap @@ -1,18 +1,18 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 682 +assertion_line: 1028 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐ │ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐ │ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -04 (C): │ │E┌ Pane #6 ─────────────── SCROLL: 0/1 ┐ │ -05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────────────────────────────┐ │ +04 (C): │ │E┌ Pane #6 ───── SCROLL: 0/1 | PIN [ ] ┐ │ +05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│──────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ │ -07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│───────────────────────────────── SCROLL: 0/1 ┐ │ +07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 08 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -09 (C): │ └──────────────────────────────────────┘─────────────────────────────────── SCROLL: 0/1 ┐ │ +09 (C): │ └──────────────────────────────────────┘───────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 10 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 11 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 12 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__float_embedded_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__float_embedded_pane.snap index ada8f530fa..6fe9a3f709 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__float_embedded_pane.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__float_embedded_pane.snap @@ -1,14 +1,14 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 2386 expression: snapshot - --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__float_embedded_pane_without_pane_frames.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__float_embedded_pane_without_pane_frames.snap index c09b5e9f10..e8d81d2ac2 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__float_embedded_pane_without_pane_frames.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__float_embedded_pane_without_pane_frames.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1632 +assertion_line: 2445 expression: snapshot --- 00 (C): @@ -8,7 +8,7 @@ expression: snapshot 02 (C): 03 (C): 04 (C): -05 (C): ┌ Pane #2 ─────────────────────────────────────────────────┐ +05 (C): ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ 06 (C): │ │ 07 (C): │ │ 08 (C): │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_layout_with_plugins_and_commands_swaped_properly.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_layout_with_plugins_and_commands_swaped_properly.snap index 1d8dfe043e..e81573557d 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_layout_with_plugins_and_commands_swaped_properly.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_layout_with_plugins_and_commands_swaped_properly.snap @@ -1,9 +1,9 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5995 +assertion_line: 7510 expression: snapshot --- -00 (C): ┌ zellij:status-bar ───────────────────────────────────────┐ab-bar ──────────────────────────────────────────┐──────────┐ +00 (C): ┌ zellij:status-bar ────────────────────────────── PIN [ ] ┐ab-bar ───────────────────────────────── PIN [ ] ┐──────────┐ 01 (C): │I am a │b bar │ │ 02 (C): │status bar │ │ │ 03 (C): │ │ │ │ @@ -13,7 +13,7 @@ expression: snapshot 07 (C): │ │ │ │ 08 (C): │ │ │ │ 09 (C): └──────────────────────────────────────────────────────────┘─────────────────────────────────────────────────┘ │ -10 (C): ┌ command1 ───────────────────│ ┌ command2 ────────────────────────────────────────────────┐ │ +10 (C): ┌ command1 ───────────────────│ ┌ command2 ─────────────────────────────────────── PIN [ ] ┐ │ 11 (C): │ │ │ │ │ 12 (C): │ │ │ │ │ 13 (C): │ │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_pane_above_sixel_image.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_pane_above_sixel_image.snap index 19d6feb881..30cddfa491 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_pane_above_sixel_image.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_pane_above_sixel_image.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1343 +assertion_line: 2685 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────── SCROLL: 0/7 ┐ @@ -10,7 +10,7 @@ expression: snapshot 04 (C): │ixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixe │ 05 (C): │ixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixe │ 06 (C): │ixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixe │ -07 (C): │ixelSixelSixelSixelSixelSixelSixe┌ Pane #2 ─────────────────────────────────────────────────┐ │ +07 (C): │ixelSixelSixelSixelSixelSixelSixe┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 08 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │ 09 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │ 10 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_panes_persist_across_toggles.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_panes_persist_across_toggles.snap index dd632a954a..ec4350423b 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_panes_persist_across_toggles.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_panes_persist_across_toggles.snap @@ -1,14 +1,14 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 881 expression: snapshot - --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_next_pane_expands_stacked_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__focus_next_pane_expands_stacked_panes.snap index fec3d753e7..dcf4f40247 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 77530c7c38..5ce1e5583f 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 41100f1ee3..9d2ada2671 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__increase_floating_pane_size.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increase_floating_pane_size.snap index 30121d194c..934b5ccb36 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increase_floating_pane_size.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__increase_floating_pane_size.snap @@ -1,13 +1,13 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 1066 expression: snapshot - --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ 03 (C): │ │ -04 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────────┐ │ +04 (C): │ ┌ Pane #2 ──────────────────────────────────────────── PIN [ ] ┐ │ 05 (C): │ │ │ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__layout_with_plugins_and_commands_swaped_properly.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__layout_with_plugins_and_commands_swaped_properly.snap index 738ed813ad..1c5ae4cf86 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__mark_text_inside_floating_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__mark_text_inside_floating_pane.snap index 20e382fbae..c711393169 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__mark_text_inside_floating_pane.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__mark_text_inside_floating_pane.snap @@ -1,18 +1,18 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1318 +assertion_line: 2050 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐ │ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐ │ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -04 (C): │ │E┌ Pane #6 ─────────────── SCROLL: 0/1 ┐ │ -05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────────────────────────────┐ │ +04 (C): │ │E┌ Pane #6 ───── SCROLL: 0/1 | PIN [ ] ┐ │ +05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│──────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ │ -07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│───────────────────────────────── SCROLL: 0/1 ┐ │ +07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 08 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -09 (C): │ └──────────────────────────────────────┘─────────────────────────────────── SCROLL: 0/1 ┐ │ +09 (C): │ └──────────────────────────────────────┘───────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 10 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 11 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 12 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_down.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_down.snap index a401ba08a7..ecec0e6653 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_down.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_down.snap @@ -1,18 +1,18 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1078 +assertion_line: 1650 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐ │ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐ │ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -04 (C): │ │E┌ Pane #6 ─────────────── SCROLL: 0/1 ┐ │ -05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────────────────────────────┐ │ +04 (C): │ │E┌ Pane #6 ───── SCROLL: 0/1 | PIN [ ] ┐ │ +05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│──────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ │ -07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│───────────────────────────────── SCROLL: 0/1 ┐ │ +07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 08 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -09 (C): │ └──────────────────────────────────────┘─────────────────────────────────── SCROLL: 0/1 ┐ │ +09 (C): │ └──────────────────────────────────────┘───────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 10 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 11 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 12 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_left.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_left.snap index 98f623d783..38a5df4b21 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_left.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_left.snap @@ -1,18 +1,18 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 911 +assertion_line: 1363 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐ │ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐ │ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 04 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ ┐ │ -05 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│E│─────────────────────────────────────────────┐ │ +05 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│E│──────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│E│ │ │ -07 (C): │ └──────────────────────────────────────┘E│───────────────────────────────── SCROLL: 0/1 ┐ │ +07 (C): │ └──────────────────────────────────────┘E│─────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 08 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -09 (C): │ └──────────────────────────────────────┘─────────────────────────────────── SCROLL: 0/1 ┐ │ +09 (C): │ └──────────────────────────────────────┘───────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 10 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 11 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 12 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_right.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_right.snap index 67d7cfa4d5..1336cda693 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_right.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_right.snap @@ -1,18 +1,18 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 967 +assertion_line: 1459 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐ │ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐ │ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -04 (C): │ │E┌ Pane #6 ─────────────── SCROLL: 0/1 ┐ │ -05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────────────────────────────┐ │ +04 (C): │ │E┌ Pane #6 ───── SCROLL: 0/1 | PIN [ ] ┐ │ +05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│──────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ │ -07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│───────────────────────────────── SCROLL: 0/1 ┐ │ +07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 08 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -09 (C): │ └──────────────────────────────────────┘─────────────────────────────────── SCROLL: 0/1 ┐ │ +09 (C): │ └──────────────────────────────────────┘───────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 10 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 11 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 12 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_up.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_up.snap index 193834e883..61c4e323b5 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_up.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_up.snap @@ -1,18 +1,18 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1022 +assertion_line: 1554 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐ │ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐ │ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 04 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ ┐ │ -05 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│E│─────────────────────────────────────────────┐ │ +05 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│E│──────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│E│ │ │ -07 (C): │ └──────────────────────────────────────┘E│───────────────────────────────── SCROLL: 0/1 ┐ │ +07 (C): │ └──────────────────────────────────────┘E│─────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 08 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -09 (C): │ └──────────────────────────────────────┘─────────────────────────────────── SCROLL: 0/1 ┐ │ +09 (C): │ └──────────────────────────────────────┘───────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 10 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 11 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 12 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_with_mouse.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_with_mouse.snap index 2561b5ce1b..b9696dc085 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_with_mouse.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_focus_with_mouse.snap @@ -1,18 +1,18 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1136 +assertion_line: 1748 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐ │ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐ │ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -04 (C): │ │E┌ Pane #6 ─────────────── SCROLL: 0/1 ┐ │ -05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────────────────────────────┐ │ +04 (C): │ │E┌ Pane #6 ───── SCROLL: 0/1 | PIN [ ] ┐ │ +05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│──────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ │ -07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│───────────────────────────────── SCROLL: 0/1 ┐ │ +07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 08 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -09 (C): │ └─────────────────────────────┌ Pane #4 ─────────────────────────────────── SCROLL: 0/1 ┐ │ +09 (C): │ └─────────────────────────────┌ Pane #4 ───────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 10 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 11 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 12 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_with_sixel_image.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_with_sixel_image.snap index df091cdb62..8365df050b 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_with_sixel_image.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_with_sixel_image.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1312 +assertion_line: 2647 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -10,7 +10,7 @@ expression: snapshot 04 (C): │ │ 05 (C): │ │ 06 (C): │ │ -07 (C): │ ┌ Pane #2 ────────────────────────────────── SCROLL: 0/17 ┐ │ +07 (C): │ ┌ Pane #2 ──────────────────────── SCROLL: 0/17 | PIN [ ] ┐ │ 08 (C): │ │SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix│ │ 09 (C): │ │SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix│ │ 10 (C): │ │SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix│ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane.snap index dd632a954a..3220eee685 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane.snap @@ -1,14 +1,14 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 849 expression: snapshot - --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-2.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-2.snap index cdef481233..1394348af1 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-2.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout-2.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5799 +assertion_line: 8040 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,7 +8,7 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ────────────────────────────────────────────┐ ┌ Pane #3 ────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ─────────────────────────────────── PIN [ ] ┐ ┌ Pane #3 ─────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ │ │ 07 (C): │ │ │ │ │ │ 08 (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 b5c19c92eb..13848a2b20 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: 5799 +assertion_line: 8043 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -01 (C): │ ┌ Pane #3 ────────────────────────────────────────────┐ ┌ Pane #2 ────────────────────────────────────────────┐ │ +01 (C): │ ┌ Pane #2 ─────────────────────────────────── PIN [ ] ┐ ┌ Pane #3 ─────────────────────────────────── PIN [ ] ┐ │ 02 (C): │ │ │ │ │ │ 03 (C): │ │ │ │ │ │ 04 (C): │ │ │ │ │ │ @@ -14,7 +14,7 @@ expression: snapshot 08 (C): │ │ │ │ │ │ 09 (C): │ │ │ │ │ │ 10 (C): │ └─────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────┘ │ -11 (C): │ ┌ Pane #4 ────────────────────────────────────────────┐ │ +11 (C): │ ┌ Pane #4 ─────────────────────────────────── PIN [ ] ┐ │ 12 (C): │ │ │ │ 13 (C): │ │ │ │ 14 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout.snap index d6c8418576..675409f813 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__new_floating_pane_in_auto_layout.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5799 +assertion_line: 8040 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -13,7 +13,7 @@ expression: snapshot 07 (C): │ │ 08 (C): │ │ 09 (C): │ │ -10 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ +10 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ 11 (C): │ │ │ 12 (C): │ │ │ 13 (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 469f2b2665..2d9209ab62 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 caf0b98aa1..316e658732 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 8956fb0fb3..4df0ed53ed 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__rename_floating_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__rename_floating_pane.snap index cb73eb45cd..2e39065d21 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__rename_floating_pane.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__rename_floating_pane.snap @@ -1,5 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 2550 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -7,7 +8,7 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Renamed floating pane ───────────────────────────────────┐ │ +05 (C): │ ┌ Renamed floating pane ────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_down.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_down.snap index 3a38a93406..93b1596845 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_down.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_down.snap @@ -1,14 +1,14 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 1268 expression: snapshot - --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_left.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_left.snap index f5831eb8fc..1c186c17bc 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_left.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_left.snap @@ -1,14 +1,14 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 1145 expression: snapshot - --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ──────────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ───────────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_right.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_right.snap index 52dffcceda..0b1b0f9369 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_right.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_right.snap @@ -1,14 +1,14 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 1186 expression: snapshot - --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ──────────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ───────────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_up.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_up.snap index 6e4b9b6dbb..a4b8209553 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_up.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_floating_pane_up.snap @@ -1,12 +1,12 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 1227 expression: snapshot - --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ -03 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +03 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 04 (C): │ │ │ │ 05 (C): │ │ │ │ 06 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_tab_with_floating_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_tab_with_floating_panes.snap index da14ad29f6..b3e645b6a5 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_tab_with_floating_panes.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_tab_with_floating_panes.snap @@ -1,13 +1,13 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1544 +assertion_line: 2144 expression: snapshot --- -00 (C): ┌ Pane #1 ────────────────────┌ ┌ ┌ Pane #4 ─────────────────────────────────── SCROLL: 0/1 ┐─────┐ +00 (C): ┌ Pane #1 ────────────────────┌ ┌ ┌ Pane #4 ───────────────────────── SCROLL: 0/1 | PIN [ ] ┐─────┐ 01 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -04 (C): │ │E┌ Pane #6 ─────────────── SCROLL: 0/1 ┐EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ +04 (C): │ │E┌ Pane #6 ───── SCROLL: 0/1 | PIN [ ] ┐EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 06 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap index 2a886db750..dd07c8fcf7 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap @@ -1,9 +1,9 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 2220 +assertion_line: 2921 expression: snapshot --- -00 (C): ┌ Pane #1 ────────────────────┌ EDITING SCROLLBACK ──────────────────────────────────────┐─────────┐ +00 (C): ┌ Pane #1 ────────────────────┌ EDITING SCROLLBACK ───────────────────────────── PIN [ ] ┐─────────┐ 01 (C): │ │ │ │ 02 (C): │ │ │ │ 03 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__search_floating_tab_highlight_fring.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__search_floating_tab_highlight_fring.snap index fdb60046d6..62d2259482 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__search_floating_tab_highlight_fring.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__search_floating_tab_highlight_fring.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1721 +assertion_line: 3029 expression: snapshot --- 00 (C): @@ -8,7 +8,7 @@ expression: snapshot 02 (C): 03 (C): 04 (C): -05 (C): ┌ SEARCHING: fring ──────────────────────── SCROLL: 0/103 ┐ +05 (C): ┌ SEARCHING: fring ────────────── SCROLL: 0/103 | PIN [ ] ┐ 06 (C): │ │ 07 (C): │a mauris in aliquam sem fringilla. │ 08 (C): │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__search_floating_tab_nothing_highlighted.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__search_floating_tab_nothing_highlighted.snap index eeb3b4915a..0e0e7e6c72 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__search_floating_tab_nothing_highlighted.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__search_floating_tab_nothing_highlighted.snap @@ -1,5 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 3017 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -7,7 +8,7 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ fish /home/thomas/Projects/zellij ─────── SCROLL: 0/103 ┐ │ +05 (C): │ ┌ fish /home/thomas/Projects/zellij ────── 0/103 | PIN [ ] ┐ │ 06 (C): │ │d viverra tellus in hac habitasse. Nunc scelerisque viverr│ │ 07 (C): │ │a mauris in aliquam sem fringilla. │ │ 08 (C): │ │⏎ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically.snap index cfa37b7472..e8a854d5f0 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically.snap @@ -1,13 +1,13 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1594 +assertion_line: 2234 expression: snapshot --- 00 (C): ┌ Pane #1 ────────────────────┌ ┌ ┌ Pane #4 ── 0 ┐ 01 (C): │ │ │E│EEEEEEEEEEEEEE│ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐EEEEEEE│ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐EEEEEEE│ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -04 (C): │ │E┌ Pane #6 ─────────────── SCROLL: 0/1 ┐EEEEE│ +04 (C): │ │E┌ Pane #6 ───── SCROLL: 0/1 | PIN [ ] ┐EEEEE│ 05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEE│ 06 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEE│ 07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEE│ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_back.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_back.snap index a7c0f582de..3c187c2735 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_back.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_back.snap @@ -1,18 +1,18 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1648 +assertion_line: 2329 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ Pane #5 ─────────────── SCROLL: 0/1 ┐ │ +02 (C): │ ┌ Pane #5 ───── SCROLL: 0/1 | PIN [ ] ┐ │ 03 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -04 (C): │ │E┌ Pane #6 ─────────────── SCROLL: 0/1 ┐ │ -05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────────────────────────────┐ │ +04 (C): │ │E┌ Pane #6 ───── SCROLL: 0/1 | PIN [ ] ┐ │ +05 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│──────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ │ -07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│───────────────────────────────── SCROLL: 0/1 ┐ │ +07 (C): │ └─│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│─────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 08 (C): │ │EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ -09 (C): │ └──────────────────────────────────────┘─────────────────────────────────── SCROLL: 0/1 ┐ │ +09 (C): │ └──────────────────────────────────────┘───────────────────────── SCROLL: 0/1 | PIN [ ] ┐ │ 10 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 11 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 12 (C): │ │ │E│EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE│ │ 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 746d110e78..a19c592b86 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__suppress_floating_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__suppress_floating_pane.snap index 6ac3104482..1a6ae09514 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__suppress_floating_pane.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__suppress_floating_pane.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 1639 +assertion_line: 2738 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,7 +8,7 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ EDITING SCROLLBACK ──────────────────────────────────────┐ │ +05 (C): │ ┌ EDITING SCROLLBACK ───────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_command_panes_absent_from_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_command_panes_absent_from_existing_layout.snap index fb7d917617..5dc4503b11 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_command_panes_absent_from_existing_layout.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_command_panes_absent_from_existing_layout.snap @@ -1,18 +1,18 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 6180 +assertion_line: 7697 expression: snapshot --- -00 (C): ┌ Pane #2 ─────────────────────────────────────────────────┐────────────────────────────────────────────────────────────┐ +00 (C): ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐────────────────────────────────────────────────────────────┐ 01 (C): │ │ │ 02 (C): │ │ │ 03 (C): │ │ │ 04 (C): │ │ │ -05 (C): │ ┌ zellij:status-bar ───────────────────────────────────────┐ │ +05 (C): │ ┌ zellij:status-bar ────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │I am a │ │ -07 (C): │ │status bar │─┐ │ +07 (C): │ │status bar │ ┐ │ 08 (C): │ │ │ │ │ -09 (C): └─────────────────────────────│ │───┐ │ +09 (C): └─────────────────────────────│ │ ] ┐ │ 10 (C): │ ┌ Pane #3 ──────────│ │ │ │ 11 (C): │ │ │ │ │ │ 12 (C): │ │ │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_plugin_panes_absent_from_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_plugin_panes_absent_from_existing_layout.snap index 2f06d9318e..ab242bad1e 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_plugin_panes_absent_from_existing_layout.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_including_plugin_panes_absent_from_existing_layout.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5672 +assertion_line: 7864 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,11 +8,11 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ -07 (C): │ │ ┌ Pane #3 ─────────────────────────────────────────────────┐ │ +07 (C): │ │ ┌ Pane #3 ──────────────────────────────────────── PIN [ ] ┐ │ 08 (C): │ │ │ │ │ -09 (C): │ │ │ ┌ Pane #4 ─────────────────────────────────────────────────┐ │ +09 (C): │ │ │ ┌ Pane #4 ──────────────────────────────────────── PIN [ ] ┐ │ 10 (C): │ │ │ │ │ │ 11 (C): │ │ │ │ │ │ 12 (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 01d107cde0..9c36e7964b 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,24 +1,24 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 6275 +assertion_line: 7796 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ command2 ────────────── SCROLL: 0/1 ┐ │ +02 (C): │ ┌ command2 ──── SCROLL: 0/1 | PIN [ ] ┐ │ 03 (C): │ │ Waiting to run: command2 │ │ -04 (C): │ │ ┌ zellij:tab-bar ──────────────────────┐ │ -05 (C): │ │<│I am a tab bar ┌ zellij:status-bar ───────────────────────────────────────┐ │ +04 (C): │ │ ┌ zellij:tab-bar ───────────── PIN [ ] ┐ │ +05 (C): │ │<│I am a tab bar ┌ zellij:status-bar ────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │l│ │I am a │ │ -07 (C): │ └─│ │status bar │─┐ │ +07 (C): │ └─│ │status bar │ ┐ │ 08 (C): │ │ │ │ │ │ -09 (C): │ └─────────────────────────│ │───┐ │ +09 (C): │ └─────────────────────────│ │ ] ┐ │ 10 (C): │ │ │ │ │ 11 (C): │ │ │ │ │ 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_floating_layouts_not_including_plugin_panes_present_in_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_plugin_panes_present_in_existing_layout.snap index bb542c19f8..63deedf006 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_plugin_panes_present_in_existing_layout.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_floating_layouts_not_including_plugin_panes_present_in_existing_layout.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 6432 +assertion_line: 7952 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,11 +8,11 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ zellij:tab-bar ──────────────────────────────────────────┐ │ +05 (C): │ ┌ zellij:tab-bar ───────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │I am a tab bar │ │ -07 (C): │ │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +07 (C): │ │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 08 (C): │ │ │ │ │ -09 (C): │ │ │ ┌ zellij:status-bar ───────────────────────────────────────┐ │ +09 (C): │ │ │ ┌ zellij:status-bar ────────────────────────────── PIN [ ] ┐ │ 10 (C): │ │ │ │I am a │ │ 11 (C): │ │ │ │status bar │ │ 12 (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 5b7bd24e0a..c0f8de17c7 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 3ec04981a3..29e05b285d 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 9a5f486727..48031c36cc 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_layout_that_has_floating_panes.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_layout_that_has_floating_panes.snap index 6816fcb8b5..ba51ae683b 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_layout_that_has_floating_panes.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__tab_with_layout_that_has_floating_panes.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 2560 +assertion_line: 3335 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,9 +8,9 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ -07 (C): │ │ ┌ Pane #3 ─────────────────────────────────────────────────┐ │ +07 (C): │ │ ┌ Pane #3 ──────────────────────────────────────── PIN [ ] ┐ │ 08 (C): │ │ │ │ │ 09 (C): │ │ │ │ │ 10 (C): │ │ │ │ │ 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 2d185efe2e..a8a050a3a5 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 6ac556ba9e..20fa9ad2e1 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__toggle_floating_panes_on.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__toggle_floating_panes_on.snap index dd632a954a..bc92cb94ce 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__toggle_floating_panes_on.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__toggle_floating_panes_on.snap @@ -1,14 +1,14 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 940 expression: snapshot - --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_floating_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_floating_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap index 331e678b4b..bff48b7327 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_floating_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_closing_a_floating_pane_in_auto_layout_the_focus_goes_to_last_focused_pane.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 6028 +assertion_line: 8340 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,9 +8,9 @@ expression: snapshot 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ Pane #3 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #3 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ -07 (C): │ │ │─┐ │ +07 (C): │ │ │ ┐ │ 08 (C): │ │ │ │ │ 09 (C): │ │ │ │ │ 10 (C): │ │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_resizing_whole_tab_with_auto_layout_and_floating_panes_the_layout_is_maintained.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_resizing_whole_tab_with_auto_layout_and_floating_panes_the_layout_is_maintained.snap index 26bcb978cd..c410513d54 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_resizing_whole_tab_with_auto_layout_and_floating_panes_the_layout_is_maintained.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_resizing_whole_tab_with_auto_layout_and_floating_panes_the_layout_is_maintained.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 6079 +assertion_line: 8408 expression: snapshot --- 00 (C): ┌ Pane #1 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -11,11 +11,11 @@ expression: snapshot 05 (C): │ │ 06 (C): │ │ 07 (C): │ │ -08 (C): │ ┌ Pane #2 ────────────────────────────────────────────────────────────────┐ │ +08 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────────── PIN [ ] ┐ │ 09 (C): │ │ │ │ -10 (C): │ │ ┌ Pane #3 ────────────────────────────────────────────────────────────────┐ │ +10 (C): │ │ ┌ Pane #3 ─────────────────────────────────────────────────────── PIN [ ] ┐ │ 11 (C): │ │ │ │ │ -12 (C): │ │ │ ┌ Pane #4 ────────────────────────────────────────────────────────────────┐ │ +12 (C): │ │ │ ┌ Pane #4 ─────────────────────────────────────────────────────── PIN [ ] ┐ │ 13 (C): │ │ │ │ │ │ 14 (C): │ │ │ │ │ │ 15 (C): │ │ │ │ │ │ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap index 985cb31727..ae98ca35fd 100644 --- a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap +++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__when_swapping_floating_layouts_in_a_damaged_state_layout_and_pane_focus_are_unchanged.snap @@ -1,16 +1,16 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5859 +assertion_line: 8119 expression: snapshot --- -00 (C): ┌ Pane #2 ─────────────────────────────────────────────────┐────────────────────────────────────────────────────────────┐ +00 (C): ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐────────────────────────────────────────────────────────────┐ 01 (C): │ │ │ 02 (C): │ │ │ 03 (C): │ │ │ 04 (C): │ │ │ -05 (C): │ ┌ Pane #3 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #3 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ -07 (C): │ │ ┌ Pane #4 ─────────────────────────────────────────────────┐ │ +07 (C): │ │ ┌ Pane #4 ──────────────────────────────────────── PIN [ ] ┐ │ 08 (C): │ │ │ │ │ 09 (C): └─────────────────────────────│ │ │ │ 10 (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 c42856cde6..e780fafa0b 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: 5915 +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 ─────────────────────────────────────────────────┐ │ +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 36c93e277f..812d985e87 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: 5970 +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 ─────────────────────────────────────────────────┐ │ +05 (C): │ ┌ Pane #2 ──────────────────────────────────────── PIN [ ] ┐ │ 06 (C): │ │ │ │ -07 (C): │ │ │─┐ │ -08 (C): │ │ │ │ │ -09 (C): │ │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │ -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 ba1a4e3ffc..af7ba0281b 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 d5f3337738..4841269b6c 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 fa937eae38..76b4474b29 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 b664910f14..438046fdeb 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/ui/components/text.rs b/zellij-server/src/ui/components/text.rs index b7f95aa036..2173f72f4c 100644 --- a/zellij-server/src/ui/components/text.rs +++ b/zellij-server/src/ui/components/text.rs @@ -65,6 +65,25 @@ pub fn stringify_text( stringified.push(character); } } + let coordinates_width = coordinates.as_ref().and_then(|c| c.width); + match (coordinates_width, text_style.background) { + (Some(coordinates_width), Some(_background_style)) => { + let text_width_with_left_padding = text_width + left_padding.unwrap_or(0); + let background_padding_length = + coordinates_width.saturating_sub(text_width_with_left_padding); + if text_width_with_left_padding < coordinates_width { + // here we pad the string with whitespace until the end so that the background + // style will apply the whole length of the coordinates + stringified.push_str(&format!( + "{:width$}", + " ", + width = background_padding_length + )); + } + text_width += background_padding_length; + }, + _ => {}, + } (stringified, text_width) } diff --git a/zellij-server/src/ui/pane_boundaries_frame.rs b/zellij-server/src/ui/pane_boundaries_frame.rs index 57cff1ce42..c3884fbf7c 100644 --- a/zellij-server/src/ui/pane_boundaries_frame.rs +++ b/zellij-server/src/ui/pane_boundaries_frame.rs @@ -5,6 +5,7 @@ use crate::ClientId; use zellij_utils::data::{client_id_to_colors, PaletteColor, Style}; use zellij_utils::errors::prelude::*; use zellij_utils::pane_size::Viewport; +use zellij_utils::position::Position; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; @@ -60,6 +61,7 @@ pub struct FrameParams { pub pane_is_stacked_under: bool, pub pane_is_stacked_over: bool, pub should_draw_pane_frames: bool, + pub pane_is_floating: bool, } #[derive(Default, PartialEq)] @@ -78,6 +80,8 @@ pub struct PaneFrame { pane_is_stacked_over: bool, pane_is_stacked_under: bool, should_draw_pane_frames: bool, + is_pinned: bool, + is_floating: bool, } impl PaneFrame { @@ -102,8 +106,14 @@ impl PaneFrame { pane_is_stacked_over: frame_params.pane_is_stacked_over, pane_is_stacked_under: frame_params.pane_is_stacked_under, should_draw_pane_frames: frame_params.should_draw_pane_frames, + is_pinned: false, + is_floating: frame_params.pane_is_floating, } } + pub fn is_pinned(mut self, is_pinned: bool) -> Self { + self.is_pinned = is_pinned; + self + } pub fn add_exit_status(&mut self, exit_status: Option) { self.exit_status = match exit_status { Some(exit_status) => Some(ExitStatus::Code(exit_status)), @@ -149,32 +159,80 @@ impl PaneFrame { max_length: usize, ) -> Option<(Vec, usize)> { // string and length because of color - if self.scroll_position.0 > 0 || self.scroll_position.1 > 0 { - let prefix = " SCROLL: "; - let full_indication = - format!(" {}/{} ", self.scroll_position.0, self.scroll_position.1); - let short_indication = format!(" {} ", self.scroll_position.0); - let full_indication_len = full_indication.chars().count(); - let short_indication_len = short_indication.chars().count(); - let prefix_len = prefix.chars().count(); - if prefix_len + full_indication_len <= max_length { - Some(( - foreground_color(&format!("{}{}", prefix, full_indication), self.color), - prefix_len + full_indication_len, - )) - } else if full_indication_len <= max_length { - Some(( - foreground_color(&full_indication, self.color), - full_indication_len, - )) - } else if short_indication_len <= max_length { - Some(( - foreground_color(&short_indication, self.color), - short_indication_len, - )) + let has_scroll = self.scroll_position.0 > 0 || self.scroll_position.1 > 0; + if has_scroll { + let pin_indication = if self.is_floating { + self.render_pinned_indication(max_length) } else { None + }; // no pin indication for tiled panes + let space_for_scroll_indication = pin_indication + .as_ref() + .map(|(_, length)| max_length.saturating_sub(*length + 1)) + .unwrap_or(max_length); + let scroll_indication = self.render_scroll_indication(space_for_scroll_indication); + match (pin_indication, scroll_indication) { + ( + Some((mut pin_indication, pin_indication_len)), + Some((mut scroll_indication, scroll_indication_len)), + ) => { + let mut characters: Vec<_> = scroll_indication.drain(..).collect(); + let mut separator = foreground_color(&format!("|"), self.color); + characters.append(&mut separator); + characters.append(&mut pin_indication); + Some((characters, pin_indication_len + scroll_indication_len + 1)) + }, + (Some(pin_indication), None) => Some(pin_indication), + (None, Some(scroll_indication)) => Some(scroll_indication), + _ => None, } + } else if self.is_floating { + self.render_pinned_indication(max_length) + } else { + None + } + } + fn render_scroll_indication( + &self, + max_length: usize, + ) -> Option<(Vec, usize)> { + let prefix = " SCROLL: "; + let full_indication = format!(" {}/{} ", self.scroll_position.0, self.scroll_position.1); + let short_indication = format!(" {} ", self.scroll_position.0); + let full_indication_len = full_indication.chars().count(); + let short_indication_len = short_indication.chars().count(); + let prefix_len = prefix.chars().count(); + if prefix_len + full_indication_len <= max_length { + Some(( + foreground_color(&format!("{}{}", prefix, full_indication), self.color), + prefix_len + full_indication_len, + )) + } else if full_indication_len <= max_length { + Some(( + foreground_color(&full_indication, self.color), + full_indication_len, + )) + } else if short_indication_len <= max_length { + Some(( + foreground_color(&short_indication, self.color), + short_indication_len, + )) + } else { + None + } + } + fn render_pinned_indication( + &self, + max_length: usize, + ) -> Option<(Vec, usize)> { + let is_checked = if self.is_pinned { '+' } else { ' ' }; + let full_indication = format!(" PIN [{}] ", is_checked); + let full_indication_len = full_indication.chars().count(); + if full_indication_len <= max_length { + Some(( + foreground_color(&full_indication, self.color), + full_indication_len, + )) } else { None } @@ -694,6 +752,22 @@ impl PaneFrame { }; Ok(res) } + pub fn clicked_on_pinned(&mut self, position: Position) -> bool { + if self.is_floating { + // TODO: this is not entirely accurate because our relative position calculation in + // itself isn't - when that is fixed, we should adjust this as well + let checkbox_center_position = self.geom.cols.saturating_sub(5); + let checkbox_position_start = checkbox_center_position.saturating_sub(1); + let checkbox_position_end = checkbox_center_position + 1; + if position.line() == -1 + && (position.column() >= checkbox_position_start + && position.column() <= checkbox_position_end) + { + return true; + } + } + false + } pub fn render(&self) -> Result<(Vec, Option)> { let err_context = || "failed to render pane frame"; let mut character_chunks = vec![]; diff --git a/zellij-server/src/ui/pane_contents_and_ui.rs b/zellij-server/src/ui/pane_contents_and_ui.rs index 72f0b80499..b2ed6383c4 100644 --- a/zellij-server/src/ui/pane_contents_and_ui.rs +++ b/zellij-server/src/ui/pane_contents_and_ui.rs @@ -57,6 +57,10 @@ impl<'a> PaneContentsAndUi<'a> { ) -> Result<()> { let err_context = "failed to render pane contents to multiple clients"; + // here we drop the fake cursors so that their lines will be updated + // and we can clear them from the UI below + drop(self.pane.drain_fake_cursors()); + if let Some((character_chunks, raw_vte_output, sixel_image_chunks)) = self.pane.render(None).context(err_context)? { @@ -136,16 +140,26 @@ impl<'a> PaneContentsAndUi<'a> { format!("failed to render fake cursor if needed for client {client_id}") })?; if let Some(colors) = client_id_to_colors(*fake_cursor_client_id, self.style.colors) { - if let Some(vte_output) = self.pane.render_fake_cursor(colors.0, colors.1) { - self.output.add_post_vte_instruction_to_client( - client_id, - &format!( - "\u{1b}[{};{}H\u{1b}[m{}", - self.pane.y() + 1, - self.pane.x() + 1, - vte_output - ), - ); + let cursor_is_visible = self + .pane + .cursor_coordinates() + .map(|(x, y)| { + self.output + .cursor_is_visible(self.pane.x() + x, self.pane.y() + y) + }) + .unwrap_or(false); + if cursor_is_visible { + if let Some(vte_output) = self.pane.render_fake_cursor(colors.0, colors.1) { + self.output.add_post_vte_instruction_to_client( + client_id, + &format!( + "\u{1b}[{};{}H\u{1b}[m{}", + self.pane.y() + 1, + self.pane.x() + 1, + vte_output + ), + ); + } } } } @@ -175,6 +189,7 @@ impl<'a> PaneContentsAndUi<'a> { client_id: ClientId, client_mode: InputMode, session_is_mirrored: bool, + pane_is_floating: bool, ) -> Result<()> { let err_context = || format!("failed to render pane frame for client {client_id}"); @@ -206,6 +221,7 @@ impl<'a> PaneContentsAndUi<'a> { pane_is_stacked_over: self.pane_is_stacked_over, pane_is_stacked_under: self.pane_is_stacked_under, should_draw_pane_frames: self.should_draw_pane_frames, + pane_is_floating, } } else { FrameParams { @@ -218,6 +234,7 @@ impl<'a> PaneContentsAndUi<'a> { pane_is_stacked_over: self.pane_is_stacked_over, pane_is_stacked_under: self.pane_is_stacked_under, should_draw_pane_frames: self.should_draw_pane_frames, + pane_is_floating, } }; diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index c536fe3107..d4b9e91681 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -1328,6 +1328,7 @@ fn open_new_floating_pane_with_custom_coordinates() { y: Some(SplitSize::Fixed(5)), width: Some(SplitSize::Percent(1)), height: Some(SplitSize::Fixed(2)), + pinned: None, }), false, Some(1), @@ -1362,6 +1363,7 @@ fn open_new_floating_pane_with_custom_coordinates_exceeding_viewport() { y: Some(SplitSize::Fixed(21)), width: Some(SplitSize::Fixed(10)), height: Some(SplitSize::Fixed(10)), + pinned: None, }), false, Some(1), @@ -2229,6 +2231,7 @@ pub fn send_cli_new_pane_action_with_default_parameters() { y: None, width: None, height: None, + pinned: None, }; 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 @@ -2272,6 +2275,7 @@ pub fn send_cli_new_pane_action_with_split_direction() { y: None, width: None, height: None, + pinned: None, }; 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 @@ -2315,11 +2319,23 @@ pub fn send_cli_new_pane_action_with_command_and_cwd() { y: None, width: None, height: None, + pinned: None, }; 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] @@ -2358,6 +2374,7 @@ pub fn send_cli_new_pane_action_with_floating_pane_and_coordinates() { y: None, width: Some("20%".to_owned()), height: None, + pinned: None, }; 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 @@ -2396,6 +2413,7 @@ pub fn send_cli_edit_action_with_default_parameters() { y: None, width: None, height: None, + pinned: None, }; send_cli_action_to_server(&session_metadata, cli_edit_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be @@ -2434,6 +2452,7 @@ pub fn send_cli_edit_action_with_line_number() { y: None, width: None, height: None, + pinned: None, }; send_cli_action_to_server(&session_metadata, cli_edit_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be @@ -2472,6 +2491,7 @@ pub fn send_cli_edit_action_with_split_direction() { y: None, width: None, height: None, + pinned: None, }; send_cli_action_to_server(&session_metadata, cli_edit_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be @@ -3627,3 +3647,43 @@ pub fn screen_can_move_pane_to_a_new_tab_left() { } assert_snapshot!(format!("{}", snapshot_count)); } + +#[test] +pub fn send_cli_stack_panes_action() { + let size = Size { cols: 80, rows: 10 }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut initial_layout = TiledPaneLayout::default(); + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![ + TiledPaneLayout::default(), + TiledPaneLayout::default(), + TiledPaneLayout::default(), + TiledPaneLayout::default(), + TiledPaneLayout::default(), + ]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(initial_layout), vec![]); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_thread = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let stack_panes_action = CliAction::StackPanes { + pane_ids: vec!["1".to_owned(), "2".to_owned(), "3".to_owned()], + }; + send_cli_action_to_server(&session_metadata, stack_panes_action, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_thread, screen_thread]); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + for (_cursor_coordinates, snapshot) in snapshots { + assert_snapshot!(format!("{}", snapshot)); + } + assert_snapshot!(format!("{}", snapshot_count)); +} diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab-2.snap index e5dd722dbc..c4170f548e 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab-2.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab-2.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 3374 +assertion_line: 3395 expression: "format!(\"{}\", snapshot)" --- 00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ @@ -8,7 +8,7 @@ expression: "format!(\"{}\", snapshot)" 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ floating_pane_to_eject ──────────────┐ │ +05 (C): │ ┌ floating_pane_to_eject ───── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab-4.snap index e5dd722dbc..c4170f548e 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab-4.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab-4.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 3374 +assertion_line: 3395 expression: "format!(\"{}\", snapshot)" --- 00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ @@ -8,7 +8,7 @@ expression: "format!(\"{}\", snapshot)" 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ floating_pane_to_eject ──────────────┐ │ +05 (C): │ ┌ floating_pane_to_eject ───── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab.snap index 8460af7b0b..a87d458831 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__screen_can_break_floating_pane_to_a_new_tab.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2849 +assertion_line: 3395 expression: "format!(\"{}\", snapshot)" --- 00 (C): ┌ tiled_pane ──────────────────────────────────────────────────────────────────┐ @@ -8,7 +8,7 @@ expression: "format!(\"{}\", snapshot)" 02 (C): │ │ 03 (C): │ │ 04 (C): │ │ -05 (C): │ ┌ floating_pane_to_eject ──────────────┐ │ +05 (C): │ ┌ floating_pane_to_eject ───── PIN [ ] ┐ │ 06 (C): │ │ │ │ 07 (C): │ │ │ │ 08 (C): │ │ │ │ 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 593dd95bd6..112a570578 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 e9f22eb300..8a3cfe4273 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 0f9b59e15b..5704230128 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_new_pane_action_with_floating_pane_and_coordinates.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_floating_pane_and_coordinates.snap index be12965c31..06cf752bc8 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_floating_pane_and_coordinates.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_floating_pane_and_coordinates.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2351 +assertion_line: 2371 expression: "format!(\"{:?}\", * received_pty_instructions.lock().unwrap())" --- -[SpawnTerminal(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None })), Some(true), None, Some(FloatingPaneCoordinates { x: Some(Fixed(10)), y: None, width: Some(Percent(20)), height: None }), false, ClientId(10)), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] +[SpawnTerminal(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None })), Some(true), None, Some(FloatingPaneCoordinates { x: Some(Fixed(10)), y: None, width: Some(Percent(20)), height: None, pinned: None }), false, ClientId(10)), UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), Exit] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_stack_panes_action-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_stack_panes_action-2.snap new file mode 100644 index 0000000000..c26d308fc3 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_stack_panes_action-2.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 3687 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────┐┌ Pane #2 ─────────────────────────────────────┐┌ Pane #5 ─────┐ +01 (C): │ │┌ Pane #3 ─────────────────────────────────────┐│ │ +02 (C): │ │┌ Pane #4 ─────────────────────────────────────┐│ │ +03 (C): │ ││ ││ │ +04 (C): │ ││ ││ │ +05 (C): │ ││ ││ │ +06 (C): │ ││ ││ │ +07 (C): │ ││ ││ │ +08 (C): │ ││ ││ │ +09 (C): └──────────────┘└──────────────────────────────────────────────┘└──────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_stack_panes_action-3.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_stack_panes_action-3.snap new file mode 100644 index 0000000000..6329f4de80 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_stack_panes_action-3.snap @@ -0,0 +1,6 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 3689 +expression: "format!(\"{}\", snapshot_count)" +--- +2 diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_stack_panes_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_stack_panes_action.snap new file mode 100644 index 0000000000..8b57c65869 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_stack_panes_action.snap @@ -0,0 +1,16 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 3687 +expression: "format!(\"{}\", snapshot)" +--- +00 (C): ┌ Pane #1 ─────┐┌ Pane #2 ─────┐┌ Pane #3 ─────┐┌ Pane #4 ─────┐┌ Pane #5 ─────┐ +01 (C): │ ││ ││ ││ ││ │ +02 (C): │ ││ ││ ││ ││ │ +03 (C): │ ││ ││ ││ ││ │ +04 (C): │ ││ ││ ││ ││ │ +05 (C): │ ││ ││ ││ ││ │ +06 (C): │ ││ ││ ││ ││ │ +07 (C): │ ││ ││ ││ ││ │ +08 (C): │ ││ ││ ││ ││ │ +09 (C): └──────────────┘└──────────────┘└──────────────┘└──────────────┘└──────────────┘ + diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-2.snap index e9727e3952..0eaddd5774 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-2.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-2.snap @@ -1,12 +1,12 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2186 +assertion_line: 2609 expression: "format!(\"{}\", snapshot)" --- 00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ -03 (C): │ ┌ Pane #1 ─────────────────────────────┐ │ +03 (C): │ ┌ Pane #1 ──────────────────── PIN [ ] ┐ │ 04 (C): │ │ │ │ 05 (C): │ │ │ │ 06 (C): │ │ │ │ diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-4.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-4.snap index e9727e3952..0eaddd5774 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-4.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_floating_panes-4.snap @@ -1,12 +1,12 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2186 +assertion_line: 2609 expression: "format!(\"{}\", snapshot)" --- 00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ -03 (C): │ ┌ Pane #1 ─────────────────────────────┐ │ +03 (C): │ ┌ Pane #1 ──────────────────── PIN [ ] ┐ │ 04 (C): │ │ │ │ 05 (C): │ │ │ │ 06 (C): │ │ │ │ diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-2.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-2.snap index a6119cc824..ca19a162a7 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-2.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_toggle_pane_embed_or_float-2.snap @@ -1,12 +1,12 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2131 +assertion_line: 2569 expression: "format!(\"{}\", snapshot)" --- 00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ 02 (C): │ │ -03 (C): │ ┌ Pane #1 ─────────────────────────────┐ │ +03 (C): │ ┌ Pane #1 ──────────────────── PIN [ ] ┐ │ 04 (C): │ │ │ │ 05 (C): │ │ │ │ 06 (C): │ │ │ │ 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 b612c67126..f2bcd76f92 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-tile/src/shim.rs b/zellij-tile/src/shim.rs index bc1b4844b1..5a97a44295 100644 --- a/zellij-tile/src/shim.rs +++ b/zellij-tile/src/shim.rs @@ -1128,6 +1128,27 @@ pub fn rebind_keys( unsafe { host_run_plugin_command() }; } +pub fn change_host_folder(new_host_folder: PathBuf) { + let plugin_command = PluginCommand::ChangeHostFolder(new_host_folder); + let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); + object_to_stdout(&protobuf_plugin_command.encode_to_vec()); + unsafe { host_run_plugin_command() }; +} + +pub fn set_floating_pane_pinned(pane_id: PaneId, should_be_pinned: bool) { + let plugin_command = PluginCommand::SetFloatingPanePinned(pane_id, should_be_pinned); + let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); + object_to_stdout(&protobuf_plugin_command.encode_to_vec()); + unsafe { host_run_plugin_command() }; +} + +pub fn stack_panes(pane_ids: Vec) { + let plugin_command = PluginCommand::StackPanes(pane_ids); + let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); + object_to_stdout(&protobuf_plugin_command.encode_to_vec()); + unsafe { host_run_plugin_command() }; +} + // Utility Functions #[allow(unused)] diff --git a/zellij-utils/assets/config/default.kdl b/zellij-utils/assets/config/default.kdl index e7dfcf5da9..15f1fd54a5 100644 --- a/zellij-utils/assets/config/default.kdl +++ b/zellij-utils/assets/config/default.kdl @@ -36,6 +36,7 @@ keybinds { bind "w" { ToggleFloatingPanes; SwitchToMode "Normal"; } bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "Normal"; } bind "c" { SwitchToMode "RenamePane"; PaneNameInput 0;} + bind "i" { TogglePanePinned; SwitchToMode "Normal"; } } move { bind "Ctrl h" { SwitchToMode "Normal"; } diff --git a/zellij-utils/assets/layouts/classic.swap.kdl b/zellij-utils/assets/layouts/classic.swap.kdl index ae1091cb2c..85fcb39858 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 300b4bdf71..6045e12b73 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 27475819b6..c983fb4756 100644 --- a/zellij-utils/assets/layouts/default.swap.kdl +++ b/zellij-utils/assets/layouts/default.swap.kdl @@ -31,7 +31,7 @@ swap_tiled_layout name="vertical" { } swap_tiled_layout name="horizontal" { - ui max_panes=5 { + ui max_panes=4 { pane pane } @@ -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/assets/prost/api.action.rs b/zellij-utils/assets/prost/api.action.rs index 651f59ebe7..87ca37dd4c 100644 --- a/zellij-utils/assets/prost/api.action.rs +++ b/zellij-utils/assets/prost/api.action.rs @@ -455,6 +455,7 @@ pub enum ActionName { CliPipe = 82, MoveTab = 83, KeybindPipe = 84, + TogglePanePinned = 85, } impl ActionName { /// String value of the enum field names used in the ProtoBuf definition. @@ -548,6 +549,7 @@ impl ActionName { ActionName::CliPipe => "CliPipe", ActionName::MoveTab => "MoveTab", ActionName::KeybindPipe => "KeybindPipe", + ActionName::TogglePanePinned => "TogglePanePinned", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -638,6 +640,7 @@ impl ActionName { "CliPipe" => Some(Self::CliPipe), "MoveTab" => Some(Self::MoveTab), "KeybindPipe" => Some(Self::KeybindPipe), + "TogglePanePinned" => Some(Self::TogglePanePinned), _ => None, } } diff --git a/zellij-utils/assets/prost/api.event.rs b/zellij-utils/assets/prost/api.event.rs index 02d709e64e..b6572a4156 100644 --- a/zellij-utils/assets/prost/api.event.rs +++ b/zellij-utils/assets/prost/api.event.rs @@ -11,7 +11,7 @@ pub struct Event { pub name: i32, #[prost( oneof = "event::Payload", - tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23" + tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25" )] pub payload: ::core::option::Option, } @@ -64,10 +64,26 @@ pub mod event { FailedToWriteConfigToDiskPayload(super::FailedToWriteConfigToDiskPayload), #[prost(message, tag = "23")] ListClientsPayload(super::ListClientsPayload), + #[prost(message, tag = "24")] + HostFolderChangedPayload(super::HostFolderChangedPayload), + #[prost(message, tag = "25")] + FailedToChangeHostFolderPayload(super::FailedToChangeHostFolderPayload), } } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct FailedToChangeHostFolderPayload { + #[prost(string, optional, tag = "1")] + pub error_message: ::core::option::Option<::prost::alloc::string::String>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HostFolderChangedPayload { + #[prost(string, tag = "1")] + pub new_host_folder_path: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct ListClientsPayload { #[prost(message, repeated, tag = "1")] pub client_info: ::prost::alloc::vec::Vec, @@ -468,6 +484,8 @@ pub enum EventType { CommandPaneReRun = 24, FailedToWriteConfigToDisk = 25, ListClients = 26, + HostFolderChanged = 27, + FailedToChangeHostFolder = 28, } impl EventType { /// String value of the enum field names used in the ProtoBuf definition. @@ -503,6 +521,8 @@ impl EventType { EventType::CommandPaneReRun => "CommandPaneReRun", EventType::FailedToWriteConfigToDisk => "FailedToWriteConfigToDisk", EventType::ListClients => "ListClients", + EventType::HostFolderChanged => "HostFolderChanged", + EventType::FailedToChangeHostFolder => "FailedToChangeHostFolder", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -535,6 +555,8 @@ impl EventType { "CommandPaneReRun" => Some(Self::CommandPaneReRun), "FailedToWriteConfigToDisk" => Some(Self::FailedToWriteConfigToDisk), "ListClients" => Some(Self::ListClients), + "HostFolderChanged" => Some(Self::HostFolderChanged), + "FailedToChangeHostFolder" => Some(Self::FailedToChangeHostFolder), _ => None, } } diff --git a/zellij-utils/assets/prost/api.plugin_command.rs b/zellij-utils/assets/prost/api.plugin_command.rs index 8b3b6752eb..ac5d2c9649 100644 --- a/zellij-utils/assets/prost/api.plugin_command.rs +++ b/zellij-utils/assets/prost/api.plugin_command.rs @@ -5,7 +5,7 @@ pub struct PluginCommand { pub name: i32, #[prost( oneof = "plugin_command::Payload", - tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88" + tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91" )] pub payload: ::core::option::Option, } @@ -174,10 +174,36 @@ pub mod plugin_command { LoadNewPluginPayload(super::LoadNewPluginPayload), #[prost(message, tag = "88")] RebindKeysPayload(super::RebindKeysPayload), + #[prost(message, tag = "89")] + ChangeHostFolderPayload(super::ChangeHostFolderPayload), + #[prost(message, tag = "90")] + SetFloatingPanePinnedPayload(super::SetFloatingPanePinnedPayload), + #[prost(message, tag = "91")] + StackPanesPayload(super::StackPanesPayload), } } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct StackPanesPayload { + #[prost(message, repeated, tag = "1")] + pub pane_ids: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SetFloatingPanePinnedPayload { + #[prost(message, optional, tag = "1")] + pub pane_id: ::core::option::Option, + #[prost(bool, tag = "2")] + pub should_be_pinned: bool, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ChangeHostFolderPayload { + #[prost(string, tag = "1")] + pub new_host_folder: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct RebindKeysPayload { #[prost(message, repeated, tag = "1")] pub keys_to_rebind: ::prost::alloc::vec::Vec, @@ -590,6 +616,8 @@ pub struct FloatingPaneCoordinates { pub width: ::core::option::Option, #[prost(message, optional, tag = "4")] pub height: ::core::option::Option, + #[prost(bool, optional, tag = "5")] + pub pinned: ::core::option::Option, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -716,6 +744,9 @@ pub enum CommandName { LoadNewPlugin = 111, RebindKeys = 112, ListClients = 113, + ChangeHostFolder = 114, + SetFloatingPanePinned = 115, + StackPanes = 116, } impl CommandName { /// String value of the enum field names used in the ProtoBuf definition. @@ -840,6 +871,9 @@ impl CommandName { CommandName::LoadNewPlugin => "LoadNewPlugin", CommandName::RebindKeys => "RebindKeys", CommandName::ListClients => "ListClients", + CommandName::ChangeHostFolder => "ChangeHostFolder", + CommandName::SetFloatingPanePinned => "SetFloatingPanePinned", + CommandName::StackPanes => "StackPanes", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -961,6 +995,9 @@ impl CommandName { "LoadNewPlugin" => Some(Self::LoadNewPlugin), "RebindKeys" => Some(Self::RebindKeys), "ListClients" => Some(Self::ListClients), + "ChangeHostFolder" => Some(Self::ChangeHostFolder), + "SetFloatingPanePinned" => Some(Self::SetFloatingPanePinned), + "StackPanes" => Some(Self::StackPanes), _ => None, } } diff --git a/zellij-utils/assets/prost/api.plugin_permission.rs b/zellij-utils/assets/prost/api.plugin_permission.rs index 013732d9bc..54b7de32e2 100644 --- a/zellij-utils/assets/prost/api.plugin_permission.rs +++ b/zellij-utils/assets/prost/api.plugin_permission.rs @@ -11,6 +11,7 @@ pub enum PermissionType { ReadCliPipes = 7, MessageAndLaunchOtherPlugins = 8, Reconfigure = 9, + FullHdAccess = 10, } impl PermissionType { /// String value of the enum field names used in the ProtoBuf definition. @@ -31,6 +32,7 @@ impl PermissionType { "MessageAndLaunchOtherPlugins" } PermissionType::Reconfigure => "Reconfigure", + PermissionType::FullHdAccess => "FullHdAccess", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -46,6 +48,7 @@ impl PermissionType { "ReadCliPipes" => Some(Self::ReadCliPipes), "MessageAndLaunchOtherPlugins" => Some(Self::MessageAndLaunchOtherPlugins), "Reconfigure" => Some(Self::Reconfigure), + "FullHdAccess" => Some(Self::FullHdAccess), _ => None, } } diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index 63348c4225..38d51f6d6e 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -246,6 +246,9 @@ pub enum Sessions { /// The height if the pane is floating as a bare integer (eg. 1) or percent (eg. 10%) #[clap(long, requires("floating"))] height: Option, + /// Whether to pin a floating pane so that it is always on top + #[clap(long, requires("floating"))] + pinned: Option, }, /// Load a plugin #[clap(visible_alias = "p")] @@ -288,6 +291,9 @@ pub enum Sessions { /// The height if the pane is floating as a bare integer (eg. 1) or percent (eg. 10%) #[clap(long, requires("floating"))] height: Option, + /// Whether to pin a floating pane so that it is always on top + #[clap(long, requires("floating"))] + pinned: Option, }, /// Edit file with default $EDITOR / $VISUAL #[clap(visible_alias = "e")] @@ -333,6 +339,9 @@ pub enum Sessions { /// The height if the pane is floating as a bare integer (eg. 1) or percent (eg. 10%) #[clap(long, requires("floating"))] height: Option, + /// Whether to pin a floating pane so that it is always on top + #[clap(long, requires("floating"))] + pinned: Option, }, ConvertConfig { old_config_file: PathBuf, @@ -526,6 +535,9 @@ pub enum CliAction { /// The height if the pane is floating as a bare integer (eg. 1) or percent (eg. 10%) #[clap(long, requires("floating"))] height: Option, + /// Whether to pin a floating pane so that it is always on top + #[clap(long, requires("floating"))] + pinned: Option, }, /// Open the specified file in a new zellij pane with your default EDITOR Edit { @@ -570,6 +582,9 @@ pub enum CliAction { /// The height if the pane is floating as a bare integer (eg. 1) or percent (eg. 10%) #[clap(long, requires("floating"))] height: Option, + /// Whether to pin a floating pane so that it is always on top + #[clap(long, requires("floating"))] + pinned: Option, }, /// Switch input mode of all connected clients [locked|pane|tab|resize|move|search|session] SwitchMode { @@ -744,4 +759,16 @@ tail -f /tmp/my-live-logfile | zellij action pipe --name logs --plugin https://e plugin_title: Option, }, ListClients, + TogglePanePinned, + /// Stack pane ids + /// Ids are a space separated list of pane ids. + /// They should either be in the form of `terminal_` (eg. terminal_1), `plugin_` (eg. + /// plugin_1) or bare integers in which case they'll be considered terminals (eg. 1 is + /// the equivalent of terminal_1) + /// + /// Example: zellij action stack-panes -- terminal_1 plugin_2 3 + StackPanes { + #[clap(last(true), required(true))] + pane_ids: Vec, + }, } diff --git a/zellij-utils/src/data.rs b/zellij-utils/src/data.rs index 94b74c4d21..de14de0296 100644 --- a/zellij-utils/src/data.rs +++ b/zellij-utils/src/data.rs @@ -912,6 +912,8 @@ pub enum Event { CommandPaneReRun(u32, Context), // u32 - terminal_pane_id, Option - FailedToWriteConfigToDisk(Option), // String -> the file path we failed to write ListClients(Vec), + HostFolderChanged(PathBuf), // PathBuf -> new host folder + FailedToChangeHostFolder(Option), // String -> the error we got when changing } #[derive( @@ -942,6 +944,7 @@ pub enum Permission { ReadCliPipes, MessageAndLaunchOtherPlugins, Reconfigure, + FullHdAccess, } impl PermissionType { @@ -963,6 +966,7 @@ impl PermissionType { "Send messages to and launch other plugins".to_owned() }, PermissionType::Reconfigure => "Change Zellij runtime configuration".to_owned(), + PermissionType::FullHdAccess => "Full access to the hard-drive".to_owned(), } } } @@ -1657,6 +1661,7 @@ pub struct FloatingPaneCoordinates { pub y: Option, pub width: Option, pub height: Option, + pub pinned: Option, } impl FloatingPaneCoordinates { @@ -1665,12 +1670,13 @@ impl FloatingPaneCoordinates { y: Option, width: Option, height: Option, + pinned: Option, ) -> Option { let x = x.and_then(|x| SplitSize::from_str(&x).ok()); let y = y.and_then(|y| SplitSize::from_str(&y).ok()); let width = width.and_then(|width| SplitSize::from_str(&width).ok()); let height = height.and_then(|height| SplitSize::from_str(&height).ok()); - if x.is_none() && y.is_none() && width.is_none() && height.is_none() { + if x.is_none() && y.is_none() && width.is_none() && height.is_none() && pinned.is_none() { None } else { Some(FloatingPaneCoordinates { @@ -1678,6 +1684,7 @@ impl FloatingPaneCoordinates { y, width, height, + pinned, }) } } @@ -1893,4 +1900,7 @@ pub enum PluginCommand { write_config_to_disk: bool, }, ListClients, + ChangeHostFolder(PathBuf), + SetFloatingPanePinned(PaneId, bool), // bool -> should be pinned + StackPanes(Vec), } diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 43deff3b7f..bd82b61c94 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -373,6 +373,9 @@ pub enum ScreenContext { BreakPanesToNewTab, BreakPanesToTabWithIndex, ListClientsToPlugin, + TogglePanePinned, + SetFloatingPanePinned, + StackPanes, } /// Stack call representations corresponding to the different types of [`PtyInstruction`]s. @@ -435,6 +438,7 @@ pub enum PluginContext { Reconfigure, FailedToWriteConfigToDisk, ListClientsToPlugin, + ChangePluginHostDir, } /// Stack call representations corresponding to the different types of [`ClientInstruction`]s. diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index e19a067244..95ec6eb26b 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -6,7 +6,7 @@ use super::layout::{ SwapFloatingLayout, SwapTiledLayout, TiledPaneLayout, }; use crate::cli::CliAction; -use crate::data::{Direction, KeyWithModifier, Resize}; +use crate::data::{Direction, KeyWithModifier, PaneId, Resize}; use crate::data::{FloatingPaneCoordinates, InputMode}; use crate::home::{find_default_config_dir, get_layout_dir}; use crate::input::config::{Config, ConfigError, KdlError}; @@ -300,6 +300,8 @@ pub enum Action { pane_title: Option, }, ListClients, + TogglePanePinned, + StackPanes(Vec), } impl Action { @@ -363,6 +365,7 @@ impl Action { y, width, height, + pinned, } => { let current_dir = get_current_dir(); // cwd should only be specified in a plugin alias if it was explicitly given to us, @@ -398,7 +401,7 @@ impl Action { name, skip_plugin_cache, cwd, - FloatingPaneCoordinates::new(x, y, width, height), + FloatingPaneCoordinates::new(x, y, width, height, pinned), )]) } else if in_place { Ok(vec![Action::NewInPlacePluginPane( @@ -440,7 +443,7 @@ impl Action { Ok(vec![Action::NewFloatingPane( Some(run_command_action), name, - FloatingPaneCoordinates::new(x, y, width, height), + FloatingPaneCoordinates::new(x, y, width, height, pinned), )]) } else if in_place { Ok(vec![Action::NewInPlacePane(Some(run_command_action), name)]) @@ -456,7 +459,7 @@ impl Action { Ok(vec![Action::NewFloatingPane( None, name, - FloatingPaneCoordinates::new(x, y, width, height), + FloatingPaneCoordinates::new(x, y, width, height, pinned), )]) } else if in_place { Ok(vec![Action::NewInPlacePane(None, name)]) @@ -476,6 +479,7 @@ impl Action { y, width, height, + pinned, } => { let mut file = file; let current_dir = get_current_dir(); @@ -494,7 +498,7 @@ impl Action { floating, in_place, start_suppressed, - FloatingPaneCoordinates::new(x, y, width, height), + FloatingPaneCoordinates::new(x, y, width, height, pinned), )]) }, CliAction::SwitchMode { input_mode } => { @@ -738,6 +742,54 @@ impl Action { }]) }, CliAction::ListClients => Ok(vec![Action::ListClients]), + CliAction::TogglePanePinned => Ok(vec![Action::TogglePanePinned]), + CliAction::StackPanes { pane_ids } => { + let mut malformed_ids = vec![]; + let pane_ids = pane_ids + .iter() + .filter_map(|stringified_pane_id| { + if let Some(terminal_pane_id) = + stringified_pane_id.strip_prefix("terminal_") + { + u32::from_str_radix(terminal_pane_id, 10) + .ok() + .or_else(|| { + malformed_ids.push(stringified_pane_id.to_owned()); + None + }) + .map(|id| PaneId::Terminal(id)) + } else if let Some(plugin_pane_id) = + stringified_pane_id.strip_prefix("plugin_") + { + u32::from_str_radix(plugin_pane_id, 10) + .ok() + .or_else(|| { + malformed_ids.push(stringified_pane_id.to_owned()); + None + }) + .map(|id| PaneId::Plugin(id)) + } else { + u32::from_str_radix(stringified_pane_id, 10) + .ok() + .or_else(|| { + malformed_ids.push(stringified_pane_id.to_owned()); + None + }) + .map(|id| PaneId::Terminal(id)) + } + }) + .collect(); + if !malformed_ids.is_empty() { + Err( + format!( + "Malformed pane ids: {}, expecting a space separated list of either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)", + malformed_ids.join(", ") + ) + ) + } else { + Ok(vec![Action::StackPanes(pane_ids)]) + } + }, } } pub fn launches_plugin(&self, plugin_url: &str) -> bool { diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index d4d8b261a5..b4110f73f1 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -738,10 +738,12 @@ pub struct FloatingPaneLayout { pub width: Option, pub x: Option, pub y: Option, + pub pinned: Option, pub run: Option, pub focus: Option, pub already_running: bool, pub pane_initial_contents: Option, + pub logical_position: Option, } impl FloatingPaneLayout { @@ -752,10 +754,12 @@ impl FloatingPaneLayout { width: None, x: None, y: None, + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, } } pub fn add_cwd_to_layout(&mut self, cwd: &PathBuf) { @@ -875,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) => { @@ -887,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); } @@ -896,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(); } @@ -1697,6 +1702,8 @@ fn split_space( cols: split_dimension, rows: inherited_dimension, is_stacked: layout.children_are_stacked, + is_pinned: false, + logical_position: None, }, SplitDirection::Horizontal => PaneGeom { x: space_to_split.x, @@ -1704,6 +1711,8 @@ fn split_space( cols: inherited_dimension, rows: split_dimension, is_stacked: layout.children_are_stacked, + is_pinned: false, + logical_position: None, }, }; split_geom.push(geom); @@ -1716,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() { @@ -1725,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 6981d9d7d0..95f6022597 100644 --- a/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap +++ b/zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tabs_and_floating_panes.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/input/./unit/layout_test.rs -assertion_line: 275 +assertion_line: 305 expression: "format!(\"{:#?}\", layout)" --- Layout { @@ -47,10 +47,12 @@ Layout { width: None, x: None, y: None, + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], ), @@ -96,10 +98,12 @@ Layout { width: None, x: None, y: None, + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -107,10 +111,12 @@ Layout { width: None, x: None, y: None, + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], ), diff --git a/zellij-utils/src/kdl/kdl_layout_parser.rs b/zellij-utils/src/kdl/kdl_layout_parser.rs index 81e97a7e23..c38c0146f7 100644 --- a/zellij-utils/src/kdl/kdl_layout_parser.rs +++ b/zellij-utils/src/kdl/kdl_layout_parser.rs @@ -122,6 +122,7 @@ impl<'a> KdlLayoutParser<'a> { || property_name == "y" || property_name == "width" || property_name == "height" + || property_name == "pinned" || property_name == "contents_file" } fn is_a_valid_tab_property(&self, property_name: &str) -> bool { @@ -596,6 +597,7 @@ impl<'a> KdlLayoutParser<'a> { let width = self.parse_percent_or_fixed(kdl_node, "width", false)?; let x = self.parse_percent_or_fixed(kdl_node, "x", true)?; let y = self.parse_percent_or_fixed(kdl_node, "y", true)?; + let pinned = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "pinned"); let run = self.parse_command_plugin_or_edit_block(kdl_node)?; let focus = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "focus"); let name = kdl_get_string_property_or_child_value_with_error!(kdl_node, "name") @@ -619,6 +621,7 @@ impl<'a> KdlLayoutParser<'a> { y, run, focus, + pinned, pane_initial_contents, ..Default::default() }) @@ -845,7 +848,7 @@ impl<'a> KdlLayoutParser<'a> { let width = self.parse_percent_or_fixed(kdl_node, "width", false)?; let x = self.parse_percent_or_fixed(kdl_node, "x", true)?; let y = self.parse_percent_or_fixed(kdl_node, "y", true)?; - // let mut floating_pane = FloatingPaneLayout::from(&pane_template); + let pinned = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "pinned"); if let Some(height) = height { pane_template.height = Some(height); } @@ -858,6 +861,9 @@ impl<'a> KdlLayoutParser<'a> { if let Some(x) = x { pane_template.x = Some(x); } + if let Some(pinned) = pinned { + pane_template.pinned = Some(pinned); + } Ok(pane_template) }, PaneOrFloatingPane::Either(mut pane_template) => { @@ -896,6 +902,7 @@ impl<'a> KdlLayoutParser<'a> { let width = self.parse_percent_or_fixed(kdl_node, "width", false)?; let x = self.parse_percent_or_fixed(kdl_node, "x", true)?; let y = self.parse_percent_or_fixed(kdl_node, "y", true)?; + let pinned = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "pinned"); let mut floating_pane = FloatingPaneLayout::from(&pane_template); if let Some(height) = height { floating_pane.height = Some(height); @@ -909,6 +916,9 @@ impl<'a> KdlLayoutParser<'a> { if let Some(x) = x { floating_pane.x = Some(x); } + if let Some(pinned) = pinned { + floating_pane.pinned = Some(pinned); + } Ok(floating_pane) }, } @@ -948,6 +958,7 @@ impl<'a> KdlLayoutParser<'a> { let width = self.parse_percent_or_fixed(kdl_node, "width", false)?; let x = self.parse_percent_or_fixed(kdl_node, "x", true)?; let y = self.parse_percent_or_fixed(kdl_node, "y", true)?; + let pinned = kdl_get_string_property_or_child_value_with_error!(kdl_node, "pinned"); let has_pane_properties = borderless.is_some() || split_size.is_some() @@ -956,7 +967,7 @@ impl<'a> KdlLayoutParser<'a> { || is_expanded_in_stack.is_some() || has_children_nodes; let has_floating_pane_properties = - height.is_some() || width.is_some() || x.is_some() || y.is_some(); + height.is_some() || width.is_some() || x.is_some() || y.is_some() || pinned.is_some(); if has_pane_properties || has_floating_pane_properties { Ok(false) } else { @@ -985,6 +996,7 @@ impl<'a> KdlLayoutParser<'a> { let width = self.parse_percent_or_fixed(kdl_node, "width", false)?; let x = self.parse_percent_or_fixed(kdl_node, "x", true)?; let y = self.parse_percent_or_fixed(kdl_node, "y", true)?; + let pinned = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "pinned"); let has_pane_properties = borderless.is_some() || split_size.is_some() @@ -993,7 +1005,7 @@ impl<'a> KdlLayoutParser<'a> { || is_expanded_in_stack.is_some() || has_children_nodes; let has_floating_pane_properties = - height.is_some() || width.is_some() || x.is_some() || y.is_some(); + height.is_some() || width.is_some() || x.is_some() || y.is_some() || pinned.is_some(); if has_pane_properties && has_floating_pane_properties { let mut pane_properties = vec![]; @@ -1028,6 +1040,9 @@ impl<'a> KdlLayoutParser<'a> { if y.is_some() { floating_pane_properties.push("y"); } + if pinned.is_some() { + floating_pane_properties.push("pinned"); + } Err(ConfigError::new_layout_kdl_error( format!( "A pane_template cannot have both pane ({}) and floating pane ({}) properties", @@ -1079,6 +1094,7 @@ impl<'a> KdlLayoutParser<'a> { let width = self.parse_percent_or_fixed(kdl_node, "width", false)?; let x = self.parse_percent_or_fixed(kdl_node, "x", true)?; let y = self.parse_percent_or_fixed(kdl_node, "y", true)?; + let pinned = kdl_get_bool_property_or_child_value_with_error!(kdl_node, "pinned"); self.pane_templates.insert( template_name, ( @@ -1089,6 +1105,7 @@ impl<'a> KdlLayoutParser<'a> { width, x, y, + pinned, ..Default::default() }), kdl_node.clone(), diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs index e3726173db..37f36fd8a5 100644 --- a/zellij-utils/src/kdl/mod.rs +++ b/zellij-utils/src/kdl/mod.rs @@ -1101,6 +1101,7 @@ impl Action { } Some(node) }, + Action::TogglePanePinned => Some(KdlNode::new("TogglePanePinned")), _ => None, } } @@ -1537,11 +1538,13 @@ impl TryFrom<(&KdlNode, &Options)> for Action { let height = command_metadata .and_then(|c_m| kdl_child_string_value_for_entry(c_m, "height")) .map(|s| s.to_owned()); + let pinned = + command_metadata.and_then(|c_m| kdl_child_bool_value_for_entry(c_m, "pinned")); if floating { Ok(Action::NewFloatingPane( Some(run_command_action), name, - FloatingPaneCoordinates::new(x, y, width, height), + FloatingPaneCoordinates::new(x, y, width, height, pinned), )) } else if in_place { Ok(Action::NewInPlacePane(Some(run_command_action), name)) @@ -1758,6 +1761,7 @@ impl TryFrom<(&KdlNode, &Options)> for Action { plugin_id, }) }, + "TogglePanePinned" => Ok(Action::TogglePanePinned), _ => Err(ConfigError::new_kdl_error( format!("Unsupported action: {}", action_name).into(), kdl_action.span().offset(), diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap index 6a709ef984..bcd3ac0e79 100644 --- a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/kdl/mod.rs -assertion_line: 5535 +assertion_line: 5551 expression: fake_config_stringified --- keybinds clear-defaults=true { @@ -17,6 +17,7 @@ keybinds clear-defaults=true { bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } bind "h" { MoveFocus "left"; } + bind "i" { TogglePanePinned; SwitchToMode "normal"; } bind "j" { MoveFocus "down"; } bind "k" { MoveFocus "up"; } bind "l" { MoveFocus "right"; } diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap index b4bbbefe3e..f31c73d3c4 100644 --- a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/kdl/mod.rs -assertion_line: 5547 +assertion_line: 5563 expression: fake_config_stringified --- keybinds clear-defaults=true { @@ -17,6 +17,7 @@ keybinds clear-defaults=true { bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } bind "h" { MoveFocus "left"; } + bind "i" { TogglePanePinned; SwitchToMode "normal"; } bind "j" { MoveFocus "down"; } bind "k" { MoveFocus "up"; } bind "l" { MoveFocus "right"; } diff --git a/zellij-utils/src/pane_size.rs b/zellij-utils/src/pane_size.rs index fe56e720e2..ba2ac8ed3f 100644 --- a/zellij-utils/src/pane_size.rs +++ b/zellij-utils/src/pane_size.rs @@ -10,15 +10,30 @@ use crate::position::Position; /// Contains the position and size of a [`Pane`], or more generally of any terminal, measured /// in character rows and columns. -#[derive(Clone, Copy, Default, PartialEq, Debug, Serialize, Deserialize, Eq, Hash)] +#[derive(Clone, Copy, Default, Debug, Serialize, Deserialize, Hash)] pub struct PaneGeom { pub x: usize, pub y: usize, pub rows: Dimension, pub cols: Dimension, pub is_stacked: bool, + 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 + self.x == other.x + && self.y == other.y + && self.rows == other.rows + && self.cols == other.cols + && self.is_stacked == other.is_stacked + } +} + +impl Eq for PaneGeom {} + #[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq)] pub struct Viewport { pub x: usize, diff --git a/zellij-utils/src/plugin_api/action.proto b/zellij-utils/src/plugin_api/action.proto index d78d5e6956..df7f3b05b7 100644 --- a/zellij-utils/src/plugin_api/action.proto +++ b/zellij-utils/src/plugin_api/action.proto @@ -244,6 +244,7 @@ enum ActionName { CliPipe = 82; MoveTab = 83; KeybindPipe = 84; + TogglePanePinned = 85; } message Position { diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs index 9bb8ac7a8e..e3c0513007 100644 --- a/zellij-utils/src/plugin_api/action.rs +++ b/zellij-utils/src/plugin_api/action.rs @@ -688,6 +688,10 @@ impl TryFrom for Action { }, _ => Err("Wrong payload for Action::RenameSession"), }, + Some(ProtobufActionName::TogglePanePinned) => match protobuf_action.optional_payload { + Some(_) => Err("TogglePanePinned should not have a payload"), + None => Ok(Action::TogglePanePinned), + }, Some(ProtobufActionName::KeybindPipe) => match protobuf_action.optional_payload { Some(_) => Err("KeybindPipe should not have a payload"), // TODO: at some point we might want to support a payload here @@ -1284,6 +1288,10 @@ impl TryFrom for ProtobufAction { name: ProtobufActionName::KeybindPipe as i32, optional_payload: None, }), + Action::TogglePanePinned { .. } => Ok(ProtobufAction { + name: ProtobufActionName::TogglePanePinned as i32, + optional_payload: None, + }), Action::NoOp | Action::Confirm | Action::NewInPlacePane(..) @@ -1293,6 +1301,7 @@ impl TryFrom for ProtobufAction { | Action::DumpLayout | Action::CliPipe { .. } | Action::ListClients + | Action::StackPanes(..) | Action::SkipConfirm(..) => Err("Unsupported action"), } } diff --git a/zellij-utils/src/plugin_api/event.proto b/zellij-utils/src/plugin_api/event.proto index 607ba448b5..be09507ef3 100644 --- a/zellij-utils/src/plugin_api/event.proto +++ b/zellij-utils/src/plugin_api/event.proto @@ -50,6 +50,8 @@ enum EventType { CommandPaneReRun = 24; FailedToWriteConfigToDisk = 25; ListClients = 26; + HostFolderChanged = 27; + FailedToChangeHostFolder = 28; } message EventNameList { @@ -81,9 +83,19 @@ message Event { CommandPaneReRunPayload command_pane_rerun_payload = 21; FailedToWriteConfigToDiskPayload failed_to_write_config_to_disk_payload = 22; ListClientsPayload list_clients_payload = 23; + HostFolderChangedPayload host_folder_changed_payload = 24; + FailedToChangeHostFolderPayload failed_to_change_host_folder_payload = 25; } } +message FailedToChangeHostFolderPayload { + optional string error_message = 1; +} + +message HostFolderChangedPayload { + string new_host_folder_path = 1; +} + message ListClientsPayload { repeated ClientInfo client_info = 1; } diff --git a/zellij-utils/src/plugin_api/event.rs b/zellij-utils/src/plugin_api/event.rs index d78f556771..b1ab0e8e24 100644 --- a/zellij-utils/src/plugin_api/event.rs +++ b/zellij-utils/src/plugin_api/event.rs @@ -333,6 +333,22 @@ impl TryFrom for Event { }, _ => Err("Malformed payload for the FailedToWriteConfigToDisk Event"), }, + Some(ProtobufEventType::HostFolderChanged) => match protobuf_event.payload { + Some(ProtobufEventPayload::HostFolderChangedPayload( + host_folder_changed_payload, + )) => Ok(Event::HostFolderChanged(PathBuf::from( + host_folder_changed_payload.new_host_folder_path, + ))), + _ => Err("Malformed payload for the HostFolderChanged Event"), + }, + Some(ProtobufEventType::FailedToChangeHostFolder) => match protobuf_event.payload { + Some(ProtobufEventPayload::FailedToChangeHostFolderPayload( + failed_to_change_host_folder_payload, + )) => Ok(Event::FailedToChangeHostFolder( + failed_to_change_host_folder_payload.error_message, + )), + _ => Err("Malformed payload for the FailedToChangeHostFolder Event"), + }, None => Err("Unknown Protobuf Event"), } } @@ -683,6 +699,20 @@ impl TryFrom for ProtobufEvent { .collect(), })), }), + Event::HostFolderChanged(new_host_folder_path) => Ok(ProtobufEvent { + name: ProtobufEventType::HostFolderChanged as i32, + payload: Some(event::Payload::HostFolderChangedPayload( + HostFolderChangedPayload { + new_host_folder_path: new_host_folder_path.display().to_string(), + }, + )), + }), + Event::FailedToChangeHostFolder(error_message) => Ok(ProtobufEvent { + name: ProtobufEventType::FailedToChangeHostFolder as i32, + payload: Some(event::Payload::FailedToChangeHostFolderPayload( + FailedToChangeHostFolderPayload { error_message }, + )), + }), } } } @@ -1228,6 +1258,8 @@ impl TryFrom for EventType { ProtobufEventType::CommandPaneReRun => EventType::CommandPaneReRun, ProtobufEventType::FailedToWriteConfigToDisk => EventType::FailedToWriteConfigToDisk, ProtobufEventType::ListClients => EventType::ListClients, + ProtobufEventType::HostFolderChanged => EventType::HostFolderChanged, + ProtobufEventType::FailedToChangeHostFolder => EventType::FailedToChangeHostFolder, }) } } @@ -1263,6 +1295,8 @@ impl TryFrom for ProtobufEventType { EventType::CommandPaneReRun => ProtobufEventType::CommandPaneReRun, EventType::FailedToWriteConfigToDisk => ProtobufEventType::FailedToWriteConfigToDisk, EventType::ListClients => ProtobufEventType::ListClients, + EventType::HostFolderChanged => ProtobufEventType::HostFolderChanged, + EventType::FailedToChangeHostFolder => ProtobufEventType::FailedToChangeHostFolder, }) } } diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto index 5b58de1433..7572476da6 100644 --- a/zellij-utils/src/plugin_api/plugin_command.proto +++ b/zellij-utils/src/plugin_api/plugin_command.proto @@ -127,6 +127,9 @@ enum CommandName { LoadNewPlugin = 111; RebindKeys = 112; ListClients = 113; + ChangeHostFolder = 114; + SetFloatingPanePinned = 115; + StackPanes = 116; } message PluginCommand { @@ -210,9 +213,25 @@ message PluginCommand { ReloadPluginPayload reload_plugin_payload = 86; LoadNewPluginPayload load_new_plugin_payload = 87; RebindKeysPayload rebind_keys_payload = 88; + ChangeHostFolderPayload change_host_folder_payload = 89; + SetFloatingPanePinnedPayload set_floating_pane_pinned_payload = 90; + StackPanesPayload stack_panes_payload = 91; } } +message StackPanesPayload { + repeated PaneId pane_ids = 1; +} + +message SetFloatingPanePinnedPayload { + PaneId pane_id = 1; + bool should_be_pinned = 2; +} + +message ChangeHostFolderPayload { + string new_host_folder = 1; +} + message RebindKeysPayload { repeated KeyToRebind keys_to_rebind = 1; repeated KeyToUnbind keys_to_unbind = 2; @@ -479,6 +498,7 @@ message FloatingPaneCoordinates { optional FixedOrPercentValue y = 2; optional FixedOrPercentValue width = 3; optional FixedOrPercentValue height = 4; + optional bool pinned = 5; } message FixedOrPercentValue { diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs index 0668797141..2621502a93 100644 --- a/zellij-utils/src/plugin_api/plugin_command.rs +++ b/zellij-utils/src/plugin_api/plugin_command.rs @@ -4,9 +4,9 @@ pub use super::generated_api::api::{ input_mode::InputMode as ProtobufInputMode, plugin_command::{ plugin_command::Payload, BreakPanesToNewTabPayload, BreakPanesToTabWithIndexPayload, - ClearScreenForPaneIdPayload, CliPipeOutputPayload, CloseTabWithIndexPayload, CommandName, - ContextItem, EditScrollbackForPaneWithIdPayload, EnvVariable, ExecCmdPayload, - FixedOrPercent as ProtobufFixedOrPercent, + ChangeHostFolderPayload, ClearScreenForPaneIdPayload, CliPipeOutputPayload, + CloseTabWithIndexPayload, CommandName, ContextItem, EditScrollbackForPaneWithIdPayload, + EnvVariable, ExecCmdPayload, FixedOrPercent as ProtobufFixedOrPercent, FixedOrPercentValue as ProtobufFixedOrPercentValue, FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates, HidePaneWithIdPayload, HttpVerb as ProtobufHttpVerb, IdAndNewName, KeyToRebind, KeyToUnbind, KillSessionsPayload, @@ -18,10 +18,11 @@ pub use super::generated_api::api::{ RebindKeysPayload, ReconfigurePayload, ReloadPluginPayload, RequestPluginPermissionPayload, RerunCommandPanePayload, ResizePaneIdWithDirectionPayload, ResizePayload, RunCommandPayload, ScrollDownInPaneIdPayload, ScrollToBottomInPaneIdPayload, - ScrollToTopInPaneIdPayload, ScrollUpInPaneIdPayload, SetTimeoutPayload, - ShowPaneWithIdPayload, SubscribePayload, SwitchSessionPayload, SwitchTabToPayload, - TogglePaneEmbedOrEjectForPaneIdPayload, TogglePaneIdFullscreenPayload, UnsubscribePayload, - WebRequestPayload, WriteCharsToPaneIdPayload, WriteToPaneIdPayload, + ScrollToTopInPaneIdPayload, ScrollUpInPaneIdPayload, SetFloatingPanePinnedPayload, + SetTimeoutPayload, ShowPaneWithIdPayload, StackPanesPayload, SubscribePayload, + SwitchSessionPayload, SwitchTabToPayload, TogglePaneEmbedOrEjectForPaneIdPayload, + TogglePaneIdFullscreenPayload, UnsubscribePayload, WebRequestPayload, + WriteCharsToPaneIdPayload, WriteToPaneIdPayload, }, plugin_permission::PermissionType as ProtobufPermissionType, resize::ResizeAction as ProtobufResizeAction, @@ -81,6 +82,7 @@ impl Into for ProtobufFloatingPaneCoordinates { None => None, } }), + pinned: self.pinned, } } } @@ -132,6 +134,7 @@ impl Into for FloatingPaneCoordinates { }), None => None, }, + pinned: self.pinned, } } } @@ -1303,6 +1306,41 @@ impl TryFrom for PluginCommand { Some(_) => Err("ListClients should have no payload, found a payload"), None => Ok(PluginCommand::ListClients), }, + Some(CommandName::ChangeHostFolder) => match protobuf_plugin_command.payload { + Some(Payload::ChangeHostFolderPayload(change_host_folder_payload)) => { + Ok(PluginCommand::ChangeHostFolder(PathBuf::from( + change_host_folder_payload.new_host_folder, + ))) + }, + _ => Err("Mismatched payload for ChangeHostFolder"), + }, + Some(CommandName::SetFloatingPanePinned) => match protobuf_plugin_command.payload { + Some(Payload::SetFloatingPanePinnedPayload(set_floating_pane_pinned_payload)) => { + match set_floating_pane_pinned_payload + .pane_id + .and_then(|p| p.try_into().ok()) + { + Some(pane_id) => Ok(PluginCommand::SetFloatingPanePinned( + pane_id, + set_floating_pane_pinned_payload.should_be_pinned, + )), + None => Err("PaneId not found!"), + } + }, + _ => Err("Mismatched payload for SetFloatingPanePinned"), + }, + Some(CommandName::StackPanes) => match protobuf_plugin_command.payload { + Some(Payload::StackPanesPayload(stack_panes_payload)) => { + Ok(PluginCommand::StackPanes( + stack_panes_payload + .pane_ids + .into_iter() + .filter_map(|p_id| p_id.try_into().ok()) + .collect(), + )) + }, + _ => Err("Mismatched payload for SetFloatingPanePinned"), + }, None => Err("Unrecognized plugin command"), } } @@ -2130,6 +2168,32 @@ impl TryFrom for ProtobufPluginCommand { name: CommandName::ListClients as i32, payload: None, }), + PluginCommand::ChangeHostFolder(new_host_folder) => Ok(ProtobufPluginCommand { + name: CommandName::ChangeHostFolder as i32, + payload: Some(Payload::ChangeHostFolderPayload(ChangeHostFolderPayload { + new_host_folder: new_host_folder.display().to_string(), // TODO: not accurate? + })), + }), + PluginCommand::SetFloatingPanePinned(pane_id, should_be_pinned) => { + Ok(ProtobufPluginCommand { + name: CommandName::SetFloatingPanePinned as i32, + payload: Some(Payload::SetFloatingPanePinnedPayload( + SetFloatingPanePinnedPayload { + pane_id: pane_id.try_into().ok(), + should_be_pinned, + }, + )), + }) + }, + PluginCommand::StackPanes(pane_ids) => Ok(ProtobufPluginCommand { + name: CommandName::StackPanes as i32, + payload: Some(Payload::StackPanesPayload(StackPanesPayload { + pane_ids: pane_ids + .into_iter() + .filter_map(|p_id| p_id.try_into().ok()) + .collect(), + })), + }), } } } diff --git a/zellij-utils/src/plugin_api/plugin_permission.proto b/zellij-utils/src/plugin_api/plugin_permission.proto index 399ebba528..4f1f90f9ac 100644 --- a/zellij-utils/src/plugin_api/plugin_permission.proto +++ b/zellij-utils/src/plugin_api/plugin_permission.proto @@ -13,4 +13,5 @@ enum PermissionType { ReadCliPipes = 7; MessageAndLaunchOtherPlugins = 8; Reconfigure = 9; + FullHdAccess = 10; } diff --git a/zellij-utils/src/plugin_api/plugin_permission.rs b/zellij-utils/src/plugin_api/plugin_permission.rs index 5ea70157a2..5b6a831fb0 100644 --- a/zellij-utils/src/plugin_api/plugin_permission.rs +++ b/zellij-utils/src/plugin_api/plugin_permission.rs @@ -25,6 +25,7 @@ impl TryFrom for PermissionType { Ok(PermissionType::MessageAndLaunchOtherPlugins) }, ProtobufPermissionType::Reconfigure => Ok(PermissionType::Reconfigure), + ProtobufPermissionType::FullHdAccess => Ok(PermissionType::FullHdAccess), } } } @@ -51,6 +52,7 @@ impl TryFrom for ProtobufPermissionType { Ok(ProtobufPermissionType::MessageAndLaunchOtherPlugins) }, PermissionType::Reconfigure => Ok(ProtobufPermissionType::Reconfigure), + PermissionType::FullHdAccess => Ok(ProtobufPermissionType::FullHdAccess), } } } diff --git a/zellij-utils/src/session_serialization.rs b/zellij-utils/src/session_serialization.rs index 68a9c2dae0..ae25295299 100644 --- a/zellij-utils/src/session_serialization.rs +++ b/zellij-utils/src/session_serialization.rs @@ -453,6 +453,14 @@ fn serialize_floating_layout_attributes( }, None => {}, } + match layout.pinned { + Some(true) => { + let mut node = KdlNode::new("pinned"); + node.entries_mut().push(KdlEntry::new(KdlValue::Bool(true))); + pane_node_children.nodes_mut().push(node); + }, + _ => {}, + } } fn serialize_start_suspended(command: &Option, pane_node_children: &mut KdlDocument) { @@ -774,10 +782,12 @@ fn get_floating_panes_layout_from_panegeoms( width: Some(m.geom.cols.into()), x: Some(PercentOrFixed::Fixed(m.geom.x)), y: Some(PercentOrFixed::Fixed(m.geom.y)), + pinned: Some(m.geom.is_pinned), run, focus: Some(m.is_focused), already_running: false, pane_initial_contents: m.pane_contents.clone(), + logical_position: None, } }) .collect() @@ -1275,6 +1285,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1286,6 +1298,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1301,6 +1315,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1315,6 +1331,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1334,6 +1352,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1347,6 +1367,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1362,6 +1384,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1373,6 +1397,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1386,6 +1412,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1415,6 +1443,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1426,6 +1456,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1441,6 +1473,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1455,6 +1489,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1474,6 +1510,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1487,6 +1525,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1502,6 +1542,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1515,6 +1557,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1528,6 +1572,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1555,6 +1601,8 @@ mod tests { rows: Dimension::fixed(1), cols: Dimension::fixed(10), is_stacked: true, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1565,6 +1613,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: true, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1575,6 +1625,8 @@ mod tests { rows: Dimension::fixed(1), cols: Dimension::fixed(10), is_stacked: true, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1598,6 +1650,8 @@ mod tests { rows: Dimension::percent(100.0), cols: Dimension::percent(100.0), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }], @@ -1612,6 +1666,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1622,6 +1678,8 @@ mod tests { rows: Dimension::fixed(10), cols: Dimension::fixed(10), is_stacked: false, + is_pinned: false, + logical_position: None, }, ..Default::default() }, @@ -1753,6 +1811,8 @@ mod tests { rows: get_dim(&data["rows"]), 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 8f85ae3e38..b870878431 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments-2.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/setup.rs -assertion_line: 740 +assertion_line: 756 expression: "format!(\"{:#?}\", layout)" --- Layout { @@ -808,7 +808,7 @@ Layout { ( { MaxPanes( - 5, + 4, ): TiledPaneLayout { children_split_direction: Horizontal, name: None, @@ -1676,10 +1676,12 @@ Layout { 1, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1703,10 +1705,12 @@ Layout { 2, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1730,10 +1734,12 @@ Layout { 3, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1757,10 +1763,12 @@ Layout { 4, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1784,10 +1792,12 @@ Layout { 5, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1811,10 +1821,12 @@ Layout { 6, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1838,10 +1850,12 @@ Layout { 7, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1865,10 +1879,12 @@ Layout { 8, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1892,10 +1908,12 @@ Layout { 9, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -1919,12 +1937,12 @@ Layout { 10, ), ), + pinned: None, run: None, - focus: Some( - true, - ), + focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], }, @@ -1951,10 +1969,12 @@ Layout { 50, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], MaxPanes( @@ -1978,10 +1998,12 @@ Layout { 25, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2001,10 +2023,12 @@ Layout { 25, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], MaxPanes( @@ -2028,12 +2052,12 @@ Layout { 55, ), ), + pinned: None, run: None, - focus: Some( - true, - ), + focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2053,10 +2077,12 @@ Layout { 1, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2076,10 +2102,12 @@ Layout { 1, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], MaxPanes( @@ -2107,10 +2135,12 @@ Layout { 55, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2134,12 +2164,12 @@ Layout { 55, ), ), + pinned: None, run: None, - focus: Some( - true, - ), + focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2163,10 +2193,12 @@ Layout { 1, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, FloatingPaneLayout { name: None, @@ -2190,10 +2222,12 @@ Layout { 1, ), ), + pinned: None, run: None, focus: None, already_running: false, pane_initial_contents: None, + logical_position: None, }, ], }, diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap index 81ca089c87..754375a862 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/setup.rs -assertion_line: 754 +assertion_line: 755 expression: "format!(\"{:#?}\", config)" --- Config { @@ -1076,6 +1076,17 @@ Config { Left, ), ], + KeyWithModifier { + bare_key: Char( + 'i', + ), + key_modifiers: {}, + }: [ + TogglePanePinned, + SwitchToMode( + Normal, + ), + ], KeyWithModifier { bare_key: Char( 'i', diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap index 8e9c8db391..4e79b783f5 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/setup.rs -assertion_line: 812 +assertion_line: 813 expression: "format!(\"{:#?}\", config)" --- Config { @@ -1076,6 +1076,17 @@ Config { Left, ), ], + KeyWithModifier { + bare_key: Char( + 'i', + ), + key_modifiers: {}, + }: [ + TogglePanePinned, + SwitchToMode( + Normal, + ), + ], KeyWithModifier { bare_key: Char( 'i', diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap index ee9f43544f..6c435fa0d1 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/setup.rs -assertion_line: 840 +assertion_line: 841 expression: "format!(\"{:#?}\", config)" --- Config { @@ -1076,6 +1076,17 @@ Config { Left, ), ], + KeyWithModifier { + bare_key: Char( + 'i', + ), + key_modifiers: {}, + }: [ + TogglePanePinned, + SwitchToMode( + Normal, + ), + ], KeyWithModifier { bare_key: Char( 'i', diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap index b380f31e92..5712f84705 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/setup.rs -assertion_line: 826 +assertion_line: 827 expression: "format!(\"{:#?}\", config)" --- Config { @@ -1076,6 +1076,17 @@ Config { Left, ), ], + KeyWithModifier { + bare_key: Char( + 'i', + ), + key_modifiers: {}, + }: [ + TogglePanePinned, + SwitchToMode( + Normal, + ), + ], KeyWithModifier { bare_key: Char( 'i',