use indicatif::{
MultiProgress as IndicatifMultiProgress, ProgressBar as IndicatifBar,
ProgressStyle as IndicatifStyle,
};
use std::time::Duration;
pub use indicatif::MultiProgress as RawMultiProgress;
#[derive(Clone, Copy)]
pub enum ProgressStyle {
Bar,
Spinner,
Download,
Finished,
}
impl ProgressStyle {
fn to_indicatif(self) -> IndicatifStyle {
match self {
Self::Bar => style_or_default(
"{prefix:.bold} {wide_bar:.cyan/dim} {pos}/{len} {percent}% {elapsed}",
IndicatifStyle::default_bar,
)
.progress_chars("━╸─"),
Self::Spinner => style_or_default(
"{spinner:.green} {prefix} {wide_msg}",
IndicatifStyle::default_spinner,
),
Self::Download => style_or_default(
"{prefix:.bold} {wide_bar:.green/dim} {bytes}/{total_bytes} {bytes_per_sec} {eta}",
IndicatifStyle::default_bar,
)
.progress_chars("━╸─"),
Self::Finished => {
style_or_default("{prefix} {wide_msg}", IndicatifStyle::default_spinner)
}
}
}
}
fn style_or_default(template: &str, fallback: impl FnOnce() -> IndicatifStyle) -> IndicatifStyle {
IndicatifStyle::with_template(template).unwrap_or_else(|_| fallback())
}
pub struct ProgressBar {
inner: IndicatifBar,
}
impl ProgressBar {
pub fn new(total: u64, style: ProgressStyle) -> Self {
let bar = IndicatifBar::new(total);
bar.set_style(style.to_indicatif());
bar.enable_steady_tick(Duration::from_millis(100));
Self { inner: bar }
}
pub fn spinner() -> Self {
let bar = IndicatifBar::new_spinner();
bar.set_style(ProgressStyle::Spinner.to_indicatif());
bar.enable_steady_tick(Duration::from_millis(80));
Self { inner: bar }
}
pub fn set_prefix(&self, prefix: impl Into<String>) {
self.inner.set_prefix(prefix.into());
}
pub fn set_style(&self, style: ProgressStyle) {
self.inner.set_style(style.to_indicatif());
}
pub fn set_message(&self, msg: impl Into<String>) {
self.inner.set_message(msg.into());
}
pub fn enable_steady_tick(&self, interval: Duration) {
self.inner.enable_steady_tick(interval);
}
pub fn tick(&self) {
self.inner.tick();
}
pub fn set_position(&self, pos: u64) {
self.inner.set_position(pos);
}
pub fn inc(&self, delta: u64) {
self.inner.inc(delta);
}
pub fn set_length(&self, len: u64) {
self.inner.set_length(len);
}
pub fn finish(&self) {
self.inner.finish();
}
pub fn finish_with_message(&self, msg: impl Into<std::borrow::Cow<'static, str>>) {
self.inner.finish_with_message(msg);
}
pub fn reset(&self) {
self.inner.reset();
}
pub fn finish_and_clear(&self) {
self.inner.finish_and_clear();
}
pub const fn inner(&self) -> &IndicatifBar {
&self.inner
}
}
pub struct MultiProgress {
inner: IndicatifMultiProgress,
}
impl MultiProgress {
#[must_use]
pub fn new() -> Self {
Self {
inner: IndicatifMultiProgress::new(),
}
}
#[must_use]
pub const fn from_raw(mp: IndicatifMultiProgress) -> Self {
Self { inner: mp }
}
pub const fn raw(&self) -> &IndicatifMultiProgress {
&self.inner
}
pub fn add_bar(&self, prefix: impl Into<String>, total: u64) -> ProgressBar {
let bar = IndicatifBar::new(total);
bar.set_style(ProgressStyle::Bar.to_indicatif());
bar.set_prefix(prefix.into());
let bar = self.inner.add(bar);
ProgressBar { inner: bar }
}
pub fn insert_bar_after(
&self,
after: &ProgressBar,
prefix: impl Into<String>,
total: u64,
) -> ProgressBar {
let bar = IndicatifBar::new(total);
bar.set_style(ProgressStyle::Bar.to_indicatif());
bar.set_prefix(prefix.into());
let bar = self.inner.insert_after(after.inner(), bar);
ProgressBar { inner: bar }
}
pub fn add_spinner(&self, prefix: impl Into<String>) -> ProgressBar {
let bar = IndicatifBar::new_spinner();
bar.set_style(ProgressStyle::Spinner.to_indicatif());
bar.set_prefix(prefix.into());
bar.enable_steady_tick(Duration::from_millis(120));
let bar = self.inner.add(bar);
ProgressBar { inner: bar }
}
pub fn add_static_line(
&self,
prefix: impl Into<String>,
msg: impl Into<std::borrow::Cow<'static, str>>,
) -> ProgressBar {
let bar = IndicatifBar::new(0);
bar.set_style(ProgressStyle::Finished.to_indicatif());
bar.set_prefix(prefix.into());
bar.finish_with_message(msg);
let bar = self.inner.add(bar);
ProgressBar { inner: bar }
}
pub fn println(&self, msg: impl AsRef<str>) -> std::io::Result<()> {
self.inner.println(msg)
}
pub fn remove(&self, bar: &ProgressBar) {
self.inner.remove(bar.inner());
}
pub fn clear(&self) -> std::io::Result<()> {
self.inner.clear()
}
}
impl Default for MultiProgress {
fn default() -> Self {
Self::new()
}
}