use anyhow::{Context, Result};
use inquire::{Confirm, Select, Text};
use std::path::Path;
pub enum AddAction {
Existing(String),
New(String),
Remote(String),
}
pub fn add_interactive(dir: &Path) -> Result<AddAction> {
let action = Select::new(
"Select action",
vec!["existing branch", "new branch", "remote branch"],
)
.prompt()?;
match action {
"existing branch" => {
let branches =
grove_core::git::list_local_branches(dir).context("failed to list branches")?;
let branch = Select::new("Select existing branch", branches).prompt()?;
Ok(AddAction::Existing(branch))
}
"new branch" => {
let branch = Text::new("Enter new branch name:").prompt()?;
Ok(AddAction::New(branch))
}
"remote branch" => {
grove_core::git::fetch_all(dir).context("fetch failed")?;
let branches = grove_core::git::list_remote_branches(dir)
.context("failed to list remote branches")?;
let branch = Select::new("Select remote branch", branches).prompt()?;
Ok(AddAction::Remote(branch))
}
_ => unreachable!(),
}
}
pub fn switch_interactive(dir: &Path) -> Result<String> {
let wts = grove_core::git::parse_worktree_list(dir).context("failed to list worktrees")?;
let display_lines: Vec<String> = wts
.iter()
.map(|wt| {
let short = grove_core::path::short_path(&wt.path);
format!("{:30} {}", wt.branch, short)
})
.collect();
let selected = Select::new("Select worktree", display_lines).prompt()?;
let branch = selected.split_whitespace().next().unwrap_or("").to_string();
Ok(branch)
}
pub fn remove_interactive(dir: &Path) -> Result<String> {
let wts = grove_core::git::parse_worktree_list(dir).context("failed to list worktrees")?;
if wts.len() <= 1 {
anyhow::bail!("no removable worktrees (main worktree cannot be removed)");
}
let display_lines: Vec<String> = wts
.iter()
.skip(1)
.map(|wt| {
let short = grove_core::path::short_path(&wt.path);
let state = if wt.prunable { " [prunable]" } else { "" };
format!("{:30} {}{}", wt.branch, short, state)
})
.collect();
let selected = Select::new("Select worktree to remove", display_lines).prompt()?;
let branch = selected.split_whitespace().next().unwrap_or("").to_string();
let confirmed = Confirm::new(&format!("Remove worktree '{}'?", branch))
.with_default(false)
.prompt()?;
if !confirmed {
anyhow::bail!("cancelled");
}
Ok(branch)
}
pub fn cache_interactive() -> Result<String> {
let action = Select::new("Cache action", vec!["link", "status", "unlink"]).prompt()?;
Ok(action.to_string())
}