Files
nix-output/src/multibar.rs
2025-11-12 06:10:37 +00:00

98 lines
2.5 KiB
Rust

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 [BarSegment<'s>; N]);
impl<const N: usize> MultiBar<'_, N> {
fn dynamic_length(&self) -> u64 {
self.0
.iter()
.filter(|seg| !seg.is_static())
.map(|seg| seg.length())
.sum::<u64>()
}
fn static_length(&self) -> u64 {
self.0
.iter()
.filter(|seg| seg.is_static())
.map(|seg| seg.length())
.sum::<u64>()
}
/// 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 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(|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)
}
});
Self(inner)
}
}
impl<const N: usize> fmt::Display for MultiBar<'_, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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)?;
}
}
Ok(())
}
}