update composer + user message styling (#4240)

Changes:

- the composer and user messages now have a colored background that
stretches the entire width of the terminal.
- the prompt character was changed from a cyan `▌` to a bold `›`.
- the "working" shimmer now follows the "dark gray" color of the
terminal, better matching the terminal's color scheme

| Terminal + Background        | Screenshot |
|------------------------------|------------|
| iTerm with dark bg | <img width="810" height="641" alt="Screenshot
2025-09-25 at 11 44 52 AM"
src="https://github.com/user-attachments/assets/1317e579-64a9-4785-93e6-98b0258f5d92"
/> |
| iTerm with light bg | <img width="845" height="540" alt="Screenshot
2025-09-25 at 11 46 29 AM"
src="https://github.com/user-attachments/assets/e671d490-c747-4460-af0b-3f8d7f7a6b8e"
/> |
| iTerm with color bg | <img width="825" height="564" alt="Screenshot
2025-09-25 at 11 47 12 AM"
src="https://github.com/user-attachments/assets/141cda1b-1164-41d5-87da-3be11e6a3063"
/> |
| Terminal.app with dark bg | <img width="577" height="367"
alt="Screenshot 2025-09-25 at 11 45 22 AM"
src="https://github.com/user-attachments/assets/93fc4781-99f7-4ee7-9c8e-3db3cd854fe5"
/> |
| Terminal.app with light bg | <img width="577" height="367"
alt="Screenshot 2025-09-25 at 11 46 04 AM"
src="https://github.com/user-attachments/assets/19bf6a3c-91e0-447b-9667-b8033f512219"
/> |
| Terminal.app with color bg | <img width="577" height="367"
alt="Screenshot 2025-09-25 at 11 45 50 AM"
src="https://github.com/user-attachments/assets/dd7c4b5b-342e-4028-8140-f4e65752bd0b"
/> |
This commit is contained in:
Jeremy Rose
2025-09-26 16:35:56 -07:00
committed by GitHub
parent cc1b21e47f
commit 43b63ccae8
50 changed files with 1181 additions and 623 deletions

View File

@@ -7,6 +7,12 @@ use ratatui::style::Modifier;
use ratatui::style::Style;
use ratatui::text::Span;
use crate::color::blend;
use crate::terminal_palette::default_fg;
use crate::terminal_palette::terminal_palette;
const FALLBACK_DARK_GRAY: (u8, u8, u8) = (103, 103, 103);
static PROCESS_START: OnceLock<Instant> = OnceLock::new();
fn elapsed_since_start() -> Duration {
@@ -32,6 +38,8 @@ pub(crate) fn shimmer_spans(text: &str) -> Vec<Span<'static>> {
let band_half_width = 3.0;
let mut spans: Vec<Span<'static>> = Vec::with_capacity(chars.len());
let default_fg = default_fg();
let palette_dark_gray = terminal_palette().map(|palette| palette[8]);
for (i, ch) in chars.iter().enumerate() {
let i_pos = i as isize + padding as isize;
let pos = pos as isize;
@@ -43,31 +51,33 @@ pub(crate) fn shimmer_spans(text: &str) -> Vec<Span<'static>> {
} else {
0.0
};
let brightness = 0.4 + 0.6 * t;
let level = (brightness * 255.0).clamp(0.0, 255.0) as u8;
let style = if has_true_color {
let base = palette_dark_gray
.or(default_fg)
.unwrap_or(FALLBACK_DARK_GRAY);
let highlight = t.clamp(0.0, 1.0);
let (r, g, b) = blend((255, 255, 255), base, highlight);
// 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(level, level, level))
.fg(Color::Rgb(r, g, b))
.add_modifier(Modifier::BOLD)
}
} else {
color_for_level(level)
color_for_level(t)
};
spans.push(Span::styled(ch.to_string(), style));
}
spans
}
fn color_for_level(level: u8) -> Style {
// Tune thresholds so the edges of the shimmer band appear dim
// in fallback mode (no true color support).
if level < 160 {
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 level < 224 {
} else if intensity < 0.6 {
Style::default()
} else {
Style::default().add_modifier(Modifier::BOLD)