eazygit 0.5.1

A fast TUI for Git with staging, conflicts, rebase, and palette-first UX
Documentation
use crate::commands::{Command, CommandResult};
use crate::services::GitService;
use crate::app::{AppState, Action, reducer};
use crate::errors::CommandError;
use tracing::instrument;

/// Command to checkout a branch
pub struct CheckoutBranchCommand {
    pub branch_name: String,
}

impl Command for CheckoutBranchCommand {
    #[instrument(skip(self, git, state), fields(branch = %self.branch_name))]
    fn execute(
        &self,
        git: &GitService,
        state: &AppState,
    ) -> Result<CommandResult, CommandError> {
        git.checkout_branch(&state.repo_path, &self.branch_name)
            .map_err(|e| CommandError::GitError(e))?;
        
        let mut new_state = state.clone();
        new_state = reducer(new_state, Action::SetFeedback(Some(
            format!("Switched to {}", self.branch_name)
        )));
        new_state.focus = crate::app::state::FocusPane::Status;
        new_state = reducer(new_state, Action::SetRefreshing(true));
        
        Ok(CommandResult::StateUpdate(new_state))
    }
}

/// Command to merge a branch into current
pub struct MergeBranchCommand {
    pub branch_name: String,
}

impl Command for MergeBranchCommand {
    #[instrument(skip(self, git, state), fields(branch = %self.branch_name))]
    fn execute(
        &self,
        git: &GitService,
        state: &AppState,
    ) -> Result<CommandResult, CommandError> {
        git.merge(&state.repo_path, &self.branch_name)
            .map_err(|e| CommandError::GitError(e))?;
        
        let mut new_state = state.clone();
        new_state = reducer(new_state, Action::SetFeedback(Some(
            format!("Merged {} successfully", self.branch_name)
        )));
        new_state.focus = crate::app::state::FocusPane::Status;
        new_state = reducer(new_state, Action::SetRefreshing(true));
        
        Ok(CommandResult::StateUpdate(new_state))
    }
}

/// Command to rebase current branch onto another
pub struct RebaseBranchCommand {
    pub branch_name: String,
}

impl Command for RebaseBranchCommand {
    #[instrument(skip(self, git, state), fields(branch = %self.branch_name))]
    fn execute(
        &self,
        git: &GitService,
        state: &AppState,
    ) -> Result<CommandResult, CommandError> {
        git.rebase(&state.repo_path, &self.branch_name)
            .map_err(|e| CommandError::GitError(e))?;
        
        let mut new_state = state.clone();
        new_state = reducer(new_state, Action::SetFeedback(Some(
            format!("Rebased onto {} successfully", self.branch_name)
        )));
        new_state.focus = crate::app::state::FocusPane::Status;
        new_state = reducer(new_state, Action::SetRefreshing(true));
        
        Ok(CommandResult::StateUpdate(new_state))
    }
}

/// Command to create a new branch
pub struct CreateBranchCommand {
    pub branch_name: String,
}

impl Command for CreateBranchCommand {
    #[instrument(skip(self, git, state), fields(branch = %self.branch_name))]
    fn execute(
        &self,
        git: &GitService,
        state: &AppState,
    ) -> Result<CommandResult, CommandError> {
        if self.branch_name.trim().is_empty() {
            let mut new_state = state.clone();
            new_state = reducer(new_state, Action::SetStatusError(Some("Branch name is empty".into())));
            return Ok(CommandResult::StateUpdate(new_state));
        }

        git.create_branch(&state.repo_path, &self.branch_name)
            .map_err(|e| CommandError::GitError(e))?;
        
        let mut new_state = state.clone();
        new_state = reducer(new_state, Action::SetFeedback(Some(
            format!("Created branch {}", self.branch_name)
        )));
        new_state.branch_create_mode = false;
        new_state.branch_name_input.clear();
        // Explicitly refresh branches list to show the new branch immediately
        new_state = reducer(new_state, Action::RefreshBranches);
        new_state = reducer(new_state, Action::SetRefreshing(true)); // Also trigger status refresh
        
        Ok(CommandResult::StateUpdate(new_state))
    }
}