mirror of
https://github.com/openai/codex.git
synced 2026-10-31 19:28:49 +00:00
## What changed Replace the continuous two-second shimmer with a 600 ms initial delay and a one-second sweep every four seconds, matching the desktop app's thinking and reasoning header timings. ## Testing Update snapshots for short, long, and Unicode labels in both themes to cover the initial delay, sweep, gap, and next sweep. Sample smoothness across two sweeps at 32 ms intervals and adjust the brightness-change bound for the faster sweep. GitOrigin-RevId: d7a6a81db99bf0e8a73eee0c67eb7e44d4d76f42
65 lines
2.5 KiB
Rust
65 lines
2.5 KiB
Rust
//! Smooth, whole-grapheme status shimmer with the desktop's cadenced sweep.
|
|
//!
|
|
//! Only brightness changes: the moving band uses the terminal foreground, while
|
|
//! the remaining text blends halfway into the background. The wave spans at
|
|
//! least six terminal columns so short labels do not flash one letter at a time.
|
|
//! New headers wait 600 ms, then sweep for one second every four seconds.
|
|
//! Unknown palettes use static dim text instead of a stepped animation.
|
|
|
|
use std::time::Duration;
|
|
|
|
use ratatui::style::Style;
|
|
use ratatui::text::Span;
|
|
use unicode_segmentation::UnicodeSegmentation;
|
|
use unicode_width::UnicodeWidthStr;
|
|
|
|
use crate::color::blend;
|
|
use crate::motion::MotionMode;
|
|
use crate::terminal_palette::StdoutColorLevel;
|
|
use crate::terminal_palette::default_bg;
|
|
use crate::terminal_palette::default_fg;
|
|
use crate::terminal_palette::effective_stdout_color_level;
|
|
use crate::terminal_palette::rgb_color;
|
|
|
|
// Match the desktop app's thinking and reasoning header timings.
|
|
const START_DELAY: Duration = Duration::from_millis(/*millis*/ 600);
|
|
const SWEEP_SECONDS: f64 = 1.0;
|
|
const INTERVAL_SECONDS: f64 = 4.0;
|
|
|
|
pub(crate) fn summary_shimmer(
|
|
text: &str,
|
|
elapsed: Duration,
|
|
motion: MotionMode,
|
|
) -> Vec<Span<'static>> {
|
|
if motion == MotionMode::Reduced {
|
|
return vec![text.to_owned().into()];
|
|
}
|
|
let (StdoutColorLevel::TrueColor, Some(fg), Some(bg)) =
|
|
(effective_stdout_color_level(), default_fg(), default_bg())
|
|
else {
|
|
return vec![Span::styled(text.to_owned(), Style::default().dim())];
|
|
};
|
|
let width = text.width() as f64;
|
|
let half_width = (width * 0.1).max(/*other*/ 3.0);
|
|
let sweep =
|
|
(elapsed.saturating_sub(START_DELAY).as_secs_f64() % INTERVAL_SECONDS).min(SWEEP_SECONDS);
|
|
let position = sweep / SWEEP_SECONDS * (width + 2.0 * half_width) - half_width;
|
|
let mut column = 0.0;
|
|
text.graphemes(/*is_extended*/ true)
|
|
.map(|grapheme| {
|
|
let glyph_width = grapheme.width() as f64;
|
|
let center = column + glyph_width / 2.0;
|
|
column += glyph_width;
|
|
let distance = ((center - position).abs() / half_width).min(/*other*/ 1.0);
|
|
let intensity = 0.5 * (1.0 + (std::f64::consts::PI * distance).cos());
|
|
let alpha = (0.5 + 0.5 * intensity) as f32;
|
|
let style = Style::default().fg(rgb_color(blend(fg, bg, alpha)));
|
|
Span::styled(grapheme.to_owned(), style)
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "summary_shimmer_tests.rs"]
|
|
mod tests;
|