diff options
| author | Mo <76752051+mo8it@users.noreply.github.com> | 2024-04-14 17:13:32 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-14 17:13:32 +0200 |
| commit | dc02c38a945fcafacf6d2d35f5d3e317e7185cb0 (patch) | |
| tree | bd3ad843a575650881b220c4b008fc7509917d24 /src/progress_bar.rs | |
| parent | 8c8f30d8ce3b732de649938d8945496bd769ac22 (diff) | |
| parent | 7526c6b1f92626df6ab8b4853535b73711bfada4 (diff) | |
Merge pull request #1942 from rust-lang/tui
TUI
Diffstat (limited to 'src/progress_bar.rs')
| -rw-r--r-- | src/progress_bar.rs | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/progress_bar.rs b/src/progress_bar.rs new file mode 100644 index 0000000..d6962b8 --- /dev/null +++ b/src/progress_bar.rs @@ -0,0 +1,97 @@ +use anyhow::{bail, Result}; +use ratatui::text::{Line, Span}; +use std::fmt::Write; + +const PREFIX: &str = "Progress: ["; +const PREFIX_WIDTH: u16 = PREFIX.len() as u16; +// Leaving the last char empty (_) for `total` > 99. +const POSTFIX_WIDTH: u16 = "] xxx/xx exercises_".len() as u16; +const WRAPPER_WIDTH: u16 = PREFIX_WIDTH + POSTFIX_WIDTH; +const MIN_LINE_WIDTH: u16 = WRAPPER_WIDTH + 4; + +const PROGRESS_EXCEEDS_MAX_ERR: &str = + "The progress of the progress bar is higher than the maximum"; + +pub fn progress_bar(progress: u16, total: u16, line_width: u16) -> Result<String> { + use crossterm::style::Stylize; + + if progress > total { + bail!(PROGRESS_EXCEEDS_MAX_ERR); + } + + if line_width < MIN_LINE_WIDTH { + return Ok(format!("Progress: {progress}/{total} exercises")); + } + + let mut line = String::with_capacity(usize::from(line_width)); + line.push_str(PREFIX); + + let width = line_width - WRAPPER_WIDTH; + let filled = (width * progress) / total; + + let mut green_part = String::with_capacity(usize::from(filled + 1)); + for _ in 0..filled { + green_part.push('#'); + } + + if filled < width { + green_part.push('>'); + } + write!(line, "{}", green_part.green()).unwrap(); + + let width_minus_filled = width - filled; + if width_minus_filled > 1 { + let red_part_width = width_minus_filled - 1; + let mut red_part = String::with_capacity(usize::from(red_part_width)); + for _ in 0..red_part_width { + red_part.push('-'); + } + write!(line, "{}", red_part.red()).unwrap(); + } + + writeln!(line, "] {progress:>3}/{total} exercises").unwrap(); + + Ok(line) +} + +pub fn progress_bar_ratatui(progress: u16, total: u16, line_width: u16) -> Result<Line<'static>> { + use ratatui::style::Stylize; + + if progress > total { + bail!(PROGRESS_EXCEEDS_MAX_ERR); + } + + if line_width < MIN_LINE_WIDTH { + return Ok(Line::raw(format!("Progress: {progress}/{total} exercises"))); + } + + let mut spans = Vec::with_capacity(4); + spans.push(Span::raw(PREFIX)); + + let width = line_width - WRAPPER_WIDTH; + let filled = (width * progress) / total; + + let mut green_part = String::with_capacity(usize::from(filled + 1)); + for _ in 0..filled { + green_part.push('#'); + } + + if filled < width { + green_part.push('>'); + } + spans.push(green_part.green()); + + let width_minus_filled = width - filled; + if width_minus_filled > 1 { + let red_part_width = width_minus_filled - 1; + let mut red_part = String::with_capacity(usize::from(red_part_width)); + for _ in 0..red_part_width { + red_part.push('-'); + } + spans.push(red_part.red()); + } + + spans.push(Span::raw(format!("] {progress:>3}/{total} exercises"))); + + Ok(Line::from(spans)) +} |
