use anyhow::Result;
use clap::{Parser, Subcommand};
mod error;
mod hooks;
mod status;
mod tmux;
mod interactive;
use error::TmuxFzfError;
use tmux::TmuxClient;
use interactive::InteractiveSelector;
#[derive(Parser)]
#[command(name = "tango")]
#[command(about = "A CLI tool for managing tmux sessions - dance between your sessions!")]
#[command(version)]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
}
#[derive(Subcommand)]
enum Commands {
List,
Attach {
session: String,
},
Kill {
session: String,
},
New {
name: Option<String>,
},
Rename {
old_name: String,
new_name: String,
},
Hooks {
#[command(subcommand)]
action: HooksAction,
},
}
#[derive(Subcommand)]
enum HooksAction {
Install,
Uninstall,
Status,
}
fn check_dependencies() -> Result<(), TmuxFzfError> {
which::which("tmux")
.map_err(|_| TmuxFzfError::DependencyMissing("tmux".to_string()))?;
Ok(())
}
fn main() -> Result<()> {
let cli = Cli::parse();
check_dependencies()?;
if let Err(e) = run_cli(&cli) {
match e {
TmuxFzfError::UserCancelled => {
std::process::exit(0);
}
_ => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
}
Ok(())
}
fn run_cli(cli: &Cli) -> Result<(), TmuxFzfError> {
let mut tmux_client = TmuxClient::new();
match &cli.command {
Some(Commands::List) => {
let sessions = tmux_client.list_sessions()?;
if sessions.is_empty() {
println!("No tmux sessions found");
} else {
for session in sessions {
let status = if session.is_attached() { " (attached)" } else { "" };
println!("{}: {} windows{}", session.name, session.windows, status);
}
}
},
Some(Commands::Attach { session }) => {
tmux_client.attach_session(session)?;
},
Some(Commands::Kill { session }) => {
tmux_client.kill_session(session)?;
println!("Killed session '{}'", session);
},
Some(Commands::New { name }) => {
let session_name = tmux_client.new_session(name.as_deref())?;
println!("Created session '{}'", session_name);
},
Some(Commands::Rename { old_name, new_name }) => {
tmux_client.rename_session(old_name, new_name)?;
println!("Renamed session '{}' to '{}'", old_name, new_name);
},
Some(Commands::Hooks { action }) => {
let result = match action {
HooksAction::Install => hooks::install(),
HooksAction::Uninstall => hooks::uninstall(),
HooksAction::Status => hooks::status(),
};
result.map_err(|e| TmuxFzfError::TmuxError(e.to_string()))?;
},
None => {
hooks::ensure_installed();
let mut selector = InteractiveSelector::new();
selector.run()?;
}
}
Ok(())
}