eazygit 0.5.1

A fast TUI for Git with staging, conflicts, rebase, and palette-first UX
Documentation
use crate::app::{Action, AppState};
use crate::errors::ComponentError;
use crate::input::InputEvent;
use crossterm::event::{KeyCode, KeyEventKind};

pub fn handle_event(
    event: InputEvent,
    state: &AppState,
) -> Result<Option<Action>, ComponentError> {
    match event {
        InputEvent::Key(key) if key.kind == KeyEventKind::Press => {
            match key.code {
                KeyCode::Char('s') => Ok(Some(Action::StageSelectedFile)),
                KeyCode::Char('u') => Ok(Some(Action::UnstageSelectedFile)),
                KeyCode::Char('S') => Ok(Some(Action::StageAllFiles)),
                KeyCode::Char('U') => Ok(Some(Action::UnstageAllFiles)),
                KeyCode::Char('k') | KeyCode::Up => {
                    if state.status_selected == 0 {
                        Ok(None)
                    } else {
                        Ok(Some(Action::StatusUp))
                    }
                }
                KeyCode::Char('j') | KeyCode::Down => {
                    let len = state.status_entries.len();
                    if len == 0 || state.status_selected + 1 >= len {
                        Ok(None)
                    } else {
                        Ok(Some(Action::StatusDown))
                    }
                }
                KeyCode::PageUp => {
                    if state.status_selected == 0 {
                        Ok(None)
                    } else {
                        Ok(Some(Action::StatusPageUp))
                    }
                }
                KeyCode::PageDown => {
                    let len = state.status_entries.len();
                    if len == 0 || state.status_selected + 1 >= len {
                        Ok(None)
                    } else {
                        Ok(Some(Action::StatusPageDown))
                    }
                }
                KeyCode::Home => Ok(Some(Action::StatusTop)),
                KeyCode::End => Ok(Some(Action::StatusBottom)),
                KeyCode::Char('r') => {
                    // Smart refresh handling: visual feedback prevents abuse, not artificial limits
                    // Philosophy: Like IDEs, users should be able to refresh whenever they want
                    // The "⟳ REFRESHING…" indicator naturally prevents spam - users see it and wait
                    
                    // Only prevent if already actively refreshing (prevents queueing multiple refreshes)
                    // This is not a rate limit - it's preventing redundant work
                    if state.refreshing {
                        // Already refreshing - ignore to prevent queueing multiple git operations
                        // User sees "⟳ REFRESHING…" so they know their action is being processed
                        Ok(None)
                    } else {
                        // Not refreshing - allow it immediately with visual feedback
                        // The visual indicator will prevent most abuse naturally
                        Ok(Some(Action::RequestRefreshStatus))
                    }
                },
                KeyCode::Char(' ') => {
                    if !state.status_selected_path.is_empty() {
                        Ok(Some(Action::ToggleFileSelect(state.status_selected_path.clone())))
                    } else {
                        Ok(None)
                    }
                }
                KeyCode::Char('n') => Ok(Some(Action::StatusNextStaged)),
                KeyCode::Char('N') => Ok(Some(Action::StatusPrevStaged)),
                KeyCode::Char('/') => Ok(Some(Action::StartFilter)),
                _ => Ok(None),
            }
        }
        _ => Ok(None),
    }
}