#![warn(missing_docs)]
use crossterm::{cursor, queue, terminal};
use std::io::Write;
pub mod bar;
pub trait TaskProgress {
fn progress(&self) -> (u64, u64);
fn before(&self) -> Option<String> {
None
}
fn after(&self) -> Option<String> {
None
}
}
pub trait ProgressBar {
type Task: TaskProgress;
fn format_line(&self, progress: &Self::Task, width: usize) -> String;
}
pub struct MultiProgressBar<P: ProgressBar> {
progress_bar: P,
}
impl<P: ProgressBar> MultiProgressBar<P> {
pub fn new(progress_bar: P) -> Self {
MultiProgressBar { progress_bar }
}
pub fn log(&self, msg: &str, ntasks: usize) -> std::io::Result<()> {
let (width, height) = crossterm::terminal::size().unwrap();
let mut stdout = std::io::stdout();
queue!(
stdout,
cursor::MoveToRow(height - ntasks as u16 - 1),
cursor::MoveToColumn(0),
terminal::ScrollUp(1),
)?;
write!(stdout, "{:width$}", msg, width = width as usize)
}
pub fn draw(&self, tasks: &[P::Task]) -> std::io::Result<()> {
let (width, height) = crossterm::terminal::size().unwrap();
let mut stdout = std::io::stdout();
queue!(
stdout,
terminal::BeginSynchronizedUpdate,
cursor::MoveToColumn(0),
cursor::MoveToRow(height - tasks.len() as u16 - 1),
)?;
for task in tasks {
let line = self.progress_bar.format_line(task, width as usize);
queue!(stdout, cursor::MoveToColumn(0), cursor::MoveDown(1))?;
write!(stdout, "{}", line)?;
}
queue!(
stdout,
terminal::EndSynchronizedUpdate,
cursor::MoveToColumn(0),
)?;
stdout.flush()?;
Ok(())
}
}