use super::styles;
use crate::{BarExt, std::Bar, term::Colorizer};
use std::num::{NonZeroI16, NonZeroU16};
#[cfg(feature = "spinner")]
use crate::spinner::Spinner;
#[derive(Debug, Clone)]
pub enum Column {
Animation,
Count,
CountTotal,
ElapsedTime,
Percentage(usize),
Rate,
RemainingTime,
#[cfg(feature = "spinner")]
#[cfg_attr(docsrs, doc(cfg(feature = "spinner")))]
Spinner(Spinner),
Text(String),
Total,
}
#[derive(BarExt, Debug)]
pub struct RichProgress {
pub columns: Vec<Column>,
#[bar]
pub pb: Bar,
}
impl RichProgress {
pub fn new(pb: Bar, columns: Vec<Column>) -> Self {
Self { columns, pb }
}
pub fn replace(&mut self, index: usize, col: Column) {
*self.columns.get_mut(index).unwrap() = col;
}
pub fn render(&mut self) -> String {
let mut bar_text = vec![];
let mut bar_length = 0;
let mut progress_bar_index = None;
for col in self.columns.iter() {
match col {
Column::Animation => {
progress_bar_index = Some(bar_text.len());
bar_text.push(String::new());
}
Column::Count => {
let fmt_progress = self.pb.fmt_counter();
bar_length += fmt_progress.len();
bar_text.push(fmt_progress.colorize("green"));
}
Column::CountTotal => {
let fmt_progress = format!("{}/{}", self.pb.fmt_counter(), self.pb.fmt_total());
bar_length += fmt_progress.len();
bar_text.push(fmt_progress.colorize("green"));
}
Column::ElapsedTime => {
let elapsed_time = self.pb.fmt_elapsed_time();
bar_length += elapsed_time.len();
bar_text.push(elapsed_time.colorize("cyan"));
}
Column::Percentage(precision) => {
let percentage = format!("{:.1$}%", self.pb.percentage() * 100., precision);
bar_length += percentage.len();
bar_text.push(percentage.colorize("magenta"));
}
Column::Rate => {
let rate = self.pb.fmt_rate();
bar_length += rate.len();
bar_text.push(rate.colorize("red"));
}
Column::RemainingTime => {
let remaining_time = self.pb.fmt_remaining_time();
bar_length += remaining_time.len();
bar_text.push(remaining_time.colorize("cyan"));
}
#[cfg(feature = "spinner")]
Column::Spinner(spinner) => {
let frame = spinner.render_frame(self.pb.elapsed_time());
bar_length += frame.chars().count();
bar_text.push(frame.colorize("green"));
}
Column::Text(text) => {
let (color, text_start_index) = match (text.find('['), text.find(']')) {
(Some(start), Some(end)) => {
if start == 0 {
(text.get(1..end), end + 1)
} else {
(None, 0)
}
}
_ => (None, 0),
};
if let Some(code) = color {
let text = &text[text_start_index..];
bar_length += text.len_ansi();
bar_text.push(text.colorize(code));
} else {
bar_length += text.len_ansi();
bar_text.push(text.to_owned());
}
}
Column::Total => {
let fmt_progress = self.pb.fmt_total();
bar_length += fmt_progress.len();
bar_text.push(fmt_progress.colorize("green"));
}
}
}
bar_length += bar_text.len() - 1;
let mut ncols = 0;
if let Some(progress_bar_index) = progress_bar_index {
ncols = self.pb.ncols_for_animation(bar_length as u16);
if ncols == 0 {
let _ = bar_text.remove(progress_bar_index);
} else {
*bar_text.get_mut(progress_bar_index).unwrap() =
if self.pb.indefinite() || !self.pb.started() {
styles::pulse(
NonZeroI16::new(ncols as i16).unwrap(),
self.pb.elapsed_time(),
)
} else {
styles::bar(NonZeroU16::new(ncols).unwrap(), self.pb.percentage())
};
}
}
self.pb.bar_length = ncols + bar_length as u16;
bar_text.join(" ")
}
}