work on multibar

This commit is contained in:
2025-11-11 13:29:01 +04:00
parent 15e8bf5e69
commit 50176e5db4
3 changed files with 131 additions and 47 deletions

View File

@@ -8,6 +8,7 @@ use crate::state_manager::{BuildEnumState, BuildState, State, StateManager};
pub mod action;
pub mod action_raw;
pub mod multibar;
pub mod nix_path;
pub mod state_manager;
#[derive(Debug, Clone)]
@@ -62,35 +63,36 @@ impl TermLike for TextTerm {
fn main() -> Result<(), color_eyre::Report> {
color_eyre::install().unwrap();
let pb = ProgressBar::new(100);
pb.set_draw_target(indicatif::ProgressDrawTarget::term_like(Box::new(TextTerm)));
// let pb = ProgressBar::new(100);
// pb.set_draw_target(indicatif::ProgressDrawTarget::term_like(Box::new(TextTerm)));
//
// pb.set_style(
// ProgressStyle::default_bar()
// .template("{msg} [{bar:40.cyan/blue}] {pos:>3}%")
// .unwrap(),
// );
// pb.set_message("Example Progress Bar");
// for i in 0..=5 {
// pb.set_position(i);
// sleep(Duration::from_millis(50));
// }
// pb.finish_and_clear();
pb.set_style(
ProgressStyle::default_bar()
.template("{msg} [{bar:40.cyan/blue}] {pos:>3}%")
.unwrap(),
);
pb.set_message("Example Progress Bar");
for i in 0..=5 {
pb.set_position(i);
sleep(Duration::from_millis(50));
}
pb.finish_and_clear();
return Ok(());
// return Ok(());
let lines = std::fs::read_to_string("build.log")?;
let lines = lines.lines().take(0).collect::<Vec<_>>().join("\n");
// let lines = lines.lines().take(0).collect::<Vec<_>>().join("\n");
let mut state = State {
progress: MultiProgress::new(),
multi_progress: MultiProgress::new(),
manager: StateManager::new(),
separator: None,
};
// let progress = MultiProgress::new();
let lines_pb = state
.progress
.add(ProgressBar::new(lines.lines().count() as u64));
// let lines_pb = state
// .multi_progress
// .add(ProgressBar::new(lines.lines().count() as u64));
// progress.println("Parsing build.log...")?;
// let pb1 = progress.add(ProgressBar::new(lines.lines().count() as u64));
// pb1.set_style(
@@ -111,15 +113,13 @@ fn main() -> Result<(), color_eyre::Report> {
// let mut map = HashMap::new();
for line in lines.lines() {
lines_pb.inc(1);
// lines_pb.inc(1);
let line = line.strip_prefix("@nix ").unwrap_or(line);
sleep(Duration::from_millis(1));
let action = action::Action::parse(line)?;
match action {
action::Action::Msg { level, msg } => {
state
.progress
.println(format!("MSG (level {level}): {msg}"))?;
state.println(format!("MSG (level {level}): {msg}"))?;
}
action::Action::Start {
start_type,
@@ -192,7 +192,7 @@ fn main() -> Result<(), color_eyre::Report> {
}
action::Action::Result { id, fields } => match fields {
action::ResultFields::FetchStatus(status) => {
state.progress.println(format!(
state.println(format!(
"RESULT FetchStatus (id: {}): status={}",
id, status
))?;

39
src/multibar.rs Normal file
View File

@@ -0,0 +1,39 @@
use std::fmt;
#[derive(Debug)]
pub struct MultiBar<'s, const N: usize>(pub [(&'s str, u64); N]);
impl<const N: usize> MultiBar<'_, N> {
/// Total length of the bar
pub(crate) fn length(&self) -> u64 {
self.0.iter().map(|(_, len)| *len).sum()
}
/// Transforms the bar to be of target size
pub(crate) fn scale(&self, size: u64) -> Self {
let length = std::cmp::max(self.length(), 1);
let mut prev_prop = 0;
let mut curr_prop = 0;
let inner = self.0.map(|(c, len)| {
curr_prop += len;
let nb_chars = size * curr_prop / length - size * prev_prop / length;
prev_prop = curr_prop;
(c, nb_chars)
});
Self(inner)
}
}
impl<const N: usize> fmt::Display for MultiBar<'_, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for &(c, len) in &self.0 {
for _ in 0..len {
f.write_str(c)?;
}
}
Ok(())
}
}

View File

@@ -1,16 +1,43 @@
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use std::{borrow::Cow, collections::HashMap};
use console::style;
use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
use std::{borrow::Cow, collections::HashMap, io};
use crate::{action::StartFields, nix_path};
pub struct State<'a> {
pub progress: MultiProgress,
pub multi_progress: MultiProgress,
pub manager: StateManager<'a>,
pub separator: Option<ProgressBar>,
}
impl<'a> State<'a> {
pub fn add_pb(&mut self, pb: ProgressBar) -> ProgressBar {
self.progress.add(pb)
let separator = self.separator.get_or_insert_with(|| {
let separator = ProgressBar::new_spinner()
.with_style(
ProgressStyle::default_spinner()
.template(&style("··{wide_msg:<}").dim().to_string())
.expect("invalid template"),
)
.with_message("·".repeat(512))
.with_finish(ProgressFinish::AndClear);
let separator = self.multi_progress.insert(0, separator);
separator.set_length(0);
separator
});
self.multi_progress.insert_after(separator, pb)
// self.progress.add(pb)
}
pub fn add_pb_before(&mut self, before: &ProgressBar, pb: ProgressBar) -> ProgressBar {
self.multi_progress.insert_before(before, pb)
}
pub fn add_pb_after(&mut self, after: &ProgressBar, pb: ProgressBar) -> ProgressBar {
self.multi_progress.insert_after(after, pb)
}
pub fn println<I: AsRef<str>>(&self, msg: I) -> io::Result<()> {
self.multi_progress.println(msg)
}
}
@@ -27,10 +54,12 @@ pub enum BuildEnumState<'a> {
},
SubstituteCopy {
path: Cow<'a, str>,
bar: ProgressBar,
},
SubstituteFetch {
path: Cow<'a, str>,
bar: ProgressBar,
extract_bar: ProgressBar,
download_bar: ProgressBar,
},
Query {
path: Cow<'a, str>,
@@ -74,12 +103,34 @@ impl<'a> BuildState<'a> {
BuildEnumState::Substitute { source, target }
}
(BuildEnumState::Substitute { .. }, StartFields::CopyPath { path, .. }) => {
BuildEnumState::SubstituteCopy { path }
let name = nix_path::extract_package_name(&path).unwrap_or("unknown".to_string());
let bar = state.add_pb(ProgressBar::new(100));
bar.set_message(format!("Copying substitute for {}", name));
bar.set_style(
ProgressStyle::default_bar()
.template("{prefix}{msg} [{bar:40.cyan/blue}] {pos:>3}%")
.unwrap()
.progress_chars("=> "),
);
bar.tick();
BuildEnumState::SubstituteCopy { path, bar }
}
(BuildEnumState::SubstituteCopy { path }, StartFields::FileTransfer { .. }) => {
(BuildEnumState::SubstituteCopy { path, bar }, StartFields::FileTransfer { .. }) => {
let download_bar = state.add_pb_after(bar, ProgressBar::new(100));
let name = nix_path::extract_package_name(path).unwrap_or("unknown".to_string());
download_bar.set_message(format!("Fetching substitute for {}", name));
download_bar.set_style(
ProgressStyle::default_bar()
.template("{prefix}{msg} [{bar:40.cyan/blue}] {pos:>3}%")
.unwrap()
.progress_chars("=> "),
);
download_bar.set_prefix("=== ");
download_bar.tick();
BuildEnumState::SubstituteFetch {
path: path.clone(),
bar: state.add_pb(ProgressBar::new(100)),
extract_bar: bar.clone(),
download_bar,
}
}
(_, StartFields::Unknown) => BuildEnumState::Unknown,
@@ -94,29 +145,23 @@ impl<'a> BuildState<'a> {
pub fn tick(&mut self, state: &mut State<'a>) {
match &self.state {
BuildEnumState::QueryFetch { target } => {
let pb = state.progress.add(ProgressBar::new_spinner());
let pb = state.add_pb(ProgressBar::new_spinner());
pb.set_message(format!("Fetching info for {}", target));
pb.enable_steady_tick(std::time::Duration::from_millis(100));
self.progress_bar = Some(pb);
}
BuildEnumState::SubstituteFetch { path, bar } => {
let name = nix_path::extract_package_name(path).unwrap_or("unknown".to_string());
bar.set_message(format!("Fetching substitute for {}", name));
bar.set_style(
ProgressStyle::default_bar()
.template("{msg} [{bar:40.cyan/blue}] {pos:>3}%")
.unwrap()
.progress_chars("=> "),
);
// bar.enable_steady_tick(std::time::Duration::from_millis(100));
// self.progress_bar = Some(bar.clone());
}
_ => {}
}
}
pub fn progress(&mut self, done: u64, expected: u64) {
match &self.state {
BuildEnumState::SubstituteFetch { bar, .. } => {
BuildEnumState::SubstituteFetch { download_bar, .. } => {
let percentage = (done * 100 / expected) as u64;
if percentage > download_bar.position() {
download_bar.set_position(percentage);
};
}
BuildEnumState::SubstituteCopy { path, bar } => {
let percentage = (done * 100 / expected) as u64;
if percentage > bar.position() {
bar.set_position(percentage);