Codex Handbook
tui/src/bottom_pane/chat_composer/footer_state.rs 73 lines
//! Footer and status-row presentation state for the chat composer.use std::time::Instant;use ratatui::text::Line;use crate::bottom_pane::footer::CollaborationModeIndicator;use crate::bottom_pane::footer::FooterMode;use crate::bottom_pane::footer::GoalStatusIndicator;use crate::key_hint::KeyBinding;#[cfg(test)]use std::time::Duration;pub(super) struct FooterState {    pub(super) quit_shortcut_expires_at: Option<Instant>,    pub(super) quit_shortcut_key: KeyBinding,    pub(super) esc_backtrack_hint: bool,    pub(super) use_shift_enter_hint: bool,    pub(super) mode: FooterMode,    pub(super) hint_override: Option<Vec<(String, String)>>,    pub(super) plan_mode_nudge_visible: bool,    pub(super) flash: Option<FooterFlash>,    pub(super) context_window_percent: Option<i64>,    pub(super) context_window_used_tokens: Option<i64>,    pub(super) collaboration_mode_indicator: Option<CollaborationModeIndicator>,    pub(super) goal_status_indicator: Option<GoalStatusIndicator>,    pub(super) ide_context_active: bool,    pub(super) status_line_value: Option<Line<'static>>,    pub(super) status_line_hyperlink_url: Option<String>,    pub(super) status_line_enabled: bool,    pub(super) side_conversation_context_label: Option<String>,    pub(super) active_agent_label: Option<String>,    pub(super) external_editor_key: Option<KeyBinding>,    pub(super) show_transcript_key: Option<KeyBinding>,    pub(super) insert_newline_key: Option<KeyBinding>,    pub(super) queue_key: Option<KeyBinding>,    pub(super) toggle_shortcuts_key: Option<KeyBinding>,    pub(super) history_search_key: Option<KeyBinding>,    pub(super) reasoning_down_key: Option<KeyBinding>,    pub(super) reasoning_up_key: Option<KeyBinding>,}#[derive(Clone, Debug)]pub(super) struct FooterFlash {    pub(super) line: Line<'static>,    pub(super) expires_at: Instant,}impl FooterState {    pub(super) fn flash_visible(&self) -> bool {        self.flash            .as_ref()            .is_some_and(|flash| Instant::now() < flash.expires_at)    }    #[cfg(test)]    pub(super) fn show_flash(&mut self, line: Line<'static>, duration: Duration) {        let expires_at = Instant::now()            .checked_add(duration)            .unwrap_or_else(Instant::now);        self.flash = Some(FooterFlash { line, expires_at });    }    #[cfg(test)]    pub(super) fn status_line_text(&self) -> Option<String> {        self.status_line_value.as_ref().map(|line| {            line.spans                .iter()                .map(|span| span.content.as_ref())                .collect::<String>()        })    }}