use std::collections::BTreeMap;use ratatui::text::Line;use super::status_line_from_segments;use super::status_line_setup::StatusLineItem;#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]pub(crate) enum StatusSurfacePreviewItem { AppName, ProjectName, ProjectRoot, CurrentDir, Status, ThreadTitle, GitBranch, PullRequestNumber, BranchChanges, Permissions, ApprovalMode, ContextRemaining, ContextUsed, FiveHourLimit, WeeklyLimit, CodexVersion, ContextWindowSize, UsedTokens, TotalInputTokens, TotalOutputTokens, SessionId, FastMode, RawOutput, Model, ModelWithReasoning, Reasoning, TaskProgress,}impl StatusSurfacePreviewItem { fn placeholder(self) -> &'static str { match self { StatusSurfacePreviewItem::AppName => "codex", StatusSurfacePreviewItem::ProjectName => "my-project", StatusSurfacePreviewItem::ProjectRoot => "my-project", StatusSurfacePreviewItem::CurrentDir => "~/my-project/subdir", StatusSurfacePreviewItem::Status => "Working", StatusSurfacePreviewItem::ThreadTitle => "thread title", StatusSurfacePreviewItem::GitBranch => "feat/awesome-feature", StatusSurfacePreviewItem::PullRequestNumber => "PR #123", StatusSurfacePreviewItem::BranchChanges => "+12 -3", StatusSurfacePreviewItem::Permissions => "Workspace", StatusSurfacePreviewItem::ApprovalMode => "on-request", StatusSurfacePreviewItem::ContextRemaining => "Context 0% left", StatusSurfacePreviewItem::ContextUsed => "Context 0% used", StatusSurfacePreviewItem::FiveHourLimit => "primary 0%", StatusSurfacePreviewItem::WeeklyLimit => "secondary 0%", StatusSurfacePreviewItem::CodexVersion => "0.0.0", StatusSurfacePreviewItem::ContextWindowSize => "0 window", StatusSurfacePreviewItem::UsedTokens => "0 used", StatusSurfacePreviewItem::TotalInputTokens => "0 in", StatusSurfacePreviewItem::TotalOutputTokens => "0 out", StatusSurfacePreviewItem::SessionId => "550e8400-e29b-41d4", StatusSurfacePreviewItem::FastMode => "Fast on", StatusSurfacePreviewItem::RawOutput => "raw output", StatusSurfacePreviewItem::Model => "gpt-5.2-codex", StatusSurfacePreviewItem::ModelWithReasoning => "gpt-5.2-codex medium", StatusSurfacePreviewItem::Reasoning => "medium", StatusSurfacePreviewItem::TaskProgress => "Tasks 0/0", } } pub(crate) fn iter() -> impl Iterator<Item = Self> { [ Self::AppName, Self::ProjectName, Self::ProjectRoot, Self::CurrentDir, Self::Status, Self::ThreadTitle, Self::GitBranch, Self::PullRequestNumber, Self::BranchChanges, Self::Permissions, Self::ApprovalMode, Self::ContextRemaining, Self::ContextUsed, Self::FiveHourLimit, Self::WeeklyLimit, Self::CodexVersion, Self::ContextWindowSize, Self::UsedTokens, Self::TotalInputTokens, Self::TotalOutputTokens, Self::SessionId, Self::FastMode, Self::RawOutput, Self::Model, Self::ModelWithReasoning, Self::Reasoning, Self::TaskProgress, ] .into_iter() }}#[derive(Clone, Debug, Eq, PartialEq)]struct PreviewValue { text: String, is_placeholder: bool,}#[derive(Clone, Debug, Eq, PartialEq)]pub(crate) struct StatusSurfacePreviewData { values: BTreeMap<StatusSurfacePreviewItem, PreviewValue>,}impl Default for StatusSurfacePreviewData { fn default() -> Self { let mut data = Self { values: BTreeMap::new(), }; for item in StatusSurfacePreviewItem::iter() { data.set_placeholder(item, item.placeholder()); } data }}impl StatusSurfacePreviewData { pub(crate) fn from_iter<I, V>(values: I) -> Self where I: IntoIterator<Item = (StatusSurfacePreviewItem, V)>, V: Into<String>, { let mut data = Self::default(); for (item, value) in values { data.set_live(item, value); } data } pub(crate) fn set_live<V>(&mut self, item: StatusSurfacePreviewItem, value: V) where V: Into<String>, { self.values.insert( item, PreviewValue { text: value.into(), is_placeholder: false, }, ); } pub(crate) fn set_placeholder<V>(&mut self, item: StatusSurfacePreviewItem, value: V) where V: Into<String>, { if self .values .get(&item) .is_some_and(|value| !value.is_placeholder) { return; } self.values.insert( item, PreviewValue { text: value.into(), is_placeholder: true, }, ); } pub(crate) fn suppress_placeholder(&mut self, item: StatusSurfacePreviewItem) { if self .values .get(&item) .is_some_and(|value| value.is_placeholder) { self.values.remove(&item); } } pub(crate) fn rate_limit_item_name( &self, item: StatusSurfacePreviewItem, fallback: &str, ) -> String { self.live_value_for(item) .and_then(rate_limit_preview_copy) .map(|copy| copy.name.to_string()) .unwrap_or_else(|| fallback.to_string()) } pub(crate) fn rate_limit_item_description( &self, item: StatusSurfacePreviewItem, fallback: &str, ) -> String { self.live_value_for(item) .and_then(rate_limit_preview_copy) .map(|copy| copy.description.to_string()) .unwrap_or_else(|| fallback.to_string()) } pub(crate) fn value_for(&self, item: StatusSurfacePreviewItem) -> Option<&str> { self.values.get(&item).map(|value| value.text.as_str()) } fn live_value_for(&self, item: StatusSurfacePreviewItem) -> Option<&str> { self.values .get(&item) .filter(|value| !value.is_placeholder) .map(|value| value.text.as_str()) } pub(crate) fn status_line_for_items<I>( &self, items: I, use_theme_colors: bool, ) -> Option<Line<'static>> where I: IntoIterator<Item = StatusLineItem>, { let segments = items.into_iter().filter_map(|item| { self.value_for(item.preview_item()) .map(|value| (item, value.to_string())) }); status_line_from_segments(segments, use_theme_colors) }}struct RateLimitPreviewCopy { name: &'static str, description: &'static str,}fn rate_limit_preview_copy(value: &str) -> Option<RateLimitPreviewCopy> { let value = value.trim_start(); if value.starts_with("secondary usage ") { Some(RateLimitPreviewCopy { name: "secondary-usage-limit", description: "Remaining usage on the secondary usage limit (omitted when unavailable)", }) } else if value.starts_with("usage ") { Some(RateLimitPreviewCopy { name: "usage-limit", description: "Remaining usage on the primary usage limit (omitted when unavailable)", }) } else if value.starts_with("5h ") { Some(RateLimitPreviewCopy { name: "five-hour-limit", description: "Remaining usage on the 5-hour usage limit (omitted when unavailable)", }) } else if value.starts_with("daily ") { Some(RateLimitPreviewCopy { name: "daily-limit", description: "Remaining usage on the daily usage limit (omitted when unavailable)", }) } else if value.starts_with("weekly ") { Some(RateLimitPreviewCopy { name: "weekly-limit", description: "Remaining usage on the weekly usage limit (omitted when unavailable)", }) } else if value.starts_with("monthly ") { Some(RateLimitPreviewCopy { name: "monthly-limit", description: "Remaining usage on the monthly usage limit (omitted when unavailable)", }) } else if value.starts_with("annual ") { Some(RateLimitPreviewCopy { name: "annual-limit", description: "Remaining usage on the annual usage limit (omitted when unavailable)", }) } else { None }}