mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
e896db1180
Instead of querying all 256 terminal colors on startup, which was slow in some terminals, hardcode the default xterm palette. Additionally, tweak the shimmer so that it blends between default_fg and default_bg, instead of "dark gray" (according to the terminal) and pure white (regardless of terminal theme).
81 lines
2.6 KiB
Rust
81 lines
2.6 KiB
Rust
use std::sync::OnceLock;
|
|
use std::time::Duration;
|
|
use std::time::Instant;
|
|
|
|
use ratatui::style::Color;
|
|
use ratatui::style::Modifier;
|
|
use ratatui::style::Style;
|
|
use ratatui::text::Span;
|
|
|
|
use crate::color::blend;
|
|
use crate::terminal_palette::default_bg;
|
|
use crate::terminal_palette::default_fg;
|
|
|
|
static PROCESS_START: OnceLock<Instant> = OnceLock::new();
|
|
|
|
fn elapsed_since_start() -> Duration {
|
|
let start = PROCESS_START.get_or_init(Instant::now);
|
|
start.elapsed()
|
|
}
|
|
|
|
pub(crate) fn shimmer_spans(text: &str) -> Vec<Span<'static>> {
|
|
let chars: Vec<char> = text.chars().collect();
|
|
if chars.is_empty() {
|
|
return Vec::new();
|
|
}
|
|
// Use time-based sweep synchronized to process start.
|
|
let padding = 10usize;
|
|
let period = chars.len() + padding * 2;
|
|
let sweep_seconds = 2.0f32;
|
|
let pos_f =
|
|
(elapsed_since_start().as_secs_f32() % sweep_seconds) / sweep_seconds * (period as f32);
|
|
let pos = pos_f as usize;
|
|
let has_true_color = supports_color::on_cached(supports_color::Stream::Stdout)
|
|
.map(|level| level.has_16m)
|
|
.unwrap_or(false);
|
|
let band_half_width = 5.0;
|
|
|
|
let mut spans: Vec<Span<'static>> = Vec::with_capacity(chars.len());
|
|
let base_color = default_fg().unwrap_or((128, 128, 128));
|
|
let highlight_color = default_bg().unwrap_or((255, 255, 255));
|
|
for (i, ch) in chars.iter().enumerate() {
|
|
let i_pos = i as isize + padding as isize;
|
|
let pos = pos as isize;
|
|
let dist = (i_pos - pos).abs() as f32;
|
|
|
|
let t = if dist <= band_half_width {
|
|
let x = std::f32::consts::PI * (dist / band_half_width);
|
|
0.5 * (1.0 + x.cos())
|
|
} else {
|
|
0.0
|
|
};
|
|
let style = if has_true_color {
|
|
let highlight = t.clamp(0.0, 1.0);
|
|
let (r, g, b) = blend(highlight_color, base_color, highlight * 0.9);
|
|
// Allow custom RGB colors, as the implementation is thoughtfully
|
|
// adjusting the level of the default foreground color.
|
|
#[allow(clippy::disallowed_methods)]
|
|
{
|
|
Style::default()
|
|
.fg(Color::Rgb(r, g, b))
|
|
.add_modifier(Modifier::BOLD)
|
|
}
|
|
} else {
|
|
color_for_level(t)
|
|
};
|
|
spans.push(Span::styled(ch.to_string(), style));
|
|
}
|
|
spans
|
|
}
|
|
|
|
fn color_for_level(intensity: f32) -> Style {
|
|
// Tune fallback styling so the shimmer band reads even without RGB support.
|
|
if intensity < 0.2 {
|
|
Style::default().add_modifier(Modifier::DIM)
|
|
} else if intensity < 0.6 {
|
|
Style::default()
|
|
} else {
|
|
Style::default().add_modifier(Modifier::BOLD)
|
|
}
|
|
}
|