tui: breathing spinner on true-color terms (#4853)
uses the same logic as shimmer_spans to render the `•` spinner. on terminals without true-color support, fall back to the existing `•/◦` blinking logic. https://github.com/user-attachments/assets/19db76f2-8fa2-440d-9fde-7bed67f4c4dc
This commit is contained in:
@@ -8,6 +8,7 @@ use crate::history_cell::HistoryCell;
|
|||||||
use crate::render::highlight::highlight_bash_to_lines;
|
use crate::render::highlight::highlight_bash_to_lines;
|
||||||
use crate::render::line_utils::prefix_lines;
|
use crate::render::line_utils::prefix_lines;
|
||||||
use crate::render::line_utils::push_owned_lines;
|
use crate::render::line_utils::push_owned_lines;
|
||||||
|
use crate::shimmer::shimmer_spans;
|
||||||
use crate::wrapping::RtOptions;
|
use crate::wrapping::RtOptions;
|
||||||
use crate::wrapping::word_wrap_line;
|
use crate::wrapping::word_wrap_line;
|
||||||
use codex_ansi_escape::ansi_escape_line;
|
use codex_ansi_escape::ansi_escape_line;
|
||||||
@@ -116,10 +117,16 @@ pub(crate) fn output_lines(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn spinner(start_time: Option<Instant>) -> Span<'static> {
|
pub(crate) fn spinner(start_time: Option<Instant>) -> Span<'static> {
|
||||||
let blink_on = start_time
|
let elapsed = start_time.map(|st| st.elapsed()).unwrap_or_default();
|
||||||
.map(|st| ((st.elapsed().as_millis() / 600) % 2) == 0)
|
if supports_color::on_cached(supports_color::Stream::Stdout)
|
||||||
.unwrap_or(false);
|
.map(|level| level.has_16m)
|
||||||
if blink_on { "•".into() } else { "◦".dim() }
|
.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 {
|
impl HistoryCell for ExecCell {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use ratatui::widgets::WidgetRef;
|
|||||||
|
|
||||||
use crate::app_event::AppEvent;
|
use crate::app_event::AppEvent;
|
||||||
use crate::app_event_sender::AppEventSender;
|
use crate::app_event_sender::AppEventSender;
|
||||||
|
use crate::exec_cell::spinner;
|
||||||
use crate::key_hint;
|
use crate::key_hint;
|
||||||
use crate::shimmer::shimmer_spans;
|
use crate::shimmer::shimmer_spans;
|
||||||
use crate::tui::FrameRequester;
|
use crate::tui::FrameRequester;
|
||||||
@@ -163,15 +164,11 @@ impl WidgetRef for StatusIndicatorWidget {
|
|||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let elapsed_duration = self.elapsed_duration_at(now);
|
let elapsed_duration = self.elapsed_duration_at(now);
|
||||||
let pretty_elapsed = fmt_elapsed_compact(elapsed_duration.as_secs());
|
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.
|
// Plain rendering: no borders or padding so the live cell is visually indistinguishable from terminal scrollback.
|
||||||
let mut spans = Vec::with_capacity(5);
|
let mut spans = Vec::with_capacity(5);
|
||||||
if blink_on {
|
spans.push(spinner(Some(self.last_resume_at)));
|
||||||
spans.push("• ".into());
|
spans.push(" ".into());
|
||||||
} else {
|
|
||||||
spans.push("◦ ".dim());
|
|
||||||
}
|
|
||||||
spans.extend(shimmer_spans(&self.header));
|
spans.extend(shimmer_spans(&self.header));
|
||||||
spans.extend(vec![
|
spans.extend(vec![
|
||||||
" ".into(),
|
" ".into(),
|
||||||
|
|||||||
Reference in New Issue
Block a user