use crate::{Tmux, TmuxCommands};
use std::borrow::Cow;
use std::fmt;
use std::process::Command;
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TmuxCommand<'a> {
pub envs: Option<Vec<(Cow<'a, str>, Cow<'a, str>)>>,
pub name: Option<Cow<'a, str>>,
pub alias: Option<Cow<'a, str>>,
pub flags: Option<Vec<Cow<'a, str>>>,
pub flags_short: Option<String>,
pub args: Option<Vec<Cow<'a, str>>>,
pub subcommands: Option<TmuxCommands<'a>>,
pub separator: Option<&'a str>,
pub flags_args_separator: Option<&'a str>,
pub combine_short_flags: bool,
pub use_alias: bool,
}
pub const EMPTY_CMD: &str = "";
pub const TMUX_COMMAND_ARG_SEPARATOR: &str = " ";
impl<'a> Default for TmuxCommand<'a> {
fn default() -> Self {
Self {
envs: None,
name: None,
alias: None,
flags: None,
flags_short: None,
args: None,
subcommands: None,
separator: None,
flags_args_separator: None,
combine_short_flags: true,
use_alias: true,
}
}
}
impl<'a> fmt::Display for TmuxCommand<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let output = self
.to_vec()
.join(self.separator.unwrap_or(TMUX_COMMAND_ARG_SEPARATOR));
write!(f, "{}", output)
}
}
impl<'a> TmuxCommand<'a> {
pub fn new() -> Self {
Default::default()
}
pub fn new_full<S: Into<Cow<'a, str>>>(name: S) -> Self {
Self {
name: Some(name.into()),
combine_short_flags: false,
use_alias: false,
..Default::default()
}
}
pub fn with_name<S: Into<Cow<'a, str>>>(name: S) -> Self {
Self {
name: Some(name.into()),
..Default::default()
}
}
pub fn with_alias<S: Into<Cow<'a, str>>>(alias: S) -> Self {
Self {
alias: Some(alias.into()),
..Default::default()
}
}
pub fn with_cmds(cmd_list: TmuxCommands<'a>) -> Self {
Self {
subcommands: Some(cmd_list),
..Default::default()
}
}
pub fn name<S: Into<Cow<'a, str>>>(&mut self, cmd: S) -> &mut Self {
self.name = Some(cmd.into());
self
}
pub fn alias<S: Into<Cow<'a, str>>>(&mut self, alias: S) -> &mut Self {
self.alias = Some(alias.into());
self
}
pub fn env<T, U>(&mut self, key: T, value: U) -> &mut Self
where
T: Into<Cow<'a, str>>,
U: Into<Cow<'a, str>>,
{
self.envs
.get_or_insert(Vec::new())
.push((key.into(), value.into()));
self
}
pub fn push_flag<S: Into<Cow<'a, str>>>(&mut self, flag: S) -> &mut Self {
self.args.get_or_insert(Vec::new()).push(flag.into());
self
}
pub fn push_flag_short(&mut self, flag: char) -> &mut Self {
self.flags_short.get_or_insert(String::new()).push(flag);
self
}
pub fn push_option<U, V>(&mut self, key: U, option: V) -> &mut Self
where
U: Into<Cow<'a, str>>,
V: Into<Cow<'a, str>>,
{
self.args
.get_or_insert(Vec::new())
.extend_from_slice(&[key.into(), option.into()]);
self
}
pub fn push_param<S: Into<Cow<'a, str>>>(&mut self, param: S) -> &mut Self {
self.args.get_or_insert(Vec::new()).push(param.into());
self
}
pub fn push_cmd(&mut self, cmd: TmuxCommand<'a>) -> &mut Self {
self.subcommands
.get_or_insert(TmuxCommands::new())
.push(cmd);
self
}
pub fn push_cmds(&mut self, cmd_list: TmuxCommands<'a>) -> &mut Self {
self.subcommands = Some(cmd_list);
self
}
pub fn arg<T, U>(&mut self, flag: T, opt: U) -> &mut Self
where
T: Into<Cow<'a, str>>,
U: Into<Cow<'a, str>>,
{
let v = self.args.get_or_insert(Vec::new());
v.push(flag.into());
v.push(opt.into());
self
}
pub fn opt<T, U>(&mut self, short: T, opt: U) -> &mut Self
where
T: Into<Cow<'a, str>>,
U: Into<Cow<'a, str>>,
{
let v = self.args.get_or_insert(Vec::new());
v.push(short.into());
v.push(opt.into());
self
}
pub fn param<T: Into<Cow<'a, str>>>(&mut self, param: T) -> &mut Self {
self.args.get_or_insert(Vec::new()).push(param.into());
self
}
pub fn combine_short_flags(&mut self) -> &mut Self {
self.combine_short_flags = true;
self
}
pub fn not_combine_short_flags(&mut self) -> &mut Self {
self.combine_short_flags = false;
self
}
pub fn combine_short_flags_ext(&mut self, state: bool) -> &mut Self {
self.combine_short_flags = state;
self
}
pub fn use_alias(&mut self) -> &mut Self {
self.use_alias = true;
self
}
pub fn not_use_alias(&mut self) -> &mut Self {
self.use_alias = false;
self
}
pub fn use_alias_ext(&mut self, state: bool) -> &mut Self {
self.use_alias = state;
self
}
pub fn to_vec(&self) -> Vec<Cow<'a, str>> {
let mut v: Vec<Cow<'a, str>> = Vec::new();
if let Some(envs) = &self.envs {
for (key, value) in envs {
v.push(Cow::Owned(format!("{}={}", key, value)));
}
}
if self.use_alias {
if let Some(alias) = &self.alias {
v.push(alias.clone());
} else if let Some(name) = &self.name {
v.push(name.clone());
}
} else if let Some(name) = &self.name {
v.push(name.clone());
}
if let Some(flags_short) = &self.flags_short {
if self.combine_short_flags {
v.push(Cow::Owned(format!("-{}", flags_short)));
} else {
for c in flags_short.chars() {
v.push(Cow::Owned(format!("-{}", c)));
}
}
}
if let Some(args) = &self.args {
v.extend(args.to_vec());
}
if let Some(cmds) = &self.subcommands {
v.extend(cmds.to_vec());
}
v
}
pub fn to_command(self) -> Command {
let name = self.name.as_ref().unwrap_or(&Cow::Borrowed(""));
let mut command = Command::new(name.as_ref());
if let Some(envs) = self.envs {
command.envs(
envs.iter()
.map(|(key, value)| (key.as_ref(), value.as_ref())),
);
}
if let Some(args) = self.args {
command.args(args.iter().map(|arg| arg.as_ref()));
}
if let Some(cmds) = self.subcommands {
command.args(cmds.to_vec().iter().map(|arg| arg.as_ref()));
}
command
}
}
impl<'a> From<&TmuxCommand<'a>> for Command {
fn from(cmd: &TmuxCommand) -> Self {
let name = cmd.name.as_ref().unwrap_or(&Cow::Borrowed(EMPTY_CMD));
let mut command = Command::new(name.as_ref());
if let Some(envs) = &cmd.envs {
command.envs(
envs.iter()
.map(|(key, value)| (key.as_ref(), value.as_ref())),
);
}
if let Some(args) = &cmd.args {
command.args(args.iter().map(|arg| arg.as_ref()));
}
if let Some(cmds) = &cmd.subcommands {
command.args(cmds.to_vec().iter().map(|arg| arg.as_ref()));
}
command
}
}
impl<'a> From<TmuxCommand<'a>> for Command {
fn from(cmd: TmuxCommand) -> Self {
Command::from(&cmd)
}
}
impl<'a> TmuxCommand<'a> {
pub fn add_command(mut self, command: TmuxCommand<'a>) -> Self {
self.push_cmd(command);
self
}
pub fn into_tmux(self) -> Tmux<'a> {
Tmux::new().command(self)
}
}