mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-26 10:55:12 +03:00
feat(cli): allow starting a session detached (#3257)
* feat(cli): allow starting a session detached * fix tests
This commit is contained in:
parent
a0f48c6731
commit
e68bc649d6
@ -407,6 +407,7 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
let mut config_options = config_options.clone();
|
||||
let mut opts = opts.clone();
|
||||
let mut is_a_reconnect = false;
|
||||
let mut should_create_detached = false;
|
||||
|
||||
if let Some(reconnect_to_session) = &reconnect_to_session {
|
||||
// this is integration code to make session reconnects work with this existing,
|
||||
@ -417,6 +418,7 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
opts.command = Some(Command::Sessions(Sessions::Attach {
|
||||
session_name: reconnect_to_session.name.clone(),
|
||||
create: true,
|
||||
background: false,
|
||||
force_run_commands: false,
|
||||
index: None,
|
||||
options: None,
|
||||
@ -476,6 +478,7 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
if let Some(Command::Sessions(Sessions::Attach {
|
||||
session_name,
|
||||
create,
|
||||
background,
|
||||
force_run_commands,
|
||||
index,
|
||||
options,
|
||||
@ -487,9 +490,14 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
},
|
||||
None => config_options,
|
||||
};
|
||||
should_create_detached = background;
|
||||
|
||||
let client = if let Some(idx) = index {
|
||||
attach_with_session_index(config_options.clone(), idx, create)
|
||||
attach_with_session_index(
|
||||
config_options.clone(),
|
||||
idx,
|
||||
create || should_create_detached,
|
||||
)
|
||||
} else {
|
||||
let session_exists = session_name
|
||||
.as_ref()
|
||||
@ -497,7 +505,10 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
.unwrap_or(false);
|
||||
let resurrection_layout =
|
||||
session_name.as_ref().and_then(|s| resurrection_layout(&s));
|
||||
if create && !session_exists && resurrection_layout.is_none() {
|
||||
if (create || should_create_detached)
|
||||
&& !session_exists
|
||||
&& resurrection_layout.is_none()
|
||||
{
|
||||
session_name.clone().map(start_client_plan);
|
||||
}
|
||||
match (session_name.as_ref(), resurrection_layout) {
|
||||
@ -507,7 +518,11 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
}
|
||||
ClientInfo::Resurrect(session_name.clone(), resurrection_layout)
|
||||
},
|
||||
_ => attach_with_session_name(session_name, config_options.clone(), create),
|
||||
_ => attach_with_session_name(
|
||||
session_name,
|
||||
config_options.clone(),
|
||||
create || should_create_detached,
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
@ -541,6 +556,7 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
tab_position_to_focus,
|
||||
pane_id_to_focus,
|
||||
is_a_reconnect,
|
||||
should_create_detached,
|
||||
);
|
||||
} else {
|
||||
if let Some(session_name) = opts.session.clone() {
|
||||
@ -555,6 +571,7 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
None,
|
||||
None,
|
||||
is_a_reconnect,
|
||||
should_create_detached,
|
||||
);
|
||||
} else {
|
||||
if let Some(session_name) = config_options.session_name.as_ref() {
|
||||
@ -595,6 +612,7 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
None,
|
||||
None,
|
||||
is_a_reconnect,
|
||||
should_create_detached,
|
||||
);
|
||||
},
|
||||
_ => {
|
||||
@ -609,6 +627,7 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
None,
|
||||
None,
|
||||
is_a_reconnect,
|
||||
should_create_detached,
|
||||
);
|
||||
},
|
||||
}
|
||||
@ -632,6 +651,7 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||
None,
|
||||
None,
|
||||
is_a_reconnect,
|
||||
should_create_detached,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -138,8 +138,8 @@ fn pipe_client(
|
||||
let mut buffer = String::new();
|
||||
let _ = stdin.read_line(&mut buffer);
|
||||
if buffer.is_empty() {
|
||||
// TODO: consider notifying the relevant plugin that the pipe has ended with a
|
||||
// specialized message
|
||||
let msg = create_msg(None);
|
||||
os_input.send_to_server(msg);
|
||||
break;
|
||||
} else {
|
||||
// we've got data! send it down the pipe (most common)
|
||||
|
@ -29,6 +29,7 @@ use zellij_utils::{
|
||||
errors::{ClientContext, ContextType, ErrorInstruction},
|
||||
input::{config::Config, options::Options},
|
||||
ipc::{ClientAttributes, ClientToServerMsg, ExitReason, ServerToClientMsg},
|
||||
pane_size::Size,
|
||||
termwiz::input::InputEvent,
|
||||
};
|
||||
use zellij_utils::{cli::CliArgs, input::layout::Layout};
|
||||
@ -168,7 +169,12 @@ pub fn start_client(
|
||||
tab_position_to_focus: Option<usize>,
|
||||
pane_id_to_focus: Option<(u32, bool)>, // (pane_id, is_plugin)
|
||||
is_a_reconnect: bool,
|
||||
start_detached_and_exit: bool,
|
||||
) -> Option<ConnectToSession> {
|
||||
if start_detached_and_exit {
|
||||
start_server_detached(os_input, opts, config, config_options, info, layout);
|
||||
return None;
|
||||
}
|
||||
info!("Starting Zellij client!");
|
||||
|
||||
let mut reconnect_to_session = None;
|
||||
@ -541,6 +547,69 @@ pub fn start_client(
|
||||
reconnect_to_session
|
||||
}
|
||||
|
||||
pub fn start_server_detached(
|
||||
mut os_input: Box<dyn ClientOsApi>,
|
||||
opts: CliArgs,
|
||||
config: Config,
|
||||
config_options: Options,
|
||||
info: ClientInfo,
|
||||
layout: Option<Layout>,
|
||||
) {
|
||||
envs::set_zellij("0".to_string());
|
||||
config.env.set_vars();
|
||||
|
||||
let palette = config
|
||||
.theme_config(&config_options)
|
||||
.unwrap_or_else(|| os_input.load_palette());
|
||||
|
||||
let client_attributes = ClientAttributes {
|
||||
size: Size { rows: 50, cols: 50 }, // just so size is not 0, it doesn't matter because we
|
||||
// immediately detach
|
||||
style: Style {
|
||||
colors: palette,
|
||||
rounded_corners: config.ui.pane_frames.rounded_corners,
|
||||
hide_session_name: config.ui.pane_frames.hide_session_name,
|
||||
},
|
||||
keybinds: config.keybinds.clone(),
|
||||
};
|
||||
|
||||
let create_ipc_pipe = || -> std::path::PathBuf {
|
||||
let mut sock_dir = ZELLIJ_SOCK_DIR.clone();
|
||||
std::fs::create_dir_all(&sock_dir).unwrap();
|
||||
set_permissions(&sock_dir, 0o700).unwrap();
|
||||
sock_dir.push(envs::get_session_name().unwrap());
|
||||
sock_dir
|
||||
};
|
||||
|
||||
let (first_msg, ipc_pipe) = match info {
|
||||
ClientInfo::New(name) | ClientInfo::Resurrect(name, _) => {
|
||||
envs::set_session_name(name.clone());
|
||||
os_input.update_session_name(name);
|
||||
let ipc_pipe = create_ipc_pipe();
|
||||
|
||||
spawn_server(&*ipc_pipe, opts.debug).unwrap();
|
||||
|
||||
(
|
||||
ClientToServerMsg::NewClient(
|
||||
client_attributes,
|
||||
Box::new(opts),
|
||||
Box::new(config_options.clone()),
|
||||
Box::new(layout.unwrap()),
|
||||
Box::new(config.plugins.clone()),
|
||||
),
|
||||
ipc_pipe,
|
||||
)
|
||||
},
|
||||
_ => {
|
||||
eprintln!("Session already exists");
|
||||
std::process::exit(1);
|
||||
},
|
||||
};
|
||||
|
||||
os_input.connect_to_server(&*ipc_pipe);
|
||||
os_input.send_to_server(first_msg);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "./unit/stdin_tests.rs"]
|
||||
mod stdin_tests;
|
||||
|
@ -317,8 +317,8 @@ impl Clone for Box<dyn ClientOsApi> {
|
||||
}
|
||||
|
||||
pub fn get_client_os_input() -> Result<ClientOsInputOutput, nix::Error> {
|
||||
let current_termios = termios::tcgetattr(0)?;
|
||||
let orig_termios = Some(Arc::new(Mutex::new(current_termios)));
|
||||
let current_termios = termios::tcgetattr(0).ok();
|
||||
let orig_termios = current_termios.map(|termios| Arc::new(Mutex::new(termios)));
|
||||
let reading_from_stdin = Arc::new(Mutex::new(None));
|
||||
Ok(ClientOsInputOutput {
|
||||
orig_termios,
|
||||
|
@ -221,7 +221,7 @@ fn handle_openpty(
|
||||
fn handle_terminal(
|
||||
cmd: RunCommand,
|
||||
failover_cmd: Option<RunCommand>,
|
||||
orig_termios: termios::Termios,
|
||||
orig_termios: Option<termios::Termios>,
|
||||
quit_cb: Box<dyn Fn(PaneId, Option<i32>, RunCommand) + Send>,
|
||||
terminal_id: u32,
|
||||
) -> Result<(RawFd, RawFd)> {
|
||||
@ -229,7 +229,7 @@ fn handle_terminal(
|
||||
|
||||
// Create a pipe to allow the child the communicate the shell's pid to its
|
||||
// parent.
|
||||
match openpty(None, Some(&orig_termios)) {
|
||||
match openpty(None, &orig_termios) {
|
||||
Ok(open_pty_res) => handle_openpty(open_pty_res, cmd, quit_cb, terminal_id),
|
||||
Err(e) => match failover_cmd {
|
||||
Some(failover_cmd) => {
|
||||
@ -279,7 +279,7 @@ fn separate_command_arguments(command: &mut PathBuf, args: &mut Vec<String>) {
|
||||
/// set.
|
||||
fn spawn_terminal(
|
||||
terminal_action: TerminalAction,
|
||||
orig_termios: termios::Termios,
|
||||
orig_termios: Option<termios::Termios>,
|
||||
quit_cb: Box<dyn Fn(PaneId, Option<i32>, RunCommand) + Send>, // u32 is the exit_status
|
||||
default_editor: Option<PathBuf>,
|
||||
terminal_id: u32,
|
||||
@ -418,7 +418,7 @@ impl ClientSender {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ServerOsInputOutput {
|
||||
orig_termios: Arc<Mutex<termios::Termios>>,
|
||||
orig_termios: Arc<Mutex<Option<termios::Termios>>>,
|
||||
client_senders: Arc<Mutex<HashMap<ClientId, ClientSender>>>,
|
||||
terminal_id_to_raw_fd: Arc<Mutex<BTreeMap<u32, Option<RawFd>>>>, // A value of None means the
|
||||
// terminal_id exists but is
|
||||
@ -876,7 +876,10 @@ impl Clone for Box<dyn ServerOsApi> {
|
||||
}
|
||||
|
||||
pub fn get_server_os_input() -> Result<ServerOsInputOutput, nix::Error> {
|
||||
let current_termios = termios::tcgetattr(0)?;
|
||||
let current_termios = termios::tcgetattr(0).ok();
|
||||
if current_termios.is_none() {
|
||||
log::warn!("Starting a server without a controlling terminal, using the default termios configuration.");
|
||||
}
|
||||
let orig_termios = Arc::new(Mutex::new(current_termios));
|
||||
Ok(ServerOsInputOutput {
|
||||
orig_termios,
|
||||
|
@ -36,7 +36,7 @@ fn get_cwd() {
|
||||
termios::tcgetattr(test_terminal.slave()).expect("Could not configure the termios");
|
||||
|
||||
let server = ServerOsInputOutput {
|
||||
orig_termios: Arc::new(Mutex::new(test_termios)),
|
||||
orig_termios: Arc::new(Mutex::new(Some(test_termios))),
|
||||
client_senders: Arc::default(),
|
||||
terminal_id_to_raw_fd: Arc::default(),
|
||||
cached_resizes: Arc::default(),
|
||||
|
@ -125,6 +125,10 @@ pub enum Sessions {
|
||||
#[clap(short, long, value_parser)]
|
||||
create: bool,
|
||||
|
||||
/// Create a detached session in the background if one does not exist
|
||||
#[clap(short, long, value_parser)]
|
||||
background: bool,
|
||||
|
||||
/// Number of the session index in the active sessions ordered creation date.
|
||||
#[clap(long, value_parser)]
|
||||
index: Option<usize>,
|
||||
|
Loading…
Reference in New Issue
Block a user