use anyhow::Result;
use crate::cli::kill;
use crate::cli::tree_view::{self, SelectedAction};
use crate::config::Project;
use crate::git;
use crate::tmux::{self, SessionBuilder};
use crate::ui;
pub fn create(project_name: Option<String>, branch: Option<String>) -> Result<()> {
let name = match project_name {
Some(n) => n,
None => ui::select_project("Select project for worktree...")?
.ok_or_else(|| anyhow::anyhow!("No project selected"))?,
};
let branch_name = match branch {
Some(b) => b,
None => ui::input("Branch name", "Enter branch name...", None)?
.ok_or_else(|| anyhow::anyhow!("Branch name is required"))?,
};
create_and_start(&name, &branch_name)
}
fn create_and_start(project_name: &str, branch_name: &str) -> Result<()> {
let project = Project::load(project_name)?;
println!(
"Creating worktree for '{}' on branch '{}'...",
project_name, branch_name
);
let worktree_path = git::create_worktree(&project, branch_name)?;
println!("Created worktree at: {:?}", worktree_path);
let session_name = project.worktree_session_name(branch_name);
if tmux::session_exists(&session_name)? {
println!("Session '{}' already exists, attaching...", session_name);
tmux::connect_to_session(&session_name)?;
return Ok(());
}
println!("Starting session '{}'...", session_name);
let builder = SessionBuilder::new(&project)
.with_session_name(session_name.clone())
.with_root(worktree_path.to_string_lossy().to_string())
.with_worktree(branch_name.to_string());
builder.start_with_control()?;
tmux::connect_to_session(&session_name)?;
Ok(())
}
pub fn list(project_name: Option<String>) -> Result<()> {
let action = tree_view::run(project_name, false)?;
match action {
Some(SelectedAction::StartProject(name)) => start_project_session(&name),
Some(SelectedAction::StartWorktree { project, branch }) => {
start_worktree_session(&project, &branch)
}
Some(SelectedAction::KillProject(name)) => kill::run(Some(name)),
Some(SelectedAction::KillWorktree { project, branch }) => {
let session_name = format!("{}__{}", project, branch);
kill::run(Some(session_name))
}
None => Ok(()), }
}
fn start_project_session(name: &str) -> Result<()> {
let project = Project::load(name)?;
if tmux::session_exists(&project.name)? {
println!("Session '{}' already exists, attaching...", project.name);
tmux::connect_to_session(&project.name)?;
return Ok(());
}
project.clone_if_needed()?;
println!("Starting session '{}'...", project.name);
SessionBuilder::new(&project).start_with_control()?;
tmux::connect_to_session(&project.name)?;
Ok(())
}
fn start_worktree_session(project_name: &str, branch: &str) -> Result<()> {
let project = Project::load(project_name)?;
let session_name = project.worktree_session_name(branch);
if tmux::session_exists(&session_name)? {
println!("Session '{}' already exists, attaching...", session_name);
tmux::connect_to_session(&session_name)?;
return Ok(());
}
let worktrees = git::list_worktrees(&project)?;
let worktree = worktrees
.iter()
.find(|wt| wt.branch == branch)
.ok_or_else(|| anyhow::anyhow!("Worktree '{}' not found", branch))?;
println!("Starting session '{}'...", session_name);
SessionBuilder::new(&project)
.with_session_name(session_name.clone())
.with_root(worktree.path.to_string_lossy().to_string())
.with_worktree(branch.to_string())
.start_with_control()?;
tmux::connect_to_session(&session_name)?;
Ok(())
}
pub fn delete(project_name: Option<String>, branch: Option<String>) -> Result<()> {
let name = match project_name {
Some(n) => n,
None => ui::select_project("Select project...")?
.ok_or_else(|| anyhow::anyhow!("No project selected"))?,
};
let project = Project::load(&name)?;
let branch_name = match branch {
Some(b) => b,
None => ui::select_worktree(&project, "Select worktree to delete...")?
.ok_or_else(|| anyhow::anyhow!("No worktree selected"))?,
};
if !ui::confirm(&format!(
"Delete worktree '{}' for project '{}'?",
branch_name, name
))? {
println!("Cancelled.");
return Ok(());
}
let session_name = project.worktree_session_name(&branch_name);
if tmux::session_exists(&session_name)? {
println!("Stopping session '{}'...", session_name);
tmux::safe_kill_session(&session_name)?;
}
println!("Deleting worktree...");
git::delete_worktree(&project, &branch_name)?;
println!("Deleted worktree: {}", branch_name);
Ok(())
}
pub fn merge(project_name: Option<String>, branch: Option<String>) -> Result<()> {
let name = match project_name {
Some(n) => n,
None => ui::select_project("Select project...")?
.ok_or_else(|| anyhow::anyhow!("No project selected"))?,
};
let project = Project::load(&name)?;
let branch_name = match branch {
Some(b) => b,
None => ui::select_worktree(&project, "Select worktree to merge...")?
.ok_or_else(|| anyhow::anyhow!("No worktree selected"))?,
};
let default_branch = git::get_default_branch(&project.root_expanded())?;
if !ui::confirm(&format!(
"Merge '{}' into '{}'?",
branch_name, default_branch
))? {
println!("Cancelled.");
return Ok(());
}
println!("Merging '{}' into '{}'...", branch_name, default_branch);
git::merge_branch_to_default(&project.root_expanded(), &branch_name)?;
println!("Merged successfully.");
if ui::confirm(&format!(
"Delete worktree '{}' and its session?",
branch_name
))? {
let session_name = project.worktree_session_name(&branch_name);
if tmux::session_exists(&session_name)? {
println!("Stopping session '{}'...", session_name);
tmux::safe_kill_session(&session_name)?;
}
println!("Deleting worktree...");
git::delete_worktree(&project, &branch_name)?;
println!("Deleted worktree: {}", branch_name);
}
Ok(())
}