use crate::error::{Result, TmuxrsError};
use std::path::Path;
use std::process::{Command, Stdio};
#[derive(Default)]
#[allow(dead_code)]
pub struct TmuxCommand {
args: Vec<String>,
}
impl TmuxCommand {
#[allow(dead_code)]
pub fn new() -> Self {
Self::default()
}
#[allow(dead_code)]
pub fn arg<S: Into<String>>(mut self, arg: S) -> Self {
self.args.push(arg.into());
self
}
#[allow(dead_code)]
pub fn execute(self) -> Result<String> {
let output = Command::new("tmux")
.args(&self.args)
.output()
.map_err(|e| TmuxrsError::TmuxError(format!("Failed to execute tmux: {e}")))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(TmuxrsError::TmuxError(stderr.to_string()));
}
Ok(String::from_utf8_lossy(&output.stdout).to_string())
}
#[allow(dead_code)]
pub fn execute_interactive(self) -> Result<()> {
let mut child = Command::new("tmux")
.args(&self.args)
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.map_err(|e| TmuxrsError::TmuxError(format!("Failed to execute tmux: {e}")))?;
let status = child
.wait()
.map_err(|e| TmuxrsError::TmuxError(format!("Failed to wait for tmux: {e}")))?;
if !status.success() {
return Err(TmuxrsError::TmuxError(format!(
"tmux command failed with exit code: {}",
status.code().unwrap_or(-1)
)));
}
Ok(())
}
#[allow(dead_code)]
pub fn session_exists(session_name: &str) -> Result<bool> {
let result = Self::new()
.arg("has-session")
.arg("-t")
.arg(session_name)
.execute();
match result {
Ok(_) => Ok(true),
Err(TmuxrsError::TmuxError(_)) => Ok(false), Err(e) => Err(e), }
}
#[allow(dead_code)]
pub fn new_session(session_name: &str, working_dir: &Path) -> Result<String> {
Self::new()
.arg("new-session")
.arg("-d") .arg("-s")
.arg(session_name)
.arg("-c")
.arg(working_dir.to_string_lossy().as_ref())
.execute()
}
#[allow(dead_code)]
pub fn new_window(
session_name: &str,
window_name: &str,
command: Option<&str>,
working_dir: Option<&Path>,
) -> Result<String> {
let mut cmd = Self::new()
.arg("new-window")
.arg("-t")
.arg(session_name)
.arg("-n")
.arg(window_name);
if let Some(dir) = working_dir {
cmd = cmd.arg("-c").arg(dir.to_string_lossy().as_ref());
}
if let Some(cmd_str) = command {
cmd = cmd.arg(cmd_str);
}
cmd.execute()
}
#[allow(dead_code)]
pub fn send_keys(session_name: &str, window_name: &str, keys: &str) -> Result<String> {
Self::new()
.arg("send-keys")
.arg("-t")
.arg(format!("{session_name}:{window_name}"))
.arg(keys)
.arg("Enter")
.execute()
}
#[allow(dead_code)]
pub fn send_keys_to_pane(
session_name: &str,
window_name: &str,
pane_index: usize,
keys: &str,
) -> Result<String> {
Self::new()
.arg("send-keys")
.arg("-t")
.arg(format!("{session_name}:{window_name}.{pane_index}"))
.arg(keys)
.arg("Enter")
.execute()
}
#[allow(dead_code)]
pub fn kill_session(session_name: &str) -> Result<String> {
Self::new()
.arg("kill-session")
.arg("-t")
.arg(session_name)
.execute()
}
#[allow(dead_code)]
pub fn split_window_horizontal(
session_name: &str,
window_name: &str,
command: &str,
working_dir: Option<&Path>,
) -> Result<String> {
let mut cmd = Self::new()
.arg("split-window")
.arg("-h") .arg("-t")
.arg(if window_name.is_empty() {
session_name.to_string()
} else {
format!("{session_name}:{window_name}")
});
if let Some(dir) = working_dir {
cmd = cmd.arg("-c").arg(dir.to_string_lossy().as_ref());
}
if !command.trim().is_empty() {
cmd = cmd.arg(command);
}
cmd.execute()
}
#[allow(dead_code)]
pub fn split_window_vertical(
session_name: &str,
window_name: &str,
command: &str,
working_dir: Option<&Path>,
) -> Result<String> {
let mut cmd = Self::new()
.arg("split-window")
.arg("-v") .arg("-t")
.arg(if window_name.is_empty() {
session_name.to_string()
} else {
format!("{session_name}:{window_name}")
});
if let Some(dir) = working_dir {
cmd = cmd.arg("-c").arg(dir.to_string_lossy().as_ref());
}
if !command.trim().is_empty() {
cmd = cmd.arg(command);
}
cmd.execute()
}
#[allow(dead_code)]
pub fn select_layout(session_name: &str, window_name: &str, layout: &str) -> Result<String> {
Self::new()
.arg("select-layout")
.arg("-t")
.arg(if window_name.is_empty() {
session_name.to_string()
} else {
format!("{session_name}:{window_name}")
})
.arg(layout)
.execute()
}
#[allow(dead_code)]
pub fn attach_session(session_name: &str) -> Result<()> {
Self::new()
.arg("attach-session")
.arg("-t")
.arg(session_name)
.execute_interactive()
}
}