use ratatui::symbols;
pub(super) const DOTS: symbols::bar::Set = symbols::bar::Set {
empty: " ",
one_eighth: "⡀",
one_quarter: "⣀",
three_eighths: "⣄",
half: "⣤",
five_eighths: "⣦",
three_quarters: "⣶",
seven_eighths: "⣷",
full: "⣿",
};
pub(super) const REV_DOTS: symbols::bar::Set = symbols::bar::Set {
empty: " ",
one_eighth: "⠁",
one_quarter: "⠉",
three_eighths: "⠋",
half: "⠛",
five_eighths: "⠟",
three_quarters: "⠿",
seven_eighths: "⡿",
full: "⣿",
};
pub(super) fn proxy_wave_lines(
width: u16,
height: u16,
current_app_routed: bool,
samples: &[u64],
bar_set: &symbols::bar::Set,
reversed: bool,
) -> Vec<String> {
if width == 0 || height == 0 {
return Vec::new();
}
let width = width as usize;
let height = height as usize;
let recent = recent_samples(width, current_app_routed, samples);
let mut scaled = scale_samples(height as u16, &recent, current_app_routed);
let mut rows = vec![String::with_capacity(width * 3); height];
for j in (0..height).rev() {
let row_index = if reversed { height - j - 1 } else { j };
for value in &mut scaled {
rows[row_index].push_str(bar_symbol(*value, bar_set));
if *value > 8 {
*value -= 8;
} else {
*value = 0;
}
}
}
rows
}
fn recent_samples(width: usize, current_app_routed: bool, samples: &[u64]) -> Vec<u64> {
if !current_app_routed {
return vec![0; width];
}
let recent = if samples.len() > width {
&samples[samples.len() - width..]
} else {
samples
};
let mut out = vec![0; width.saturating_sub(recent.len())];
out.extend_from_slice(recent);
out
}
fn scale_samples(height: u16, samples: &[u64], show_idle_baseline: bool) -> Vec<u64> {
let baseline = if show_idle_baseline { 1 } else { 0 };
let max = samples.iter().copied().max().unwrap_or(0);
if max == 0 {
return vec![baseline; samples.len()];
}
samples
.iter()
.map(|value| {
if *value == 0 {
baseline
} else {
(value * u64::from(height) * 8 / max).max(baseline + 1)
}
})
.collect()
}
fn bar_symbol<'a>(level: u64, bar_set: &'a symbols::bar::Set) -> &'a str {
match level {
0 => bar_set.empty,
1 => bar_set.one_eighth,
2 => bar_set.one_quarter,
3 => bar_set.three_eighths,
4 => bar_set.half,
5 => bar_set.five_eighths,
6 => bar_set.three_quarters,
7 => bar_set.seven_eighths,
_ => bar_set.full,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn proxy_wave_lines_left_pads_recent_samples() {
let rows = proxy_wave_lines(8, 1, true, &[0, 1, 4, 8], &DOTS, false);
assert_eq!(rows, vec!["⡀⡀⡀⡀⡀⣀⣤⣿".to_string()]);
}
#[test]
fn proxy_wave_lines_reverses_rows_for_lower_half() {
let rows = proxy_wave_lines(4, 2, true, &[0, 1, 4, 8], &REV_DOTS, true);
assert_eq!(rows.len(), 2);
assert!(rows[0].contains('⠁') || rows[0].contains('⠉'));
assert!(rows[0].contains('⣿'));
assert!(rows[1].contains('⣿'));
}
#[test]
fn proxy_wave_lines_keep_baseline_when_burst_appears() {
let upper = proxy_wave_lines(8, 1, true, &[0, 1, 4, 8], &DOTS, false);
let lower = proxy_wave_lines(8, 1, true, &[0, 1, 4, 8], &REV_DOTS, true);
assert!(upper[0].contains('⡀'), "{:?}", upper);
assert!(lower[0].contains('⠁'), "{:?}", lower);
assert!(upper[0].contains('⣿'), "{:?}", upper);
}
}