1use indicatif::{
6 MultiProgress as IndicatifMultiProgress, ProgressBar as IndicatifBar,
7 ProgressStyle as IndicatifStyle,
8};
9use std::time::Duration;
10
11pub use indicatif::MultiProgress as RawMultiProgress;
13
14#[derive(Clone, Copy)]
16pub enum ProgressStyle {
17 Bar,
19 Spinner,
21 Download,
23 Finished,
25}
26
27impl ProgressStyle {
28 fn to_indicatif(self) -> IndicatifStyle {
29 match self {
30 Self::Bar => style_or_default(
31 "{prefix:.bold} {wide_bar:.cyan/dim} {pos}/{len} {percent}% {elapsed}",
32 IndicatifStyle::default_bar,
33 )
34 .progress_chars("━╸─"),
35
36 Self::Spinner => style_or_default(
37 "{spinner:.green} {prefix} {wide_msg}",
38 IndicatifStyle::default_spinner,
39 ),
40
41 Self::Download => style_or_default(
42 "{prefix:.bold} {wide_bar:.green/dim} {bytes}/{total_bytes} {bytes_per_sec} {eta}",
43 IndicatifStyle::default_bar,
44 )
45 .progress_chars("━╸─"),
46
47 Self::Finished => {
48 style_or_default("{prefix} {wide_msg}", IndicatifStyle::default_spinner)
49 }
50 }
51 }
52}
53
54fn style_or_default(template: &str, fallback: impl FnOnce() -> IndicatifStyle) -> IndicatifStyle {
55 IndicatifStyle::with_template(template).unwrap_or_else(|_| fallback())
56}
57
58pub struct ProgressBar {
60 inner: IndicatifBar,
61}
62
63impl ProgressBar {
64 pub fn new(total: u64, style: ProgressStyle) -> Self {
66 let bar = IndicatifBar::new(total);
67 bar.set_style(style.to_indicatif());
68 bar.enable_steady_tick(Duration::from_millis(100));
69 Self { inner: bar }
70 }
71
72 pub fn spinner() -> Self {
74 let bar = IndicatifBar::new_spinner();
75 bar.set_style(ProgressStyle::Spinner.to_indicatif());
76 bar.enable_steady_tick(Duration::from_millis(80));
77 Self { inner: bar }
78 }
79
80 pub fn set_prefix(&self, prefix: impl Into<String>) {
82 self.inner.set_prefix(prefix.into());
83 }
84
85 pub fn set_style(&self, style: ProgressStyle) {
87 self.inner.set_style(style.to_indicatif());
88 }
89
90 pub fn set_message(&self, msg: impl Into<String>) {
92 self.inner.set_message(msg.into());
93 }
94
95 pub fn enable_steady_tick(&self, interval: Duration) {
97 self.inner.enable_steady_tick(interval);
98 }
99
100 pub fn tick(&self) {
102 self.inner.tick();
103 }
104
105 pub fn set_position(&self, pos: u64) {
107 self.inner.set_position(pos);
108 }
109
110 pub fn inc(&self, delta: u64) {
112 self.inner.inc(delta);
113 }
114
115 pub fn set_length(&self, len: u64) {
117 self.inner.set_length(len);
118 }
119
120 pub fn finish(&self) {
122 self.inner.finish();
123 }
124
125 pub fn finish_with_message(&self, msg: impl Into<std::borrow::Cow<'static, str>>) {
127 self.inner.finish_with_message(msg);
128 }
129
130 pub fn reset(&self) {
132 self.inner.reset();
133 }
134
135 pub fn finish_and_clear(&self) {
137 self.inner.finish_and_clear();
138 }
139
140 pub const fn inner(&self) -> &IndicatifBar {
142 &self.inner
143 }
144}
145
146pub struct MultiProgress {
148 inner: IndicatifMultiProgress,
149}
150
151impl MultiProgress {
152 #[must_use]
154 pub fn new() -> Self {
155 Self {
156 inner: IndicatifMultiProgress::new(),
157 }
158 }
159
160 #[must_use]
162 pub const fn from_raw(mp: IndicatifMultiProgress) -> Self {
163 Self { inner: mp }
164 }
165
166 pub const fn raw(&self) -> &IndicatifMultiProgress {
168 &self.inner
169 }
170
171 pub fn add_bar(&self, prefix: impl Into<String>, total: u64) -> ProgressBar {
173 let bar = IndicatifBar::new(total);
174 bar.set_style(ProgressStyle::Bar.to_indicatif());
175 bar.set_prefix(prefix.into());
176 let bar = self.inner.add(bar);
177 ProgressBar { inner: bar }
178 }
179
180 pub fn insert_bar_after(
182 &self,
183 after: &ProgressBar,
184 prefix: impl Into<String>,
185 total: u64,
186 ) -> ProgressBar {
187 let bar = IndicatifBar::new(total);
188 bar.set_style(ProgressStyle::Bar.to_indicatif());
189 bar.set_prefix(prefix.into());
190 let bar = self.inner.insert_after(after.inner(), bar);
191 ProgressBar { inner: bar }
192 }
193
194 pub fn add_spinner(&self, prefix: impl Into<String>) -> ProgressBar {
196 let bar = IndicatifBar::new_spinner();
197 bar.set_style(ProgressStyle::Spinner.to_indicatif());
198 bar.set_prefix(prefix.into());
199 bar.enable_steady_tick(Duration::from_millis(120));
200 let bar = self.inner.add(bar);
201 ProgressBar { inner: bar }
202 }
203
204 pub fn add_static_line(
206 &self,
207 prefix: impl Into<String>,
208 msg: impl Into<std::borrow::Cow<'static, str>>,
209 ) -> ProgressBar {
210 let bar = IndicatifBar::new(0);
211 bar.set_style(ProgressStyle::Finished.to_indicatif());
212 bar.set_prefix(prefix.into());
213 bar.finish_with_message(msg);
214 let bar = self.inner.add(bar);
215 ProgressBar { inner: bar }
216 }
217
218 pub fn println(&self, msg: impl AsRef<str>) -> std::io::Result<()> {
220 self.inner.println(msg)
221 }
222
223 pub fn remove(&self, bar: &ProgressBar) {
225 self.inner.remove(bar.inner());
226 }
227
228 pub fn clear(&self) -> std::io::Result<()> {
230 self.inner.clear()
231 }
232}
233
234impl Default for MultiProgress {
235 fn default() -> Self {
236 Self::new()
237 }
238}