From 491615d38f0c944b0c2243ff35be283ed11968e2 Mon Sep 17 00:00:00 2001 From: Ben LeFevre Date: Tue, 19 Dec 2023 13:55:50 +1100 Subject: [PATCH] feat: allow RunCommand to block calling terminal until command has exited --- src/commands.rs | 12 +++++++++++- src/main.rs | 3 +++ zellij-client/src/cli_client.rs | 10 +++++++++- zellij-client/src/lib.rs | 3 +++ zellij-server/src/lib.rs | 12 ++++++++++++ zellij-server/src/pty.rs | 1 + zellij-server/src/unit/screen_tests.rs | 3 +++ zellij-utils/src/cli.rs | 16 ++++++++++++++++ zellij-utils/src/errors.rs | 2 ++ zellij-utils/src/input/actions.rs | 1 + zellij-utils/src/ipc.rs | 1 + 11 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 52dff211b9..39ccfc7d35 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -296,9 +296,19 @@ fn attach_with_cli_client( ) { let os_input = get_os_input(zellij_client::os_input_output::get_cli_client_os_input); let get_current_dir = || std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); + let blocking = match cli_action { + zellij_utils::cli::CliAction::NewPane { blocking, .. } => blocking, + _ => false, + }; + match Action::actions_from_cli(cli_action, Box::new(get_current_dir), config) { Ok(actions) => { - zellij_client::cli_client::start_cli_client(Box::new(os_input), session_name, actions); + zellij_client::cli_client::start_cli_client( + Box::new(os_input), + session_name, + actions, + blocking, + ); std::process::exit(0); }, Err(e) => { diff --git a/src/main.rs b/src/main.rs index 871d468fe7..201c18fa35 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,7 @@ fn main() { in_place, name, close_on_exit, + blocking, start_suspended, x, y, @@ -46,6 +47,7 @@ fn main() { in_place, name, close_on_exit, + blocking, start_suspended, configuration: None, skip_plugin_cache, @@ -79,6 +81,7 @@ fn main() { in_place, name: None, close_on_exit: false, + blocking: false, start_suspended: false, configuration, skip_plugin_cache, diff --git a/zellij-client/src/cli_client.rs b/zellij-client/src/cli_client.rs index 38d73a4cca..b893f90fec 100644 --- a/zellij-client/src/cli_client.rs +++ b/zellij-client/src/cli_client.rs @@ -17,6 +17,7 @@ pub fn start_cli_client( mut os_input: Box, session_name: &str, actions: Vec, + blocking: bool, ) { let zellij_ipc_pipe: PathBuf = { let mut sock_dir = zellij_utils::consts::ZELLIJ_SOCK_DIR.clone(); @@ -64,7 +65,7 @@ pub fn start_cli_client( ); }, action => { - single_message_client(&mut os_input, action, pane_id); + single_message_client(&mut os_input, action, pane_id, blocking); }, } } @@ -186,12 +187,19 @@ fn single_message_client( os_input: &mut Box, action: Action, pane_id: Option, + blocking: bool, ) { let msg = ClientToServerMsg::Action(action, pane_id, None); os_input.send_to_server(msg); loop { match os_input.recv_from_server() { Some((ServerToClientMsg::UnblockInputThread, _)) => { + if !blocking { + os_input.send_to_server(ClientToServerMsg::ClientExited); + process::exit(0); + } + }, + Some((ServerToClientMsg::RunCommandComplete, _)) => { os_input.send_to_server(ClientToServerMsg::ClientExited); process::exit(0); }, diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs index 640cbcd80a..f1a34f5402 100644 --- a/zellij-client/src/lib.rs +++ b/zellij-client/src/lib.rs @@ -39,6 +39,7 @@ pub(crate) enum ClientInstruction { Error(String), Render(String), UnblockInputThread, + RunCommandComplete, Exit(ExitReason), SwitchToMode(InputMode), Connected, @@ -59,6 +60,7 @@ impl From for ClientInstruction { ServerToClientMsg::Exit(e) => ClientInstruction::Exit(e), ServerToClientMsg::Render(buffer) => ClientInstruction::Render(buffer), ServerToClientMsg::UnblockInputThread => ClientInstruction::UnblockInputThread, + ServerToClientMsg::RunCommandComplete => ClientInstruction::RunCommandComplete, ServerToClientMsg::SwitchToMode(input_mode) => { ClientInstruction::SwitchToMode(input_mode) }, @@ -86,6 +88,7 @@ impl From<&ClientInstruction> for ClientContext { ClientInstruction::Error(_) => ClientContext::Error, ClientInstruction::Render(_) => ClientContext::Render, ClientInstruction::UnblockInputThread => ClientContext::UnblockInputThread, + ClientInstruction::RunCommandComplete => ClientContext::RunCommandComplete, ClientInstruction::SwitchToMode(_) => ClientContext::SwitchToMode, ClientInstruction::Connected => ClientContext::Connected, ClientInstruction::ActiveClients(_) => ClientContext::ActiveClients, diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index 0089557055..0ac1b9d5c3 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -70,6 +70,7 @@ pub enum ServerInstruction { ), Render(Option>), UnblockInputThread, + RunCommandComplete, ClientExit(ClientId), RemoveClient(ClientId), Error(String), @@ -102,6 +103,7 @@ impl From<&ServerInstruction> for ServerContext { ServerInstruction::NewClient(..) => ServerContext::NewClient, ServerInstruction::Render(..) => ServerContext::Render, ServerInstruction::UnblockInputThread => ServerContext::UnblockInputThread, + ServerInstruction::RunCommandComplete => ServerContext::RunCommandComplete, ServerInstruction::ClientExit(..) => ServerContext::ClientExit, ServerInstruction::RemoveClient(..) => ServerContext::RemoveClient, ServerInstruction::Error(_) => ServerContext::Error, @@ -571,6 +573,16 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { }, } }, + ServerInstruction::RunCommandComplete => { + for client_id in session_state.read().unwrap().clients.keys() { + send_to_client!( + *client_id, + os_input, + ServerToClientMsg::RunCommandComplete, + session_state + ); + } + }, ServerInstruction::ClientExit(client_id) => { let _ = os_input.send_to_client(client_id, ServerToClientMsg::Exit(ExitReason::Normal)); diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index 0f9001a2fb..ef317dbf43 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -820,6 +820,7 @@ impl Pty { let quit_cb = Box::new({ let senders = self.bus.senders.clone(); move |pane_id, exit_status, command| { + let _ = senders.send_to_server(ServerInstruction::RunCommandComplete); if hold_on_close { let _ = senders.send_to_screen(ScreenInstruction::HoldPane( pane_id, diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index dc8939e6f8..88e01bd2da 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -2108,6 +2108,7 @@ pub fn send_cli_new_pane_action_with_default_parameters() { in_place: false, name: None, close_on_exit: false, + blocking: false, start_suspended: false, configuration: None, skip_plugin_cache: false, @@ -2151,6 +2152,7 @@ pub fn send_cli_new_pane_action_with_split_direction() { in_place: false, name: None, close_on_exit: false, + blocking: false, start_suspended: false, configuration: None, skip_plugin_cache: false, @@ -2194,6 +2196,7 @@ pub fn send_cli_new_pane_action_with_command_and_cwd() { in_place: false, name: None, close_on_exit: false, + blocking: false, start_suspended: false, configuration: None, skip_plugin_cache: false, diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index 595293f4e7..3806f3f842 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -213,6 +213,10 @@ pub enum Sessions { #[clap(short, long, value_parser, default_value("false"), takes_value(false))] close_on_exit: bool, + /// Block the calling terminal until the run command exits + #[clap(short, long, value_parser, default_value("false"), takes_value(false))] + blocking: bool, + /// Start the command suspended, only running after you first presses ENTER #[clap(short, long, value_parser, default_value("false"), takes_value(false))] start_suspended: bool, @@ -483,6 +487,18 @@ pub enum CliAction { requires("command") )] close_on_exit: bool, + + /// Block the calling terminal until the run command exits + #[clap( + short, + long, + value_parser, + default_value("false"), + takes_value(false), + requires("command") + )] + blocking: bool, + /// Start the command suspended, only running it after the you first press ENTER #[clap( short, diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 0677f611f4..7ec1d00bfd 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -408,6 +408,7 @@ pub enum ClientContext { Exit, Error, UnblockInputThread, + RunCommandComplete, Render, ServerError, SwitchToMode, @@ -430,6 +431,7 @@ pub enum ServerContext { NewClient, Render, UnblockInputThread, + RunCommandComplete, ClientExit, RemoveClient, Error, diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index b19529e48f..62ab3567c8 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -339,6 +339,7 @@ impl Action { in_place, name, close_on_exit, + blocking: _, start_suspended, configuration, skip_plugin_cache, diff --git a/zellij-utils/src/ipc.rs b/zellij-utils/src/ipc.rs index 902d023529..625f93929b 100644 --- a/zellij-utils/src/ipc.rs +++ b/zellij-utils/src/ipc.rs @@ -96,6 +96,7 @@ pub enum ClientToServerMsg { pub enum ServerToClientMsg { Render(String), UnblockInputThread, + RunCommandComplete, Exit(ExitReason), SwitchToMode(InputMode), Connected,