use super::*;
use crate::compat::queue::tailq_foreach;
use crate::compat::tree::rb_empty;
pub static CMD_ATTACH_SESSION_ENTRY: cmd_entry = cmd_entry {
name: "attach-session",
alias: Some("attach"),
args: args_parse::new("c:dEf:rt:x", 0, 0, None),
usage: "[-dErx] [-c working-directory] [-f flags] [-t target-session]",
flags: cmd_flag::CMD_STARTSERVER.union(cmd_flag::CMD_READONLY),
exec: cmd_attach_session_exec,
source: cmd_entry_flag::zeroed(),
target: cmd_entry_flag::zeroed(),
};
pub unsafe fn cmd_attach_session(
item: *mut cmdq_item,
tflag: Option<&str>,
dflag: bool,
xflag: bool,
rflag: bool,
cflag: *const u8,
eflag: bool,
fflag: *const u8,
) -> cmd_retval {
unsafe {
let current: *mut cmd_find_state = cmdq_get_current(item);
let mut target: cmd_find_state = zeroed(); let c: *mut client = cmdq_get_client(item);
let cwd: *mut u8;
let mut cause: *mut u8 = null_mut();
let msgtype: msgtype;
if rb_empty(&raw mut SESSIONS) {
cmdq_error!(item, "no sessions");
return cmd_retval::CMD_RETURN_ERROR;
}
if c.is_null() {
return cmd_retval::CMD_RETURN_NORMAL;
}
if server_client_check_nested(c) {
cmdq_error!(
item,
"sessions should be nested with care, unset $TMUX to force",
);
return cmd_retval::CMD_RETURN_ERROR;
}
let (type_, flags) =
if tflag.is_some_and(|tflag| !tflag.trim_start_matches([':', '.']).is_empty()) {
(cmd_find_type::CMD_FIND_PANE, cmd_find_flags::empty())
} else {
(
cmd_find_type::CMD_FIND_SESSION,
cmd_find_flags::CMD_FIND_PREFER_UNATTACHED,
)
};
if cmd_find_target(&raw mut target, item, tflag, type_, flags) != 0 {
return cmd_retval::CMD_RETURN_ERROR;
}
let s = target.s;
let wl = target.wl;
let wp = target.wp;
if !wl.is_null() {
if !wp.is_null() {
window_set_active_pane((*wp).window, wp, 1);
}
session_set_current(s, wl);
if !wp.is_null() {
cmd_find_from_winlink_pane(current, wl, wp, cmd_find_flags::empty());
} else {
cmd_find_from_winlink(current, wl, cmd_find_flags::empty());
}
}
if !cflag.is_null() {
cwd = format_single(item, cstr_to_str(cflag), c, s, wl, wp);
(*s).cwd = Some(std::ffi::CString::from_raw(cwd.cast()));
}
if !fflag.is_null() {
server_client_set_flags(c, fflag);
}
if rflag {
(*c).flags |= client_flag::READONLY | client_flag::IGNORESIZE;
}
(*c).last_session = (*c).session;
if !(*c).session.is_null() {
if dflag || xflag {
if xflag {
msgtype = msgtype::MSG_DETACHKILL;
} else {
msgtype = msgtype::MSG_DETACH;
}
for c_loop in tailq_foreach(&raw mut CLIENTS).map(NonNull::as_ptr) {
{
if (*c_loop).session != s || c == c_loop {
continue;
}
server_client_detach(c_loop, msgtype);
}
}
}
if !eflag {
environ_update((*s).options, (*c).environ, (*s).environ);
}
server_client_set_session(c, s);
if !cmdq_get_flags(item).intersects(cmdq_state_flags::CMDQ_STATE_REPEAT) {
server_client_set_key_table(c, null_mut());
}
} else {
if server_client_open(c, &raw mut cause) != 0 {
cmdq_error!(item, "open terminal failed: {}", _s(cause));
free_(cause);
return cmd_retval::CMD_RETURN_ERROR;
}
if dflag || xflag {
msgtype = if xflag {
msgtype::MSG_DETACHKILL
} else {
msgtype::MSG_DETACH
};
for c_loop in tailq_foreach(&raw mut CLIENTS).map(NonNull::as_ptr) {
if (*c_loop).session != s || c == c_loop {
continue;
}
server_client_detach(c_loop, msgtype);
}
}
if !eflag {
environ_update((*s).options, (*c).environ, (*s).environ);
}
server_client_set_session(c, s);
server_client_set_key_table(c, null_mut());
if !(*c).flags.intersects(client_flag::CONTROL) {
proc_send((*c).peer, msgtype::MSG_READY, -1, null_mut(), 0);
}
notify_client(c"client-attached", c);
(*c).flags |= client_flag::ATTACHED;
if CFG_FINISHED.load(atomic::Ordering::Acquire) {
cfg_show_causes(s);
}
}
cmd_retval::CMD_RETURN_NORMAL
}
}
unsafe fn cmd_attach_session_exec(self_: *mut cmd, item: *mut cmdq_item) -> cmd_retval {
unsafe {
let args = cmd_get_args(self_);
cmd_attach_session(
item,
cstr_to_str_(args_get(args, b't')),
args_has(args, 'd'),
args_has(args, 'x'),
args_has(args, 'r'),
args_get(args, b'c'),
args_has(args, 'E'),
args_get(args, b'f'),
)
}
}