magi-code 0.80.2

Repository-aware CLI coding agent for terminal work
Documentation
use super::render_scroll_view_persistent_with_theme;
#[cfg(any(test, debug_assertions))]
use crate::tui::PADDED_INLINE_SEPARATOR;
use crate::tui::{input, state::MissionControlState};
use ratatui::{
    Frame,
    layout::Rect,
    text::{Line, Span},
    widgets::{Paragraph, Wrap},
};

pub(super) fn branch_text(state: &MissionControlState) -> String {
    state
        .footer_git_branch
        .as_deref()
        .filter(|branch| !branch.is_empty())
        .map(|branch| format!("Branch: {branch}"))
        .unwrap_or_default()
}

pub(super) fn version_title(state: &MissionControlState) -> Line<'static> {
    let accent = state.theme.accent(false);
    let mut spans = Vec::new();
    #[cfg(any(test, debug_assertions))]
    if let Some(perf) = state.perf.footer_text() {
        spans.push(Span::styled(
            format!("{perf}{PADDED_INLINE_SEPARATOR}"),
            accent,
        ));
    }
    if state.available_update_version.is_some() {
        spans.push(Span::styled(
            "(/update ready) ",
            accent.fg(state.theme.text_command()),
        ));
    }
    spans.push(Span::styled(
        format!("MAGI-CODE v{}", env!("CARGO_PKG_VERSION")),
        accent,
    ));
    Line::from(spans)
}

pub(super) fn draw_help(frame: &mut Frame<'_>, area: Rect, state: &MissionControlState) {
    let theme = state.theme;
    let inner = crate::tui::modal_container::draw_modal_container(
        frame,
        area,
        "Help",
        "[PgUp]/[PgDn] scroll",
        theme,
        Some("[Esc] close"),
    );
    let text_area = super::overlay_text_area(inner);
    let help_text = input::help_text();
    let wrap_width = super::scroll_view_content_width(text_area).max(1);
    let scroll = state.help_render_offset(text_area.height, wrap_width, help_text);
    render_scroll_view_persistent_with_theme(
        frame,
        text_area,
        super::usize_to_u16_saturating(scroll),
        super::usize_to_u16_saturating(crate::tui::transcript::ratatui_wrapped_visual_rows(
            help_text, wrap_width,
        )),
        Paragraph::new(help_text)
            .style(theme.app())
            .wrap(Wrap { trim: false }),
        &state.scroll_views.help,
        theme,
    );
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn help_shell_keeps_chrome_out_of_scroll_content() {
        use ratatui::{Terminal, backend::TestBackend};
        let state = MissionControlState::default();
        let mut terminal = Terminal::new(TestBackend::new(100, 30)).unwrap();
        let area = crate::tui::modal_container::modal_area(Rect::new(0, 0, 100, 30), 60, 60);
        terminal
            .draw(|frame| draw_help(frame, area, &state))
            .unwrap();
        let buffer = terminal.backend().buffer();
        let row = |y| {
            (area.x..area.right())
                .map(|x| buffer[(x, y)].symbol())
                .collect::<String>()
        };
        assert!(row(area.y).starts_with("┌Help"));
        assert!(row(area.y).contains("[Esc] close"));
        assert!(row(area.bottom() - 1).contains("[PgUp]/[PgDn] scroll"));
        assert_eq!(
            buffer[(area.x + 1, area.y + 1)].bg,
            state.theme.app().bg.unwrap()
        );
    }

    #[test]
    fn branch_header_omits_directory() {
        let state = MissionControlState {
            footer_cwd: "/repo".to_string(),
            footer_git_branch: Some("main".to_string()),
            ..Default::default()
        };
        assert_eq!(branch_text(&state), "Branch: main");
    }

    #[test]
    fn branch_header_is_empty_for_missing_or_empty_branch() {
        for branch in [None, Some(String::new())] {
            let state = MissionControlState {
                footer_cwd: "/repo".to_string(),
                footer_git_branch: branch,
                ..Default::default()
            };
            assert_eq!(branch_text(&state), "");
        }
    }

    #[test]
    fn version_title_uses_accent_and_package_version() {
        let state = MissionControlState::default();
        let title = version_title(&state);
        assert_eq!(
            title.to_string(),
            format!("MAGI-CODE v{}", env!("CARGO_PKG_VERSION"))
        );
        assert_eq!(title.spans[0].style, state.theme.accent(false));
    }

    #[test]
    fn version_title_includes_perf_text_only_after_snapshot_exists() {
        let state = MissionControlState {
            #[cfg(any(test, debug_assertions))]
            perf: crate::tui::perf::TuiPerfCounters::with_enabled(true),
            ..Default::default()
        };
        assert!(!version_title(&state).to_string().contains("perf drain"));

        #[cfg(any(test, debug_assertions))]
        {
            state.perf.record_drain_us(400);
            state.perf.increment_projected_cards();
            state.perf.set_backlog_before_drain(3);
            state.perf.set_backlog_after_drain(2);
            state.perf.set_backlog_before_draw(1);
            state.perf.record_draw_us(2100);
            state.perf.record_prompt_edit_to_draw_us(17_300);
        }
        let text = version_title(&state).to_string();
        assert!(text.contains("perf drain 0.4/0.4ms draw 2.1/2.1ms cards 1 backlog 3/2/1"));
        assert!(text.contains("edit->draw 17.3ms"));
        assert!(text.contains("MAGI-CODE v"));
    }
}