eazygit 0.5.1

A fast TUI for Git with staging, conflicts, rebase, and palette-first UX
Documentation
//! Feedback and error message rendering.

use crate::app::AppState;
use crate::ui::style::{self, Emphasis};
use ratatui::Frame;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::text::{Line, Span};
use ratatui::widgets::Paragraph;

/// Render feedback messages (success) or errors with guidance.
pub fn render(frame: &mut Frame, area: Rect, state: &AppState) {
    // Show feedback messages (success) or errors with guidance
    if let Some(ref feedback) = state.feedback_message {
        let footer_style = style::text(&state.theme, Emphasis::Success);
        let block = style::pane_block(&state.theme, "Status", false);
        let paragraph = Paragraph::new(feedback.clone())
            .style(footer_style)
            .block(block);

        let footer = Layout::default()
            .direction(Direction::Vertical)
            .constraints([Constraint::Min(0), Constraint::Length(3)])
            .split(area);
        frame.render_widget(paragraph, footer[1]);
        return;
    }

    // Show error with guidance if available
    if let Some(ref error_guidance) = state.error_guidance {
        let formatted = error_guidance.format_display();
        let lines: Vec<Line> = formatted
            .lines()
            .map(|line| {
                if line.starts_with("  [") && line.contains("]") {
                    // Format quick actions with highlighted keys
                    let parts: Vec<&str> = line.splitn(2, "] ").collect();
                    if parts.len() == 2 {
                        let key_part = parts[0].trim_start_matches("  [");
                        let label = parts[1];
                        Line::from(vec![
                            Span::styled("  [", style::text(&state.theme, Emphasis::Normal)),
                            Span::styled(key_part, style::text(&state.theme, Emphasis::Warning)),
                            Span::styled("] ", style::text(&state.theme, Emphasis::Normal)),
                            Span::styled(label, style::text(&state.theme, Emphasis::Normal)),
                        ])
                    } else {
                        Line::from(line)
                    }
                } else if line.starts_with("") {
                    // Format suggestions
                    let prefix = "";
                    let char_count = prefix.chars().count();
                    let rest: String = line.chars().skip(char_count).collect();
                    Line::from(vec![
                        Span::styled(prefix, style::text(&state.theme, Emphasis::Muted)),
                        Span::styled(rest, style::text(&state.theme, Emphasis::Normal)),
                    ])
                } else if line == "Suggestions:" || line == "Quick actions:" {
                    // Format section headers
                    Line::from(vec![
                        Span::styled(line, style::text(&state.theme, Emphasis::Header)),
                    ])
                } else {
                    Line::from(line)
                }
            })
            .collect();

        let error_style = style::text(&state.theme, Emphasis::Error);
        let block = style::pane_block(&state.theme, "Error", false);
        let paragraph = Paragraph::new(lines)
            .style(error_style)
            .block(block);

        // Calculate height needed (at least 3, but more if guidance is long)
        let content_height = formatted.lines().count().max(3);
        let height = (content_height + 2).min(area.height as usize) as u16;

        let footer = Layout::default()
            .direction(Direction::Vertical)
            .constraints([Constraint::Min(0), Constraint::Length(height)])
            .split(area);
        frame.render_widget(paragraph, footer[1]);
        return;
    }

    // Fallback to simple error message if no guidance
    if let Some(ref error) = state.last_status_error {
        let footer_style = style::text(&state.theme, Emphasis::Error);
        let block = style::pane_block(&state.theme, "Status", false);
        let paragraph = Paragraph::new(error.clone())
            .style(footer_style)
            .block(block);

        let footer = Layout::default()
            .direction(Direction::Vertical)
            .constraints([Constraint::Min(0), Constraint::Length(3)])
            .split(area);
        frame.render_widget(paragraph, footer[1]);
    }
}