git_workty/commands/
pick.rs1use crate::git::GitRepo;
2use crate::status::get_all_statuses;
3use crate::ui::{format_time, UiOptions};
4use crate::worktree::list_worktrees;
5use anyhow::{bail, Result};
6use console::Term;
7use dialoguer::FuzzySelect;
8use is_terminal::IsTerminal;
9
10pub fn execute(repo: &GitRepo, _opts: &UiOptions) -> Result<()> {
11 if !std::io::stdin().is_terminal() {
12 bail!("Cannot run interactive picker in non-TTY. Use `git workty go <name>` instead.");
13 }
14
15 let worktrees = list_worktrees(repo)?;
16 if worktrees.is_empty() {
17 bail!("No worktrees found");
18 }
19
20 let statuses = get_all_statuses(repo, &worktrees);
22
23 let max_name_len = statuses
25 .iter()
26 .map(|(wt, _)| wt.name().len())
27 .max()
28 .unwrap_or(10);
29
30 let items: Vec<String> = statuses
31 .iter()
32 .map(|(wt, status)| {
33 let name = format!("{:width$}", wt.name(), width = max_name_len);
34
35 let dirty = if status.dirty_count > 0 {
37 format!("*{}", status.dirty_count)
38 } else {
39 " ".to_string()
40 };
41
42 let time = format_time(status.last_commit_time);
44
45 let rebase = if status.needs_rebase() {
47 format!("R{}", status.behind_main.unwrap_or(0))
48 } else {
49 " ".to_string()
50 };
51
52 format!("{} {:>3} {:>4} {}", name, dirty, time, rebase)
53 })
54 .collect();
55
56 let selection = FuzzySelect::new()
57 .with_prompt("Select worktree")
58 .items(&items)
59 .default(0)
60 .interact_on_opt(&Term::stderr())?;
61
62 match selection {
63 Some(idx) => {
64 println!("{}", statuses[idx].0.path.display());
65 Ok(())
66 }
67 None => {
68 std::process::exit(130);
70 }
71 }
72}