From f38864d801eaa91ec63d73fd5f2a1da614da7923 Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Sun, 31 May 2026 02:43:38 -0700 Subject: [PATCH] fix(tui): compact statusline token chip (#2411) Harvested from #2405 with thanks to @axobase001.\n\nCompacts the statusline token chip to use the short label while preserving the existing token detail and adding focused coverage for the rendered label.\n\nPartially addresses #2309. --- crates/tui/src/tui/footer_ui.rs | 16 +++++----------- crates/tui/src/tui/ui/tests.rs | 20 ++++++++++++++++++-- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/crates/tui/src/tui/footer_ui.rs b/crates/tui/src/tui/footer_ui.rs index 70b84e15..141b6d6f 100644 --- a/crates/tui/src/tui/footer_ui.rs +++ b/crates/tui/src/tui/footer_ui.rs @@ -631,22 +631,16 @@ pub(crate) fn should_show_footer_cost(displayed_cost: f64) -> bool { /// Session token-usage chip for the footer right cluster. /// -/// Renders the accumulated input / cache-hit / output token breakdown -/// since the current runtime session started (not persisted across -/// restarts). Returns empty when no tokens have been recorded yet. +/// Renders a compact accumulated token count for the current runtime session. +/// Detailed cache stats live in the separate `cache` chip. pub(crate) fn footer_session_tokens_spans(app: &App) -> Vec> { let session = &app.session; if session.total_input_tokens == 0 && session.total_output_tokens == 0 { return Vec::new(); } - let in_str = format_token_count_compact(u64::from(session.total_input_tokens)); - let out_str = format_token_count_compact(u64::from(session.total_output_tokens)); - let text = if session.total_cache_hit_tokens == 0 && session.total_cache_miss_tokens == 0 { - format!("{in_str} in · {out_str} out") - } else { - let cache_str = format_token_count_compact(u64::from(session.total_cache_hit_tokens)); - format!("{in_str} in · {cache_str} cch · {out_str} out") - }; + let total = u64::from(session.total_input_tokens) + .saturating_add(u64::from(session.total_output_tokens)); + let text = format!("tok {}", format_token_count_compact(total)); vec![Span::styled(text, Style::default().fg(palette::TEXT_MUTED))] } diff --git a/crates/tui/src/tui/ui/tests.rs b/crates/tui/src/tui/ui/tests.rs index 308afc19..50790f31 100644 --- a/crates/tui/src/tui/ui/tests.rs +++ b/crates/tui/src/tui/ui/tests.rs @@ -10,8 +10,9 @@ use crate::tui::file_mention::{ }; use crate::tui::footer_ui::{ active_tool_status_label, footer_auxiliary_spans, footer_balance_spans, footer_cache_spans, - footer_coherence_spans, footer_state_label, footer_status_line_spans, format_context_budget, - format_token_count_compact, friendly_subagent_progress, render_footer_from, + footer_coherence_spans, footer_session_tokens_spans, footer_state_label, + footer_status_line_spans, format_context_budget, format_token_count_compact, + friendly_subagent_progress, render_footer_from, }; use crate::tui::history::{ ExecCell, ExecSource, GenericToolCell, HistoryCell, ToolCell, ToolStatus, @@ -2421,6 +2422,21 @@ fn format_token_count_compact_formats_units() { assert_eq!(format_token_count_compact(1_000_000), "1.0M"); } +#[test] +fn footer_session_tokens_chip_uses_single_compact_total() { + let mut app = create_test_app(); + app.session.total_input_tokens = 900_000; + app.session.total_cache_hit_tokens = 700_000; + app.session.total_cache_miss_tokens = 200_000; + app.session.total_output_tokens = 600_000; + + let text = spans_text(&footer_session_tokens_spans(&app)); + + assert_eq!(text, "tok 1.5M"); + assert!(!text.contains(" cch ")); + assert!(!text.contains(" out")); +} + #[test] fn format_context_budget_caps_overflow_display() { assert_eq!(format_context_budget(5_000, 128_000), "5.0k/128.0k");