use super::{
overlay_block_with_theme, render_overlay_fill_with_theme,
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::{Clear, 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()
}
fn footer_right_text(_state: &MissionControlState) -> String {
let base = format!("MAGI-CODE v{}", env!("CARGO_PKG_VERSION"));
#[cfg(any(test, debug_assertions))]
{
if let Some(perf) = _state.perf.footer_text() {
return format!("{perf}{PADDED_INLINE_SEPARATOR}{base}");
}
}
base
}
pub(super) fn version_title(state: &MissionControlState) -> Line<'static> {
Line::from(Span::styled(
footer_right_text(state),
state.theme.accent(false),
))
}
pub(super) fn draw_help(frame: &mut Frame<'_>, area: Rect, state: &MissionControlState) {
let theme = state.theme;
frame.render_widget(Clear, area);
let block = overlay_block_with_theme(theme, "Help");
let inner = block.inner(area);
frame.render_widget(block, area);
let text_area = render_overlay_fill_with_theme(frame, inner, theme);
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.panel_alt())
.wrap(Wrap { trim: false }),
&state.scroll_views.help,
theme,
);
}
#[cfg(test)]
mod tests {
use super::*;
#[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"));
}
}