diff --git a/src/main.rs b/src/main.rs index bfa6c7c..5e17a1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use console::{Term, style}; use indicatif::{MultiProgress, ProgressBar, ProgressStyle, TermLike}; use crate::action::StartFields; -use crate::multibar::MultiBar; +use crate::multibar::{BarSegment, MultiBar}; use crate::state_manager::{BuildEnumState, BuildState, State, StateManager}; static LAZY: LazyLock = LazyLock::new(|| { @@ -89,10 +89,10 @@ fn main() -> Result<(), color_eyre::Report> { let term = Term::stdout(); let empty = style("-").blue().to_string(); let bar = MultiBar([ - ("=", 50, false), - (">", 1, true), - (empty.as_str(), 3, false), - (" ", 30, false), + BarSegment::Dynamic("=", 10), + BarSegment::Static(">"), + BarSegment::Dynamic(empty.as_str(), 3), + BarSegment::Dynamic(" ", 50), ]) .scale(u64::from(term.size().1 - 2)); println!("[{}]", bar); diff --git a/src/multibar.rs b/src/multibar.rs index 1e49e4b..cef2ed6 100644 --- a/src/multibar.rs +++ b/src/multibar.rs @@ -1,37 +1,92 @@ use std::fmt; +#[derive(Debug, Clone, Copy)] +pub enum BarSegment<'s> { + Dynamic(&'s str, u64), + Static(&'s str), +} + +impl<'s> BarSegment<'s> { + fn char(&self) -> &'s str { + match self { + BarSegment::Dynamic(c, _) => c, + BarSegment::Static(c) => c, + } + } + + fn length(&self) -> u64 { + match self { + BarSegment::Dynamic(c, len) => *len, + BarSegment::Static(c) => c.len() as u64, + } + } + + fn is_static(&self) -> bool { + matches!(self, BarSegment::Static(_)) + } + + fn scaled(&self, new_len: u64) -> Self { + match self { + BarSegment::Dynamic(c, _) => BarSegment::Dynamic(c, new_len), + BarSegment::Static(c) => BarSegment::Static(c), + } + } +} + #[derive(Debug)] -pub struct MultiBar<'s, const N: usize>(pub [(&'s str, u64, bool); N]); +pub struct MultiBar<'s, const N: usize>(pub [BarSegment<'s>; N]); impl MultiBar<'_, N> { - /// Total length of the bar - pub(crate) fn length(&self) -> u64 { - self.0.iter().map(|(_, len, _)| *len).sum::() + fn dynamic_length(&self) -> u64 { + self.0 + .iter() + .filter(|seg| !seg.is_static()) + .map(|seg| seg.length()) + .sum::() + } + + fn static_length(&self) -> u64 { + self.0 + .iter() + .filter(|seg| seg.is_static()) + .map(|seg| seg.length()) + .sum::() } /// Transforms the bar to be of target size + /// Static parts remain the same length, dynamic parts are scaled proportionally pub(crate) fn scale(&self, size: u64) -> Self { - let length = std::cmp::max(self.length(), 1); + let static_len = self.static_length(); + let dynamic_len = std::cmp::max(self.dynamic_length(), 1); + + let available_size = size.saturating_sub(static_len); + let mut prev_prop = 0; let mut curr_prop = 0; - let inner = self.0.map(|(c, len, const_len)| { - if const_len { - return (c, len, const_len); + let inner = self.0.map(|seg| match seg { + BarSegment::Static(_) => seg, + BarSegment::Dynamic(c, len) => { + curr_prop += len; + let nb_chars = available_size * curr_prop / dynamic_len + - available_size * prev_prop / dynamic_len; + prev_prop = curr_prop; + BarSegment::Dynamic(c, nb_chars) } - curr_prop += len; - let nb_chars = size * curr_prop / length - size * prev_prop / length; - - prev_prop = curr_prop; - (c, nb_chars, const_len) }); + Self(inner) } } impl fmt::Display for MultiBar<'_, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for &(c, len, _) in &self.0 { + for seg in &self.0 { + let (c, len) = match seg { + BarSegment::Dynamic(c, len) => (c, *len), + BarSegment::Static(c) => (c, c.len() as u64), + }; + for _ in 0..len { f.write_str(c)?; } diff --git a/src/state_manager.rs b/src/state_manager.rs index 2e0c822..a9cce68 100644 --- a/src/state_manager.rs +++ b/src/state_manager.rs @@ -8,6 +8,8 @@ pub struct State<'a> { pub multi_progress: MultiProgress, pub manager: StateManager<'a>, pub separator: Option, + pub width: u16, + pub current_width: u16, } impl<'a> State<'a> { @@ -74,7 +76,6 @@ pub struct BuildState<'a> { pub path: Option, pub progress_bar: Option, pub state: BuildEnumState<'a>, - ref_count: usize, } impl<'a> BuildState<'a> { pub fn new() -> Self { @@ -82,7 +83,6 @@ impl<'a> BuildState<'a> { path: None, progress_bar: None, state: BuildEnumState::Init, - ref_count: 1, } } }