Skip to main content

pistonite_cu/cli/progress/
mod.rs

1/// # Progress Bars
2/// Progress bars are a feature in the print system. It is aware of the printing/prompting going on
3/// in the console and will keep the bars at the bottom of the console without interferring
4/// with the other outputs.
5///
6/// ## Components
7/// A bar has the following display components
8/// - Step display: Displays the current and total steps. For example, `[42/100]`. Will not display
9///   for bars that are unbounded. Bars that are not unbounded but the total is not set
10///   will show total as `?`. The step display can also be configured to a style more suitable
11///   for displaying bytes (for example downloading or processing file), like `10.0K / 97.3M`
12/// - Prefix: A string configured once when launching the progress bar
13/// - Percentage: Percentage display for the current and total steps, For example `42.00%`.
14///   This can be turned off if not needed
15/// - ETA: Estimated remaining time. This can be turned off if not needed
16/// - Message: A message that can be set while the progress bar is showing. For example,
17///   this can be the name of the current file being processed, etc.
18///
19/// With everything displayed, it will look something like this:
20/// ```text
21/// X][42/100] prefix: 42.00% ETA 32.35s processing the 42th item
22/// ```
23/// (`X`) is where the animated spinner is
24///
25/// ## Progress Tree
26/// You can display progress bars with a hierarchy if desired. The progress bars
27/// will be organized as an directed acyclic graph (i.e. a tree). Special characters
28/// will be used to draw the tree in the terminal.
29///
30/// Each progress bar holds a strong ref to its parent, and weak refs to all of its children.
31/// The printer keeps weak refs to all root progress bars (i.e. one without a parent).
32///
33/// ## State and Output
34/// Each progress bar can have 3 states: `progress`, `done`, and `interrupted`.
35///
36/// When in `progress`, the bar will be animated if the output is a terminal. Otherwise,
37/// updates will be ignored.
38///
39/// The bar will be `done` when all handles are dropped if 1 of the following is true:
40/// - The bar has finite total, and current step equals total step
41/// - The bar is unbounded, and `.done()` is called on any handle
42///
43/// If neither is true when all handles are dropped, the bar becomes `interrupted`.
44/// This makes the bar easier to use with control flows. When the bar is in this state,
45/// it will print an interrupted message to the regular print stream, like
46/// ```text
47/// X][42/100] prefix: interrupted
48/// ```
49/// This message is customizable when building the progress bar. All of its children
50/// that are interrupted will also be printed. All children that are `done` will only be
51/// printed if `keep` is true for that children (see below). The interrupted message is printed
52/// regardless if the output is terminal or not.
53///
54/// When the progress bar is done, it may print a "done message" depending on
55/// if it has a parent and the `keep` option:
56/// | Has parent (i.e. is child) | Keep | Behavior |
57/// |-|-|-|
58/// | Yes | Yes | Done message will be displayed under the parent, but the bar will disappear completely when the parent is done |
59/// | Yes | No  | The bar will disappear after it's done |
60/// | No  | Yes | The bar will print a done message to the regular print stream when done, no children will be printed |
61/// | No  | No  | The bar will disappear after done, no children will be printed |
62///
63/// The done message is also customizable when building the bar. Note (from the table) that it will
64/// be effective in some way if the `keep` option is true. Setting a done message
65/// does not automatically set `keep` to true.
66///
67/// The default done message is something like below, will be displayed in green.
68/// ```text
69/// X][100/100] prefix: done
70/// ```
71///
72/// ## Updating the bar
73/// The [`progress`](macro@crate::progress) macro is used to update the progress bar.
74/// For example:
75///
76/// ```rust
77/// # use pistonite_cu as cu;
78/// let bar = cu::progress("doing something").total(10).spawn();
79/// for i in 0..10 {
80///     cu::progress!(bar = i, "doing {i}th step");
81/// }
82/// drop(bar);
83/// ```
84///
85/// ## Building the bar
86/// This function `cu::progress` will make a [`ProgressBarBuilder`]
87/// with these default configs:
88/// - Total steps: unbounded
89/// - Keep after done: `true`
90/// - Show ETA: `true` (only effective if steps is finite)
91/// - Finish message: Default
92/// - Interrupted message: Default
93///
94/// See [`ProgressBarBuilder`] for builder methods
95///
96/// ## Print Levels
97/// The bar final messages are suppressed at `-q` and the bar animations are suppressed at `-qq`
98///
99/// ## Other considerations
100/// If the progress bar print section exceeds the terminal height,
101/// it will probably not render properly. Keep in mind when you
102/// are displaying a large number of progress bars.
103///
104/// You can use `.max_display_children()` to set the maximum number of children
105/// to display at a time. However, there is no limit on the number of root progress bars.
106#[inline(always)]
107pub fn progress(message: impl Into<String>) -> ProgressBarBuilder {
108    ProgressBarBuilder::new(message.into())
109}
110
111mod eta;
112
113pub use eta::Estimater;
114mod state;
115pub use state::ProgressBar;
116use state::{State, StateImmut};
117mod builder;
118pub use builder::ProgressBarBuilder;
119mod util;
120pub use util::{BarFormatter, BarResult};
121use util::{ChildState, ChildStateStrong};
122mod macros;
123
124/// Convenience type for `Arc<cu::ProgressBar>`
125pub type ProgressHandle = std::sync::Arc<ProgressBar>;
126
127// spawn_iter stuff, keep for reference, not sure if needed yet
128// .enumerate seems more readable
129/*
130/// In the example above, you can also attach it to an iterator directly.
131/// The builder will call `size_hint()` once and set the total on the bar,
132/// and will automatically mark it as done if `next()` returns `None`.
133///
134/// If the default iteration behavior of `spawn_iter` is not desirable, use `spawn`
135/// and iterate manually.
136/// ```rust
137/// # use pistonite_cu as cu;
138/// for i in cu::progress("doing something").spawn_iter(0..10) {
139///     cu::print!("doing {i}th step");
140/// }
141/// ```
142///
143/// Note that in the code above, we didn't have a handle to the bar directly
144/// to update the message, we can fix that by getting the bar from the iter
145///
146/// ```rust
147/// # use pistonite_cu as cu;
148/// let mut iter = cu::progress("doing something").spawn_iter(0..10);
149/// let bar = iter.bar();
150/// for i in iter {
151///     // bar = i is handled by the iterator automatically
152///     cu::progress!(bar, "doing {i}th step");
153/// }
154/// ```
155*/