From 397f4de1ebd2ee92defb440df44afadeb3e8e587 Mon Sep 17 00:00:00 2001 From: Pistonight Date: Sat, 25 Apr 2026 11:06:42 -0700 Subject: [PATCH] feat(progress): set_done_message and set_interrupted_message --- packages/copper/Cargo.toml | 4 +- packages/copper/src/cli/mod.rs | 2 +- packages/copper/src/cli/progress/builder.rs | 9 ++- packages/copper/src/cli/progress/mod.rs | 4 ++ packages/copper/src/cli/progress/state.rs | 78 ++++++++++++++++++--- 5 files changed, 83 insertions(+), 14 deletions(-) diff --git a/packages/copper/Cargo.toml b/packages/copper/Cargo.toml index bd6148c..2ddaa58 100644 --- a/packages/copper/Cargo.toml +++ b/packages/copper/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pistonite-cu" -version = "0.8.1" +version = "0.8.2" edition = "2024" description = "Battery-included common utils to speed up development of rust tools" repository = "https://github.com/Pistonite/cu" @@ -50,7 +50,7 @@ toml = { version = "1.1.2", optional = true } derive_more = { version = "2.1.1", features = ["full"], optional = true } [target.'cfg(unix)'.dependencies] -libc = "0.2.185" +libc = "0.2.186" [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.61.2", features = ["Win32_Foundation", "Win32_System_Console", "Win32_Storage_FileSystem", "Win32_Security", "Win32_System_SystemServices"] } diff --git a/packages/copper/src/cli/mod.rs b/packages/copper/src/cli/mod.rs index 9608417..dd1c1bd 100644 --- a/packages/copper/src/cli/mod.rs +++ b/packages/copper/src/cli/mod.rs @@ -151,7 +151,7 @@ pub use thread_name::{reset_thread_name, set_thread_name}; mod printer; mod progress; -pub use progress::{ProgressBar, ProgressBarBuilder, progress}; +pub use progress::{ProgressBar, ProgressBarBuilder, ProgressHandle, progress}; #[cfg(feature = "prompt")] mod prompt; diff --git a/packages/copper/src/cli/progress/builder.rs b/packages/copper/src/cli/progress/builder.rs index 8fd1610..12dda88 100644 --- a/packages/copper/src/cli/progress/builder.rs +++ b/packages/copper/src/cli/progress/builder.rs @@ -195,15 +195,18 @@ impl ProgressBarBuilder { id: crate::next_atomic_usize(), parent: self.parent.as_ref().map(Arc::clone), prefix: self.message, - done_message, - interrupted_message: self.interrupted_message, show_percentage: self.show_percentage, unbounded: self.total.is_none(), display_bytes: self.total_is_in_bytes, max_display_children: self.max_display_children, }; let eta = self.show_eta.then(Estimater::new); - let state = State::new(self.total.unwrap_or(0), eta); + let state = State::new( + self.total.unwrap_or(0), + eta, + done_message, + self.interrupted_message, + ); ProgressBar::spawn(state_immut, state, self.parent) } diff --git a/packages/copper/src/cli/progress/mod.rs b/packages/copper/src/cli/progress/mod.rs index 4e85c3d..0894e43 100644 --- a/packages/copper/src/cli/progress/mod.rs +++ b/packages/copper/src/cli/progress/mod.rs @@ -109,6 +109,7 @@ pub fn progress(message: impl Into) -> ProgressBarBuilder { } mod eta; + pub use eta::Estimater; mod state; pub use state::ProgressBar; @@ -120,6 +121,9 @@ pub use util::{BarFormatter, BarResult}; use util::{ChildState, ChildStateStrong}; mod macros; +/// Convenience type for `Arc` +pub type ProgressHandle = std::sync::Arc; + // spawn_iter stuff, keep for reference, not sure if needed yet // .enumerate seems more readable /* diff --git a/packages/copper/src/cli/progress/state.rs b/packages/copper/src/cli/progress/state.rs index 8ce8f90..0c1404c 100644 --- a/packages/copper/src/cli/progress/state.rs +++ b/packages/copper/src/cli/progress/state.rs @@ -88,6 +88,37 @@ impl ProgressBar { ProgressBarBuilder::new(message.into()).parent(Some(Arc::clone(self))) } + /// Set the message to be printed and mark the bar as done + pub fn done_with_message(self: Arc, message: &str) { + self.set_done_message(message); + self.done(); + } + + /// Set the message to be printed and mark the bar as done + pub fn done_by_ref_with_message(&self, message: &str) { + self.set_done_message(message); + self.done_by_ref(); + } + + /// Change the message to be printed when the bar is done. + /// Useful if information is not available yet when the bar is spawned. + /// + /// This does NOT mark the bar as done, use [`done_with_message`](Self::done_with_message) + /// for that. + pub fn set_done_message(&self, message: &str) { + if let Ok(mut bar) = self.state_mut.lock() { + bar.set_done_message(message); + } + } + + /// Change the message to be printed when the bar is interrupted. + /// Useful if information is not available yet when the bar is spawned. + pub fn set_interrupted_message(&self, message: &str) { + if let Ok(mut bar) = self.state_mut.lock() { + bar.set_interrupted_message(message); + } + } + /// Mark the progress bar as done and drop the handle. /// /// This needs to be called if the bar is unbounded. Otherwise, @@ -172,11 +203,6 @@ pub struct StateImmut { pub parent: Option>, /// The prefix message (corresponds to message in the builder) pub prefix: String, - /// None means don't keep the progress bar printed - /// (the default done message is formatted at spawn time) - pub done_message: Option, - /// None means use the default - pub interrupted_message: Option, /// If percentage field is shown pub show_percentage: bool, /// If the steps are unbounded @@ -194,15 +220,27 @@ pub struct State { unreal_total: u64, unreal_current: u64, message: String, + /// None means don't keep the progress bar printed + /// (the default done message is formatted at spawn time) + done_message: Option, + /// None means use the default + interrupted_message: Option, eta: Option, children: Vec, } impl State { - pub fn new(total: u64, eta: Option) -> Self { + pub fn new( + total: u64, + eta: Option, + done_message: Option, + interrupted_message: Option, + ) -> Self { Self { unreal_total: total, unreal_current: 0, message: String::new(), + done_message, + interrupted_message, eta, children: vec![], } @@ -270,7 +308,7 @@ impl State { let is_interrupted = (self.unreal_current == 0 && self.unreal_total == 0) || (self.unreal_current < self.unreal_total); if !is_interrupted { - match &state.done_message { + match &self.done_message { None => BarResult::DontKeep, Some(message) => { let message = @@ -279,7 +317,7 @@ impl State { } } } else { - match &state.interrupted_message { + match &self.interrupted_message { None => { let message = if state.prefix.is_empty() { self.format_finish_message( @@ -310,6 +348,30 @@ impl State { self.message.push_str(message); } + pub fn set_done_message(&mut self, message: &str) { + match &mut self.done_message { + None => { + self.done_message = Some(message.to_string()); + } + Some(msg) => { + msg.clear(); + msg.push_str(message); + } + } + } + + pub fn set_interrupted_message(&mut self, message: &str) { + match &mut self.interrupted_message { + None => { + self.interrupted_message = Some(message.to_string()); + } + Some(msg) => { + msg.clear(); + msg.push_str(message); + } + } + } + /// Format the bar into the out buffer at the depth /// /// If depth is 0, the animation character is already formatted.