1use thor_core::{find_repo, list_worktrees};
2use std::path::PathBuf;
3
4pub enum GoQuery {
6 Fuzzy(String),
8 Index(usize),
10 Previous,
12}
13
14pub enum GoResult {
16 Found { path: PathBuf, branch: String },
17 NotFound(String),
18 Ambiguous(Vec<String>),
19}
20
21pub fn save_last_worktree(path: &std::path::Path) {
23 if let Some(data_dir) = dirs::data_dir() {
24 let thor_dir = data_dir.join("thor");
25 let _ = std::fs::create_dir_all(&thor_dir);
26 let _ = std::fs::write(thor_dir.join("last_worktree"), path.display().to_string());
27 }
28}
29
30fn load_last_worktree() -> Option<PathBuf> {
31 let data_dir = dirs::data_dir()?;
32 let path_str = std::fs::read_to_string(data_dir.join("thor").join("last_worktree")).ok()?;
33 let path = PathBuf::from(path_str.trim());
34 if path.is_dir() { Some(path) } else { None }
35}
36
37pub async fn go(query: &GoQuery) -> anyhow::Result<GoResult> {
39 let repo = find_repo()?;
40 let worktrees = list_worktrees(&repo).await?;
41
42 match query {
43 GoQuery::Previous => {
44 match load_last_worktree() {
45 Some(saved) => {
46 match worktrees.iter().find(|wt| saved.starts_with(&wt.path)) {
48 Some(wt) => Ok(GoResult::Found {
49 path: wt.path.clone(),
50 branch: wt.display_name(),
51 }),
52 None => Ok(GoResult::Found { path: saved, branch: "unknown".to_string() }),
53 }
54 }
55 None => Ok(GoResult::NotFound("No previous worktree".to_string())),
56 }
57 }
58 GoQuery::Index(idx) => {
59 match worktrees.get(idx.saturating_sub(1)) {
60 Some(wt) => Ok(GoResult::Found {
61 path: wt.path.clone(),
62 branch: wt.display_name(),
63 }),
64 None => Ok(GoResult::NotFound(format!("Index {} out of range (1-{})", idx, worktrees.len()))),
65 }
66 }
67 GoQuery::Fuzzy(query) => {
68 let query_lower = query.to_lowercase();
69
70 if let Some(wt) = worktrees.iter().find(|wt| {
72 wt.branch.as_ref().map(|b| b == query).unwrap_or(false)
73 }) {
74 return Ok(GoResult::Found {
75 path: wt.path.clone(),
76 branch: wt.display_name(),
77 });
78 }
79
80 let matches: Vec<_> = worktrees.iter()
82 .filter(|wt| {
83 wt.branch.as_ref()
84 .map(|b| b.to_lowercase().contains(&query_lower))
85 .unwrap_or(false)
86 })
87 .collect();
88
89 match matches.len() {
90 0 => Ok(GoResult::NotFound(format!("No worktree matching '{}'", query))),
91 1 => Ok(GoResult::Found {
92 path: matches[0].path.clone(),
93 branch: matches[0].display_name(),
94 }),
95 _ => Ok(GoResult::Ambiguous(
96 matches.iter().map(|wt| wt.display_name()).collect()
97 )),
98 }
99 }
100 }
101}