use thor_core::{find_repo, list_worktrees};
use std::path::PathBuf;
pub enum GoQuery {
Fuzzy(String),
Index(usize),
Previous,
}
pub enum GoResult {
Found { path: PathBuf, branch: String },
NotFound(String),
Ambiguous(Vec<String>),
}
pub fn save_last_worktree(path: &std::path::Path) {
if let Some(data_dir) = dirs::data_dir() {
let thor_dir = data_dir.join("thor");
let _ = std::fs::create_dir_all(&thor_dir);
let _ = std::fs::write(thor_dir.join("last_worktree"), path.display().to_string());
}
}
fn load_last_worktree() -> Option<PathBuf> {
let data_dir = dirs::data_dir()?;
let path_str = std::fs::read_to_string(data_dir.join("thor").join("last_worktree")).ok()?;
let path = PathBuf::from(path_str.trim());
if path.is_dir() { Some(path) } else { None }
}
pub async fn go(query: &GoQuery) -> anyhow::Result<GoResult> {
let repo = find_repo()?;
let worktrees = list_worktrees(&repo).await?;
match query {
GoQuery::Previous => {
match load_last_worktree() {
Some(saved) => {
match worktrees.iter().find(|wt| saved.starts_with(&wt.path)) {
Some(wt) => Ok(GoResult::Found {
path: wt.path.clone(),
branch: wt.display_name(),
}),
None => Ok(GoResult::Found { path: saved, branch: "unknown".to_string() }),
}
}
None => Ok(GoResult::NotFound("No previous worktree".to_string())),
}
}
GoQuery::Index(idx) => {
match worktrees.get(idx.saturating_sub(1)) {
Some(wt) => Ok(GoResult::Found {
path: wt.path.clone(),
branch: wt.display_name(),
}),
None => Ok(GoResult::NotFound(format!("Index {} out of range (1-{})", idx, worktrees.len()))),
}
}
GoQuery::Fuzzy(query) => {
let query_lower = query.to_lowercase();
if let Some(wt) = worktrees.iter().find(|wt| {
wt.branch.as_ref().map(|b| b == query).unwrap_or(false)
}) {
return Ok(GoResult::Found {
path: wt.path.clone(),
branch: wt.display_name(),
});
}
let matches: Vec<_> = worktrees.iter()
.filter(|wt| {
wt.branch.as_ref()
.map(|b| b.to_lowercase().contains(&query_lower))
.unwrap_or(false)
})
.collect();
match matches.len() {
0 => Ok(GoResult::NotFound(format!("No worktree matching '{}'", query))),
1 => Ok(GoResult::Found {
path: matches[0].path.clone(),
branch: matches[0].display_name(),
}),
_ => Ok(GoResult::Ambiguous(
matches.iter().map(|wt| wt.display_name()).collect()
)),
}
}
}
}