diff --git a/codex-rs/tui/src/exec_cell/render.rs b/codex-rs/tui/src/exec_cell/render.rs index 9c1231f0cf..51824ddc3c 100644 --- a/codex-rs/tui/src/exec_cell/render.rs +++ b/codex-rs/tui/src/exec_cell/render.rs @@ -8,6 +8,7 @@ use crate::history_cell::HistoryCell; use crate::render::highlight::highlight_bash_to_lines; use crate::render::line_utils::prefix_lines; use crate::render::line_utils::push_owned_lines; +use crate::shimmer::shimmer_spans; use crate::wrapping::RtOptions; use crate::wrapping::word_wrap_line; use codex_ansi_escape::ansi_escape_line; @@ -116,10 +117,16 @@ pub(crate) fn output_lines( } pub(crate) fn spinner(start_time: Option) -> Span<'static> { - let blink_on = start_time - .map(|st| ((st.elapsed().as_millis() / 600) % 2) == 0) - .unwrap_or(false); - if blink_on { "•".into() } else { "◦".dim() } + let elapsed = start_time.map(|st| st.elapsed()).unwrap_or_default(); + if supports_color::on_cached(supports_color::Stream::Stdout) + .map(|level| level.has_16m) + .unwrap_or(false) + { + shimmer_spans("•")[0].clone() + } else { + let blink_on = (elapsed.as_millis() / 600).is_multiple_of(2); + if blink_on { "•".into() } else { "◦".dim() } + } } impl HistoryCell for ExecCell { diff --git a/codex-rs/tui/src/status_indicator_widget.rs b/codex-rs/tui/src/status_indicator_widget.rs index e60204cdb8..ce4f6eabd8 100644 --- a/codex-rs/tui/src/status_indicator_widget.rs +++ b/codex-rs/tui/src/status_indicator_widget.rs @@ -15,6 +15,7 @@ use ratatui::widgets::WidgetRef; use crate::app_event::AppEvent; use crate::app_event_sender::AppEventSender; +use crate::exec_cell::spinner; use crate::key_hint; use crate::shimmer::shimmer_spans; use crate::tui::FrameRequester; @@ -163,15 +164,11 @@ impl WidgetRef for StatusIndicatorWidget { let now = Instant::now(); let elapsed_duration = self.elapsed_duration_at(now); let pretty_elapsed = fmt_elapsed_compact(elapsed_duration.as_secs()); - let blink_on = (elapsed_duration.as_millis() / 600).is_multiple_of(2); // Plain rendering: no borders or padding so the live cell is visually indistinguishable from terminal scrollback. let mut spans = Vec::with_capacity(5); - if blink_on { - spans.push("• ".into()); - } else { - spans.push("◦ ".dim()); - } + spans.push(spinner(Some(self.last_resume_at))); + spans.push(" ".into()); spans.extend(shimmer_spans(&self.header)); spans.extend(vec![ " ".into(),