summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2022-11-01 09:07:25 +0100
committerGitHub <noreply@github.com>2022-11-01 09:07:25 +0100
commitabc700fc4d10d61c969ad94fa520d7d9336dcf14 (patch)
treea2e6318c4fe3951236cfa758befce8b95393a26e
parent6d29c6951e4768cc6f2f3c7b1bbb708d79d860c9 (diff)
feat(command-panes): allow to start suspended (#1887)
* feat(command-panes): allow panes to start suspended * style(fmt): remove unused code * style(fmt): rustfmt
-rw-r--r--src/main.rs2
-rw-r--r--src/tests/e2e/cases.rs19
-rw-r--r--src/tests/e2e/remote_runner.rs3
-rw-r--r--src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap8
-rw-r--r--zellij-server/src/os_input_output.rs34
-rw-r--r--zellij-server/src/panes/floating_panes/mod.rs3
-rw-r--r--zellij-server/src/panes/grid.rs1
-rw-r--r--zellij-server/src/panes/terminal_character.rs117
-rw-r--r--zellij-server/src/panes/terminal_pane.rs52
-rw-r--r--zellij-server/src/panes/tiled_panes/mod.rs3
-rw-r--r--zellij-server/src/pty.rs179
-rw-r--r--zellij-server/src/screen.rs84
-rw-r--r--zellij-server/src/tab/mod.rs29
-rw-r--r--zellij-server/src/tab/unit/tab_integration_tests.rs16
-rw-r--r--zellij-server/src/tab/unit/tab_tests.rs4
-rw-r--r--zellij-server/src/ui/pane_boundaries_frame.rs33
-rw-r--r--zellij-server/src/unit/screen_tests.rs9
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_line_number.snap2
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap4
-rw-r--r--zellij-utils/src/cli.rs14
-rw-r--r--zellij-utils/src/input/actions.rs3
-rw-r--r--zellij-utils/src/input/command.rs5
-rw-r--r--zellij-utils/src/input/layout.rs11
-rw-r--r--zellij-utils/src/input/unit/layout_test.rs13
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_added_to_args_in_template.snap4
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__args_override_args_in_template.snap4
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_added_to_close_on_exit_in_template.snap2
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__close_on_exit_overrides_close_on_exit_in_template.snap2
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_added_to_cwd_in_template.snap4
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__cwd_override_cwd_in_template.snap4
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_pane_templates.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_and_tab_cwd_prepended_to_panes_with_and_without_cwd_in_tab_templates.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_given_to_panes_without_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_passed_from_layout_constructor_overrides_global_cwd_in_layout_file.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_prepended_to_panes_with_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__global_cwd_with_tab_cwd_given_to_panes_without_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_close_on_exit.snap1
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_command_panes_and_start_suspended.snap42
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__layout_with_tab_and_pane_templates.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_is_overriden_by_its_consumers_bare_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_overriden_by_its_consumers_command_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_with_cwd_remains_when_its_consumer_command_does_not_have_a_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_is_overriden_by_its_consumers_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_command_without_cwd_receives_its_consumers_bare_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_with_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__pane_template_with_bare_propagated_to_its_consumer_command_without_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_given_to_panes_without_cwd.snap3
-rw-r--r--zellij-utils/src/input/unit/snapshots/zellij_utils__input__layout__layout_test__tab_cwd_prepended_to_panes_with_cwd.snap3
-rw-r--r--zellij-utils/src/kdl/kdl_layout_parser.rs28
-rw-r--r--zellij-utils/src/kdl/mod.rs47
52 files changed, 668 insertions, 172 deletions
diff --git a/src/main.rs b/src/main.rs
index 3ed592c53..6203f0f16 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -26,6 +26,7 @@ fn main() {
floating,
name,
close_on_exit,
+ start_suspended,
})) = opts.command
{
let command_cli_action = CliAction::NewPane {
@@ -35,6 +36,7 @@ fn main() {
floating,
name,
close_on_exit,
+ start_suspended,
};
commands::send_action_to_session(command_cli_action, opts.session);
std::process::exit(0);
diff --git a/src/tests/e2e/cases.rs b/src/tests/e2e/cases.rs
index 44551d997..359d74162 100644
--- a/src/tests/e2e/cases.rs
+++ b/src/tests/e2e/cases.rs
@@ -1915,6 +1915,25 @@ pub fn send_command_through_the_cli() {
},
})
.add_step(Step {
+ name: "Initial run of suspended command",
+ instruction: |mut remote_terminal: RemoteTerminal| -> bool {
+ let mut step_is_complete = false;
+ if remote_terminal.snapshot_contains("<Ctrl-c>")
+ && remote_terminal.cursor_position_is(0, 0)
+ // cursor does not appear in
+ // suspend_start panes
+ {
+ remote_terminal.send_key(&SPACE); // run script - here we use SPACE
+ // instead of the default ENTER because
+ // sending ENTER over SSH can be a little
+ // problematic (read: I couldn't get it
+ // to pass consistently)
+ step_is_complete = true
+ }
+ step_is_complete
+ },
+ })
+ .add_step(Step {
name: "Wait for command to run",
instruction: |mut remote_terminal: RemoteTerminal| -> bool {
let mut step_is_complete = false;
diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs
index dd2c800da..9b007989c 100644
--- a/src/tests/e2e/remote_runner.rs
+++ b/src/tests/e2e/remote_runner.rs
@@ -346,7 +346,8 @@ impl RemoteTerminal {
let mut channel = self.channel.lock().unwrap();
channel
.write_all(
- format!("{} run -- \"{}\"\n", ZELLIJ_EXECUTABLE_LOCATION, command).as_bytes(),
+ // note that this is run with the -s flag that suspends the command on startup
+ format!("{} run -s -- \"{}\"\n", ZELLIJ_EXECUTABLE_LOCATION, command).as_bytes(),
)
.unwrap();
channel.flush().unwrap();
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 84d33a037..0603ac26e 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,14 +1,14 @@
---
source: src/tests/e2e/cases.rs
-assertion_line: 1968
+assertion_line: 1998
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 -- "/usr/src/zellij/fixtures/append-echo-script.sh" ││foo │
-│$ ││█ │
-│ ││ │
+│ run -s -- "/usr/src/zellij/fixtures/append-echo-script.sh││foo │
+│" ││█ │
+│$ ││ │
│ ││ │
│ ││ │
│ ││ │
diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs
index 9a8ce0088..02f53dbe5 100644
--- a/zellij-server/src/os_input_output.rs
+++ b/zellij-server/src/os_input_output.rs
@@ -280,6 +280,7 @@ fn spawn_terminal(
args,
cwd: None,
hold_on_close: false,
+ hold_on_start: false,
}
},
TerminalAction::RunCommand(command) => command,
@@ -381,6 +382,10 @@ pub trait ServerOsApi: Send + Sync {
quit_cb: Box<dyn Fn(PaneId, Option<i32>, RunCommand) + Send>, // u32 is the exit status
default_editor: Option<PathBuf>,
) -> Result<(u32, RawFd, RawFd), SpawnTerminalError>;
+ // reserves a terminal id without actually opening a terminal
+ fn reserve_terminal_id(&self) -> Result<u32, SpawnTerminalError> {
+ unimplemented!()
+ }
/// Read bytes from the standard output of the virtual terminal referred to by `fd`.
fn read_from_tty_stdout(&self, fd: RawFd, buf: &mut [u8]) -> Result<usize, nix::Error>;
/// Creates an `AsyncReader` that can be used to read from `fd` in an async context
@@ -484,6 +489,35 @@ impl ServerOsApi for ServerOsInputOutput {
None => Err(SpawnTerminalError::NoMoreTerminalIds),
}
}
+ fn reserve_terminal_id(&self) -> Result<u32, SpawnTerminalError> {
+ let mut terminal_id = None;
+ {
+ let current_ids: HashSet<u32> = self
+ .terminal_id_to_raw_fd
+ .lock()
+ .unwrap()
+ .keys()
+ .copied()
+ .collect();
+ for i in 0..u32::MAX {
+ let i = i as u32;
+ if !current_ids.contains(&i) {
+ terminal_id = Some(i);
+ break;
+ }
+ }
+ }
+ match terminal_id {
+ Some(terminal_id) => {
+ self.terminal_id_to_raw_fd
+ .lock()
+ .unwrap()
+ .insert(terminal_id, None);
+ Ok(terminal_id)
+ },
+ None => Err(SpawnTerminalError::NoMoreTerminalIds),
+ }
+ }
fn read_from_tty_stdout(&self, fd: RawFd, buf: &mut [u8]) -> Result<usize, nix::Error> {
unistd::read(fd, buf)
}
diff --git a/zellij-server/src/panes/floating_panes/mod.rs b/zellij-server/src/panes/floating_panes/mod.rs
index f686f40bb..d17be7557 100644
--- a/zellij-server/src/panes/floating_panes/mod.rs
+++ b/zellij-server/src/panes/floating_panes/mod.rs
@@ -156,11 +156,12 @@ impl FloatingPanes {
&mut self,
pane_id: PaneId,
exit_status: Option<i32>,
+ is_first_run: bool,
run_command: RunCommand,
) {
self.panes
.get_mut(&pane_id)
- .map(|p| p.hold(exit_status, run_command));
+ .map(|p| p.hold(exit_status, is_first_run, run_command));
}
pub fn get(&self, pane_id: &PaneId) -> Option<&Box<dyn Pane>> {
self.panes.get(pane_id)
diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs
index 67a882fb4..d9d60fefe 100644
--- a/zellij-server/src/panes/grid.rs
+++ b/zellij-server/src/panes/grid.rs
@@ -1533,6 +1533,7 @@ impl Grid {
self.sixel_scrolling = false;
self.mouse_mode = MouseMode::NoEncoding;
self.mouse_tracking = MouseTracking::Off;
+ self.cursor_is_hidden = false;
if let Some(images_to_reap) = self.sixel_grid.clear() {
self.sixel_grid.reap_images(images_to_reap);
}
diff --git a/zellij-server/src/panes/terminal_character.rs b/zellij-server/src/panes/terminal_character.rs
index c6fa0adf1..68813e7a9 100644
--- a/zellij-server/src/panes/terminal_character.rs
+++ b/zellij-server/src/panes/terminal_character.rs
@@ -3,7 +3,12 @@ use std::fmt::{self, Debug, Display, Formatter};
use std::ops::{Index, IndexMut};
use unicode_width::UnicodeWidthChar;
-use zellij_utils::{data::PaletteColor, vte::ParamsIter};
+use unicode_width::UnicodeWidthStr;
+use zellij_utils::input::command::RunCommand;
+use zellij_utils::{
+ data::{PaletteColor, Style},
+ vte::ParamsIter,
+};
use crate::panes::alacritty_functions::parse_sgr_color;
@@ -736,3 +741,113 @@ impl ::std::fmt::Debug for TerminalCharacter {
write!(f, "{}", self.character)
}
}
+
+pub fn render_first_run_banner(
+ columns: usize,
+ rows: usize,
+ style: &Style,
+ run_command: Option<&RunCommand>,
+) -> String {
+ let middle_row = rows / 2;
+ let middle_column = columns / 2;
+ match run_command {
+ Some(run_command) => {
+ let bold_text = RESET_STYLES.bold(Some(AnsiCode::On));
+ let command_color_text = RESET_STYLES
+ .foreground(Some(AnsiCode::from(style.colors.green)))
+ .bold(Some(AnsiCode::On));
+ let waiting_to_run_text = "Waiting to run: ";
+ let command_text = run_command.to_string();
+ let waiting_to_run_text_width = waiting_to_run_text.width() + command_text.width();
+ let column_start_postion = middle_column.saturating_sub(waiting_to_run_text_width / 2);
+ let waiting_to_run_line = format!(
+ "\u{1b}[{};{}H{}{}{}{}{}",
+ middle_row,
+ column_start_postion,
+ bold_text,
+ waiting_to_run_text,
+ command_color_text,
+ command_text,
+ RESET_STYLES
+ );
+
+ let controls_bare_text_first_part = "<";
+ let enter_bare_text = "ENTER";
+ let controls_bare_text_second_part = "> to run, <";
+ let ctrl_c_bare_text = "Ctrl-c";
+ let controls_bare_text_third_part = "> to 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()
+ + ctrl_c_bare_text.len()
+ + controls_bare_text_third_part.len();