treeflow 0.2.0

CLI tool for simplified Git worktree management to speed up switching contexts when working collaboratively.
Documentation
use treeflow::core::config::{Config, ConfigPaths};
use treeflow::core::project::Project;
use clap::ArgMatches;
use std::env;
use std::path::PathBuf;
use treeflow::utils::errors::CustomError;
use treeflow::utils::{Return, Shell};
use crate::cli::handlers::*;

const REQUIRED: &str = "This argument is required. Does your Command match your matcher?";

pub fn match_treeflow(matches: &ArgMatches, config_paths: ConfigPaths) -> Result<Return, CustomError> {
    match matches.subcommand() {
        Some(("config", _)) => handle_config(&config_paths),
        Some(("init", sub_matches)) => {
            let shell = sub_matches.get_one::<Shell>("SHELL").expect(REQUIRED);
            let enable_shorthands = sub_matches.get_flag("enable-shorthands");
            handle_init(&config_paths, shell, enable_shorthands)
        },
        Some(("worktype", sub_matches)) => match_worktype(sub_matches, config_paths),
        Some(("project", sub_matches)) => match_project(sub_matches, config_paths),
        Some(("primary", _)) => handle_primary(&config_paths),
        Some(("review", sub_matches)) => {
            let branch = sub_matches.get_one::<String>("BRANCH").map(|s| s.clone()).expect(REQUIRED);
            handle_review(&config_paths, &branch)
        },
        Some(("finish", sub_matches)) => {
            let force = sub_matches.get_flag("force");
            handle_finish(&config_paths, force)
        },
        Some((work_type_name, sub_matches)) => { // Handle dynamic work type commands (e.g., "feature", "bugfix")
            // Check if this is a valid work type by loading the config
            let config = Config::load(&config_paths)?;
            if config.work_types.iter().any(|wt| &wt.type_name == work_type_name) {
                let work_name = sub_matches.get_one::<String>("NAME").expect(REQUIRED);
                handle_start(&config_paths, work_name, &work_type_name.to_string())
            } else {
                Err(CustomError::InvalidCommand(format!("Unknown subcommand: {}", work_type_name)))
            }
        },
        _ => unreachable!(),
    }
}

fn match_worktype(matches: &ArgMatches, config_paths: ConfigPaths) -> Result<Return, CustomError> {
    match matches.subcommand() {
        Some(("list", _)) => handle_worktype_list(&config_paths),
        Some(("add", sub_matches)) => {
            let type_name = sub_matches.get_one::<String>("NAME").expect(REQUIRED);
            let prefix = sub_matches.get_one::<String>("prefix").expect(REQUIRED);
            handle_worktype_add(&config_paths, type_name, prefix)
        }
        Some(("remove", sub_matches)) => {
            let type_name = sub_matches.get_one::<String>("NAME").expect(REQUIRED);
            handle_worktype_remove(&config_paths, &type_name)
        }
        _ => Err(CustomError::InvalidCommand("Unknown worktype subcommand".to_string())),
    }
}

fn match_project(matches: &ArgMatches, config_paths: ConfigPaths) -> Result<Return, CustomError> {
    match matches.subcommand() {
        Some(("list", _)) => handle_project_list(&config_paths),
        Some(("add", sub_matches)) => {
            let repository = sub_matches.get_one::<PathBuf>("REPOSITORY_DIR").expect(REQUIRED);
            let worktrees = sub_matches.get_one::<PathBuf>("worktrees-dir");
            handle_project_add(&config_paths, repository, worktrees)
        }
        Some(("remove", sub_matches)) => {
            let repository = sub_matches.get_one::<PathBuf>("REPOSITORY_DIR").expect(REQUIRED);
            handle_project_remove(&config_paths, repository)
        }
        _ => Err(CustomError::InvalidCommand("Unknown project subcommand".to_string())),
    }
}