From 69eb904426e64649fc7228b0d6803469911267d7 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Tue, 17 Oct 2023 11:55:38 +0200 Subject: [PATCH] feat(panes): Add an option to press and drop to shell in command panes (#2872) * feat(panes): ESC to drop to default shell on command panes * style(fmt): rustfmt --- src/tests/e2e/cases.rs | 8 +-- ...2e__cases__quit_and_resurrect_session.snap | 4 +- ...t_session_with_viewport_serialization.snap | 4 +- ...__cases__send_command_through_the_cli.snap | 48 ++++++++--------- zellij-server/src/os_input_output.rs | 22 ++------ zellij-server/src/panes/terminal_character.rs | 32 +++++++++--- zellij-server/src/panes/terminal_pane.rs | 8 +++ zellij-server/src/pty.rs | 51 +++++++++++++++++++ zellij-server/src/screen.rs | 1 + zellij-server/src/tab/mod.rs | 15 ++++++ ...ng_layout_is_included_in_swap_layouts.snap | 4 +- ...se_layout_is_included_in_swap_layouts.snap | 7 +-- ..._plugins_and_commands_swaped_properly.snap | 4 +- ..._plugins_and_commands_swaped_properly.snap | 7 +-- ...mand_panes_present_in_existing_layout.snap | 12 ++--- ...mand_panes_present_in_existing_layout.snap | 7 +-- ...ugin_panes_present_in_existing_layout.snap | 7 +-- .../src/tab/unit/tab_integration_tests.rs | 6 +++ zellij-server/src/tab/unit/tab_tests.rs | 3 ++ zellij-server/src/ui/pane_boundaries_frame.rs | 25 +++++++-- zellij-utils/src/errors.rs | 1 + 21 files changed, 194 insertions(+), 82 deletions(-) diff --git a/src/tests/e2e/cases.rs b/src/tests/e2e/cases.rs index c5110b69..be337ea9 100644 --- a/src/tests/e2e/cases.rs +++ b/src/tests/e2e/cases.rs @@ -2070,7 +2070,7 @@ pub fn send_command_through_the_cli() { // so when we press "Enter", it will run again and we'll see two "foo"s one after the other, // that's how we know the whole flow is working let fake_win_size = Size { - cols: 120, + cols: 150, rows: 24, }; let mut test_attempts = 10; @@ -2118,7 +2118,7 @@ pub fn send_command_through_the_cli() { instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; if remote_terminal.snapshot_contains("") - && remote_terminal.cursor_position_is(61, 3) + && remote_terminal.cursor_position_is(76, 3) { remote_terminal.send_key(&SPACE); // re-run script - here we use SPACE // instead of the default ENTER because @@ -2135,7 +2135,7 @@ pub fn send_command_through_the_cli() { instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; if remote_terminal.snapshot_contains("") - && remote_terminal.cursor_position_is(61, 4) + && remote_terminal.cursor_position_is(76, 4) { step_is_complete = true } @@ -2149,7 +2149,7 @@ pub fn send_command_through_the_cli() { instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; if remote_terminal.snapshot_contains("foo") - && remote_terminal.cursor_position_is(61, 4) + && remote_terminal.cursor_position_is(76, 4) { step_is_complete = true } 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 a7c58010..fd55ac42 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 @@ -17,10 +17,10 @@ expression: last_snapshot │ │ │ │ │────────────────────────────┘ │ │ │ Waiting to run: top │ │────────────────────────────┐ │ │ │ │ │ │ -│ │ │ to run, to exit │ │ │ +│ │ │ run, drop to shell, exit │ │ │ │ └─│ │ │ │ │ │ │ │ │ -│ └─ to run, to exit ─────────────────────┘ │ │ +│ └─ run, drop to shell, exit ──────┘ │ │ │ │ │ │ │ └────────────────────────────────────────────────────────┘ │ │ ││ │ 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 51031337..f3677360 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 @@ -17,10 +17,10 @@ expression: last_snapshot │ │ │ │ │────────────────────────────┘ │ │ │ Waiting to run: top │ │────────────────────────────┐ │ │ │ │ │ │ -│ │ │ to run, to exit │ │ │ +│ │ │ run, drop to shell, exit │ │ │ │ └─│ │ │ │ │ │ │ │ │ -│ └─ to run, to exit ─────────────────────┘ │ │ +│ └─ run, drop to shell, exit ──────┘ │ │ │ │ │ │ │ └────────────────────────────────────────────────────────┘ │ │ ││ │ diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap index 343e574a..4d255521 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap @@ -1,29 +1,29 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 2031 +assertion_line: 2175 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  -┌ Pane #1 ─────────────────────────────────────────────────┐┌ /usr/src/zellij/fixtures/append-echo-script.sh ──────────┐ -│$ /usr/src/zellij/x86_64-unknown-linux-musl/release/zellij││foo │ -│ run -s -- "/usr/src/zellij/fixtures/append-echo-script.sh││foo │ -│" ││█ │ -│$ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -└──────────────────────────────────────────────────────────┘└ [ EXIT CODE: 0 ] to re-run, to exit ────┘ - Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. +┌ Pane #1 ────────────────────────────────────────────────────────────────┐┌ /usr/src/zellij/fixtures/append-echo-script.sh ─────────────────────────┐ +│$ /usr/src/zellij/x86_64-unknown-linux-musl/release/zellij run -s -- "/us││foo │ +│r/src/zellij/fixtures/append-echo-script.sh" ││foo │ +│$ ││█ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +└─────────────────────────────────────────────────────────────────────────┘└ [ EXIT CODE: 0 ] re-run, drop to shell, exit ────┘ + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  Alt + <[]>  VERTICAL  + Tip: Alt + => open new pane. Alt + <←↓↑→> or Alt + => navigate between panes. Alt + <+|-> => increase/decrease pane size. diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index 46a0d997..793e5b66 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -31,7 +31,7 @@ use zellij_utils::{ }; use std::{ - collections::{BTreeMap, HashMap, HashSet}, + collections::{BTreeMap, BTreeSet, HashMap}, env, fs::File, io::Write, @@ -581,7 +581,7 @@ impl ServerOsApi for ServerOsInputOutput { .with_context(err_context)?; let mut terminal_id = None; { - let current_ids: HashSet = self + let current_ids: BTreeSet = self .terminal_id_to_raw_fd .lock() .to_anyhow() @@ -589,13 +589,7 @@ impl ServerOsApi for ServerOsInputOutput { .keys() .copied() .collect(); - for i in 0..u32::MAX { - let i = i as u32; - if !current_ids.contains(&i) { - terminal_id = Some(i); - break; - } - } + terminal_id = current_ids.last().map(|l| l + 1).or(Some(0)); } match terminal_id { Some(terminal_id) => { @@ -628,7 +622,7 @@ impl ServerOsApi for ServerOsInputOutput { let mut terminal_id = None; { - let current_ids: HashSet = self + let current_ids: BTreeSet = self .terminal_id_to_raw_fd .lock() .to_anyhow() @@ -636,13 +630,7 @@ impl ServerOsApi for ServerOsInputOutput { .keys() .copied() .collect(); - for i in 0..u32::MAX { - let i = i as u32; - if !current_ids.contains(&i) { - terminal_id = Some(i); - break; - } - } + terminal_id = current_ids.last().map(|l| l + 1).or(Some(0)); } match terminal_id { Some(terminal_id) => { diff --git a/zellij-server/src/panes/terminal_character.rs b/zellij-server/src/panes/terminal_character.rs index 23ea1a52..71aec7a4 100644 --- a/zellij-server/src/panes/terminal_character.rs +++ b/zellij-server/src/panes/terminal_character.rs @@ -773,21 +773,25 @@ pub fn render_first_run_banner( let controls_bare_text_first_part = "<"; let enter_bare_text = "ENTER"; - let controls_bare_text_second_part = "> to run, <"; + let controls_bare_text_second_part = "> run, <"; + let esc_bare_text = "ESC"; + let controls_bare_text_third_part = "> drop to shell, <"; let ctrl_c_bare_text = "Ctrl-c"; - let controls_bare_text_third_part = "> to exit"; + let controls_bare_text_fourth_part = "> exit"; let controls_color = RESET_STYLES .foreground(Some(AnsiCode::from(style.colors.orange))) .bold(Some(AnsiCode::On)); let controls_line_length = controls_bare_text_first_part.len() + enter_bare_text.len() + controls_bare_text_second_part.len() + + esc_bare_text.len() + + controls_bare_text_third_part.len() + ctrl_c_bare_text.len() - + controls_bare_text_third_part.len(); + + controls_bare_text_fourth_part.len(); let controls_column_start_position = middle_column.saturating_sub(controls_line_length / 2); let controls_line = format!( - "\u{1b}[{};{}H{}<{}{}{}{}> to run, <{}{}{}{}> to exit", + "\u{1b}[{};{}H{}<{}{}{}{}> run, <{}{}{}{}> drop to shell, <{}{}{}{}> exit", middle_row + 2, controls_column_start_position, bold_text, @@ -796,6 +800,10 @@ pub fn render_first_run_banner( RESET_STYLES, bold_text, controls_color, + esc_bare_text, + RESET_STYLES, + bold_text, + controls_color, ctrl_c_bare_text, RESET_STYLES, bold_text @@ -817,21 +825,25 @@ pub fn render_first_run_banner( let controls_bare_text_first_part = "<"; let enter_bare_text = "ENTER"; - let controls_bare_text_second_part = "> to run, <"; + let controls_bare_text_second_part = "> run, <"; + let esc_bare_text = "ESC"; + let controls_bare_text_third_part = "> drop to shell, <"; let ctrl_c_bare_text = "Ctrl-c"; - let controls_bare_text_third_part = "> to exit"; + let controls_bare_text_fourth_part = "> exit"; let controls_color = RESET_STYLES .foreground(Some(AnsiCode::from(style.colors.orange))) .bold(Some(AnsiCode::On)); let controls_line_length = controls_bare_text_first_part.len() + enter_bare_text.len() + controls_bare_text_second_part.len() + + esc_bare_text.len() + + controls_bare_text_third_part.len() + ctrl_c_bare_text.len() - + controls_bare_text_third_part.len(); + + controls_bare_text_fourth_part.len(); let controls_column_start_position = middle_column.saturating_sub(controls_line_length / 2); let controls_line = format!( - "\u{1b}[{};{}H{}<{}{}{}{}> to run, <{}{}{}{}> to exit", + "\u{1b}[{};{}H{}<{}{}{}{}> run, <{}{}{}{}> drop to shell, <{}{}{}{}> exit", middle_row + 2, controls_column_start_position, bold_text, @@ -840,6 +852,10 @@ pub fn render_first_run_banner( RESET_STYLES, bold_text, controls_color, + esc_bare_text, + RESET_STYLES, + bold_text, + controls_color, ctrl_c_bare_text, RESET_STYLES, bold_text diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index 6c405b6e..ac4c6da6 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -40,6 +40,7 @@ const END_KEY: &[u8] = &[27, 91, 70]; const BRACKETED_PASTE_BEGIN: &[u8] = &[27, 91, 50, 48, 48, 126]; const BRACKETED_PASTE_END: &[u8] = &[27, 91, 50, 48, 49, 126]; const ENTER_NEWLINE: &[u8] = &[10]; +const ESC: &[u8] = &[27]; const ENTER_CARRIAGE_RETURN: &[u8] = &[13]; const SPACE: &[u8] = &[32]; const CTRL_C: &[u8] = &[3]; // TODO: check this to be sure it fits all types of CTRL_C (with mac, etc) @@ -192,6 +193,13 @@ impl Pane for TerminalPane { self.remove_banner(); Some(AdjustedInput::ReRunCommandInThisPane(run_command)) }, + ESC => { + self.is_held = None; + self.grid.reset_terminal_state(); + self.set_should_render(true); + self.remove_banner(); + Some(AdjustedInput::DropToShellInThisPane) + }, CTRL_C => Some(AdjustedInput::CloseThisPane), _ => None, } diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index e355e8c5..6dd38e9f 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -66,6 +66,7 @@ pub enum PtyInstruction { ClosePane(PaneId), CloseTab(Vec), ReRunCommandInPane(PaneId, RunCommand), + DropToShellInPane(PaneId, Option), // Option - default shell SpawnInPlaceTerminal( Option, Option, @@ -89,6 +90,7 @@ impl From<&PtyInstruction> for PtyContext { PtyInstruction::CloseTab(_) => PtyContext::CloseTab, PtyInstruction::NewTab(..) => PtyContext::NewTab, PtyInstruction::ReRunCommandInPane(..) => PtyContext::ReRunCommandInPane, + PtyInstruction::DropToShellInPane(..) => PtyContext::DropToShellInPane, PtyInstruction::SpawnInPlaceTerminal(..) => PtyContext::SpawnInPlaceTerminal, PtyInstruction::DumpLayout(..) => PtyContext::DumpLayout, PtyInstruction::LogLayoutToHd(..) => PtyContext::LogLayoutToHd, @@ -532,6 +534,55 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box) -> Result<()> { }, } }, + PtyInstruction::DropToShellInPane(pane_id, default_shell) => { + let err_context = || format!("failed to rerun command in pane {:?}", pane_id); + + // TODO: get configured default_shell from screen/tab as an option and default to + // this otherwise (also look for a place that turns get_default_shell into a + // RunCommand, we might have done this before) + let run_command = RunCommand { + command: default_shell.unwrap_or_else(|| get_default_shell()), + hold_on_close: false, + hold_on_start: false, + // TODO: cwd + ..Default::default() + }; + match pty + .rerun_command_in_pane(pane_id, run_command.clone()) + .with_context(err_context) + { + Ok(..) => {}, + Err(err) => match err.downcast_ref::() { + Some(ZellijError::CommandNotFound { terminal_id, .. }) => { + if run_command.hold_on_close { + pty.bus + .senders + .send_to_screen(ScreenInstruction::PtyBytes( + *terminal_id, + format!( + "Command not found: {}", + run_command.command.display() + ) + .as_bytes() + .to_vec(), + )) + .with_context(err_context)?; + pty.bus + .senders + .send_to_screen(ScreenInstruction::HoldPane( + PaneId::Terminal(*terminal_id), + Some(2), // exit status + run_command, + None, + None, + )) + .with_context(err_context)?; + } + }, + _ => Err::<(), _>(err).non_fatal(), + }, + } + }, PtyInstruction::DumpLayout(mut session_layout_metadata, client_id) => { let err_context = || format!("Failed to dump layout"); pty.populate_session_layout_metadata(&mut session_layout_metadata); diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index 6b974ef8..58286185 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -1149,6 +1149,7 @@ impl Screen { self.terminal_emulator_colors.clone(), self.terminal_emulator_color_codes.clone(), swap_layouts, + self.default_shell.clone(), self.debug, ); self.tabs.insert(tab_index, tab); diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index 30a6bed8..f441e729 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -8,6 +8,7 @@ mod swap_layouts; use copy_command::CopyCommand; use std::env::temp_dir; +use std::path::PathBuf; use uuid::Uuid; use zellij_utils::data::{ Direction, PaneInfo, PermissionStatus, PermissionType, PluginPermission, ResizeStrategy, @@ -182,6 +183,7 @@ pub(crate) struct Tab { pending_instructions: Vec, // instructions that came while the tab was // pending and need to be re-applied swap_layouts: SwapLayouts, + default_shell: Option, debug: bool, } @@ -482,6 +484,7 @@ pub enum AdjustedInput { ReRunCommandInThisPane(RunCommand), PermissionRequestResult(Vec, PermissionStatus), CloseThisPane, + DropToShellInThisPane, } pub fn get_next_terminal_position( tiled_panes: &TiledPanes, @@ -528,6 +531,7 @@ impl Tab { terminal_emulator_colors: Rc>, terminal_emulator_color_codes: Rc>>, swap_layouts: (Vec, Vec), + default_shell: Option, debug: bool, ) -> Self { let name = if name.is_empty() { @@ -615,6 +619,7 @@ impl Tab { is_pending: true, // will be switched to false once the layout is applied pending_instructions: vec![], swap_layouts, + default_shell, debug, } } @@ -1695,6 +1700,16 @@ impl Tab { self.close_pane(PaneId::Terminal(active_terminal_id), false, None); should_update_ui = true; }, + Some(AdjustedInput::DropToShellInThisPane) => { + self.pids_waiting_resize.insert(active_terminal_id); + self.senders + .send_to_pty(PtyInstruction::DropToShellInPane( + PaneId::Terminal(active_terminal_id), + self.default_shell.clone(), + )) + .with_context(err_context)?; + should_update_ui = true; + }, Some(_) => {}, None => {}, } diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_floating_layout_is_included_in_swap_layouts.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_floating_layout_is_included_in_swap_layouts.snap index f6e33291..cd3f576f 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,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5472 +assertion_line: 6071 expression: snapshot --- 00 (C): ┌ tab-bar ────────────────────────────────────────┌ status-bar ──────────────────────────────────────────────┐──────────┐ @@ -19,7 +19,7 @@ expression: snapshot 13 (C): │ │ │ │ │ 14 (C): │ Waiting to ru└───────────────────│ Waiting to run: command2 │ │ 15 (C): │ │ │ │ -16 (C): │ to run, to exit │ to run, to exit │ │ +16 (C): │ run, drop to shell, e│ run, drop to shell, exit │ │ 17 (C): │ │ │ │ 18 (C): │ │ │ │ 19 (C): └─────────────────────────────────────────────────└──────────────────────────────────────────────────────────┘──────────┘ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_layout_is_included_in_swap_layouts.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__base_layout_is_included_in_swap_layouts.snap index 97692e66..440d15cb 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,5 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 5109 expression: snapshot --- 00 (C): I am a tab bar @@ -12,14 +13,14 @@ expression: snapshot 07 (C): │ ││ ││ │ 08 (C): │ Waiting to run: command2 ││ ││ Waiting to run: command1 │ 09 (C): │ ││ ││ │ -10 (C): │ to run, to exit ││ ││ to run, to exit │ -11 (C): │ ││ ││ │ +10 (C): │ run, drop to shell, run, drop to shell, exit ││ ││l-c> exit │ 12 (C): │ ││ ││ │ 13 (C): │ ││ ││ │ 14 (C): │ ││ ││ │ 15 (C): │ ││ ││ │ 16 (C): │ ││ ││ │ -17 (C): └───────────────────────────────────────┘└──────────────────────────────────────┘└─ to run, to exit ───┘ +17 (C): └───────────────────────────────────────┘└──────────────────────────────────────┘└──────────────────────────────────────┘ 18 (C): I am a 19 (C): status bar diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__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 39838348..10982475 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,6 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5926 +assertion_line: 5971 expression: snapshot --- 00 (C): ┌ status-bar ──────────────────────────────────────────────┐─────────────────────────────────────────────────┐──────────┐ @@ -19,7 +19,7 @@ expression: snapshot 13 (C): │ │ │ │ │ 14 (C): │ Waiting to ru└───────────────────│ Waiting to run: command2 │ │ 15 (C): │ │ │ │ -16 (C): │ to run, to exit │ to run, to exit │ │ +16 (C): │ run, drop to shell, e│ run, drop to shell, exit │ │ 17 (C): │ │ │ │ 18 (C): │ │ │ │ 19 (C): └─────────────────────────────────────────────────└──────────────────────────────────────────────────────────┘──────────┘ diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__layout_with_plugins_and_commands_swaped_properly.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__layout_with_plugins_and_commands_swaped_properly.snap index 4c31fe25..738ed813 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,5 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 5007 expression: snapshot --- 00 (C): I am a @@ -8,13 +9,13 @@ expression: snapshot 03 (C): │ │ 04 (C): │ Waiting to run: command1 │ 05 (C): │ │ -06 (C): │ to run, to exit │ -07 (C): └─ to run, to exit ────────────────────────────────────────────────────────────────────────────────────┘ +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 │ 11 (C): │ │ -12 (C): │ to run, to exit │ +12 (C): │ run, drop to shell, exit │ 13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 14 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 15 (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 29553797..8db6a06a 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,15 +1,15 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs -assertion_line: 5614 +assertion_line: 6269 expression: snapshot --- 00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 01 (C): │ │ -02 (C): │ ┌ command2 ────────────────────────────┐ │ -03 (C): │ │ │ │ +02 (C): │ ┌ command2 ────────────── SCROLL: 0/1 ┐ │ +03 (C): │ │ Waiting to run: command2 │ │ 04 (C): │ │ ┌ tab-bar ─────────────────────────────┐ │ -05 (C): │ │ │I am a tab bar ┌ status-bar ──────────────────────────────────────────────┐ │ -06 (C): │ │ │ │I am a │ │ +05 (C): │ │<│I am a tab bar ┌ status-bar ──────────────────────────────────────────────┐ │ +06 (C): │ │l│ │I am a │ │ 07 (C): │ └─│ │status bar │─┐ │ 08 (C): │ │ │ │ │ │ 09 (C): │ └─────────────────────────│ │───┐ │ @@ -18,7 +18,7 @@ expression: snapshot 12 (C): │ │ │ │ │ 13 (C): │ │ │ │ │ 14 (C): │ └──────────────────────────────────────────────────────────┘ │ │ -15 (C): │ │ │ to run, to exit │ │ +15 (C): │ │ │ run, drop to shell, exit │ │ 16 (C): │ └─│ │ │ 17 (C): │ │ │ │ 18 (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 edac6ec4..3ec04981 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,5 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 5307 expression: snapshot --- 00 (C): I am a @@ -14,12 +15,12 @@ expression: snapshot 09 (C): │ │ 10 (C): │ Waiting to run: command1 │ 11 (C): │ │ -12 (C): │ to run, to exit │ -13 (C): └─ to run, to exit ────────────────────────────────────────────────────────────────────────────────────┘ +12 (C): │ run, drop to shell, exit │ +13 (C): └─ run, drop to shell, exit ─────────────────────────────────────────────────────────────────────┘ 14 (C): ┌ command2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 15 (C): │ Waiting to run: command2 │ 16 (C): │ │ -17 (C): │ to run, to exit │ +17 (C): │ run, drop to shell, exit │ 18 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 19 (C): I am a tab bar diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_plugin_panes_present_in_existing_layout.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__swap_layouts_not_including_plugin_panes_present_in_existing_layout.snap index d5366c73..1c8c7f77 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,5 +1,6 @@ --- source: zellij-server/src/tab/./unit/tab_integration_tests.rs +assertion_line: 5481 expression: snapshot --- 00 (C): ┌ Pane #2 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ @@ -8,13 +9,13 @@ expression: snapshot 03 (C): │ │ 04 (C): │ Waiting to run: command1 │ 05 (C): │ │ -06 (C): │ to run, to exit │ -07 (C): └─ to run, to exit ────────────────────────────────────────────────────────────────────────────────────┘ +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 │ 11 (C): │ │ -12 (C): │ to run, to exit │ +12 (C): │ run, drop to shell, exit │ 13 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 14 (C): ┌ status-bar ───────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 15 (C): │I am a │ diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs index 7409bbc4..7574ee5e 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -245,6 +245,7 @@ fn create_new_tab(size: Size, default_mode: ModeInfo) -> Tab { terminal_emulator_colors, terminal_emulator_color_codes, (vec![], vec![]), + None, debug, ); tab.apply_layout( @@ -317,6 +318,7 @@ fn create_new_tab_with_swap_layouts( terminal_emulator_colors, terminal_emulator_color_codes, swap_layouts, + None, debug, ); let ( @@ -391,6 +393,7 @@ fn create_new_tab_with_os_api( terminal_emulator_colors, terminal_emulator_color_codes, (vec![], vec![]), // swap layouts + None, debug, ); tab.apply_layout( @@ -451,6 +454,7 @@ fn create_new_tab_with_layout(size: Size, default_mode: ModeInfo, layout: &str) terminal_emulator_colors, terminal_emulator_color_codes, (vec![], vec![]), // swap layouts + None, debug, ); let pane_ids = tab_layout @@ -525,6 +529,7 @@ fn create_new_tab_with_mock_pty_writer( terminal_emulator_colors, terminal_emulator_color_codes, (vec![], vec![]), // swap layouts + None, debug, ); tab.apply_layout( @@ -590,6 +595,7 @@ fn create_new_tab_with_sixel_support( terminal_emulator_colors, terminal_emulator_color_codes, (vec![], vec![]), // swap layouts + None, debug, ); tab.apply_layout( diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs index 8ba95967..7ba629b8 100644 --- a/zellij-server/src/tab/unit/tab_tests.rs +++ b/zellij-server/src/tab/unit/tab_tests.rs @@ -186,6 +186,7 @@ fn create_new_tab(size: Size) -> Tab { terminal_emulator_colors, terminal_emulator_color_codes, (vec![], vec![]), // swap layouts + None, debug, ); tab.apply_layout( @@ -243,6 +244,7 @@ fn create_new_tab_with_layout(size: Size, layout: TiledPaneLayout) -> Tab { terminal_emulator_colors, terminal_emulator_color_codes, (vec![], vec![]), // swap layouts + None, debug, ); let mut new_terminal_ids = vec![]; @@ -306,6 +308,7 @@ fn create_new_tab_with_cell_size( terminal_emulator_colors, terminal_emulator_color_codes, (vec![], vec![]), // swap layouts + None, debug, ); tab.apply_layout( diff --git a/zellij-server/src/ui/pane_boundaries_frame.rs b/zellij-server/src/ui/pane_boundaries_frame.rs index 94569cca..745786de 100644 --- a/zellij-server/src/ui/pane_boundaries_frame.rs +++ b/zellij-server/src/ui/pane_boundaries_frame.rs @@ -837,14 +837,20 @@ impl PaneFrame { let enter_text = "ENTER"; let right_enter_bracket = ">"; let enter_tip = if self.is_first_run { - " to run, " + " run, " } else { - " to re-run, " + " re-run, " }; + + let left_esc_bracket = "<"; + let esc_text = "ESC"; + let right_esc_bracket = ">"; + let esc_tip = " drop to shell, "; + let left_break_bracket = "<"; let break_text = "Ctrl-c"; let right_break_bracket = ">"; - let break_tip = " to exit "; + let break_tip = " exit "; second_part.append(&mut foreground_color(left_enter_bracket, self.color)); second_part.append(&mut foreground_color( enter_text, @@ -852,6 +858,15 @@ impl PaneFrame { )); second_part.append(&mut foreground_color(right_enter_bracket, self.color)); second_part.append(&mut foreground_color(enter_tip, self.color)); + + second_part.append(&mut foreground_color(left_esc_bracket, self.color)); + second_part.append(&mut foreground_color( + esc_text, + Some(self.style.colors.orange), + )); + second_part.append(&mut foreground_color(right_esc_bracket, self.color)); + second_part.append(&mut foreground_color(esc_tip, self.color)); + second_part.append(&mut foreground_color(left_break_bracket, self.color)); second_part.append(&mut foreground_color( break_text, @@ -865,6 +880,10 @@ impl PaneFrame { + enter_text.len() + right_enter_bracket.len() + enter_tip.len() + + left_esc_bracket.len() + + esc_text.len() + + right_esc_bracket.len() + + esc_tip.len() + left_break_bracket.len() + break_text.len() + right_break_bracket.len() diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index cee98391..2f5cfc2d 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -362,6 +362,7 @@ pub enum PtyContext { ClosePane, CloseTab, ReRunCommandInPane, + DropToShellInPane, SpawnInPlaceTerminal, DumpLayout, LogLayoutToHd,