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
14pub enum ProgressStyle {
16 Bar,
18 Spinner,
20 Download,
22 Finished,
24}
25
26impl ProgressStyle {
27 fn to_indicatif(&self) -> IndicatifStyle {
28 match self {
29 ProgressStyle::Bar => style_or_default(
30 "{prefix:.bold} {wide_bar:.cyan/dim} {pos}/{len} {percent}% {elapsed}",
31 IndicatifStyle::default_bar,
32 )
33 .progress_chars("━╸─"),
34
35 ProgressStyle::Spinner => style_or_default(
36 "{spinner:.green} {prefix} {wide_msg}",
37 IndicatifStyle::default_spinner,
38 ),
39
40 ProgressStyle::Download => style_or_default(
41 "{prefix:.bold} {wide_bar:.green/dim} {bytes}/{total_bytes} {bytes_per_sec} {eta}",
42 IndicatifStyle::default_bar,
43 )
44 .progress_chars("━╸─"),
45
46 ProgressStyle::Finished => {
47 style_or_default("{prefix} {wide_msg}", IndicatifStyle::default_spinner)
48 }
49 }
50 }
51}
52
53fn style_or_default(template: &str, fallback: impl FnOnce() -> IndicatifStyle) -> IndicatifStyle {
54 IndicatifStyle::with_template(template).unwrap_or_else(|_| fallback())
55}
56
57pub struct ProgressBar {
59 inner: IndicatifBar,
60}
61
62impl ProgressBar {
63 pub fn new(total: u64, style: ProgressStyle) -> Self {
65 let bar = IndicatifBar::new(total);
66 bar.set_style(style.to_indicatif());
67 bar.enable_steady_tick(Duration::from_millis(100));
68 Self { inner: bar }
69 }
70
71 pub fn spinner() -> Self {
73 let bar = IndicatifBar::new_spinner();
74 bar.set_style(ProgressStyle::Spinner.to_indicatif());
75 bar.enable_steady_tick(Duration::from_millis(80));
76 Self { inner: bar }
77 }
78
79 pub fn set_prefix(&self, prefix: impl Into<String>) {
81 self.inner.set_prefix(prefix.into());
82 }
83
84 pub fn set_style(&self, style: ProgressStyle) {
86 self.inner.set_style(style.to_indicatif());
87 }
88
89 pub fn set_message(&self, msg: impl Into<String>) {
91 self.inner.set_message(msg.into());
92 }
93
94 pub fn enable_steady_tick(&self, interval: Duration) {
96 self.inner.enable_steady_tick(interval);
97 }
98
99 pub fn tick(&self) {
101 self.inner.tick();
102 }
103
104 pub fn set_position(&self, pos: u64) {
106 self.inner.set_position(pos);
107 }
108
109 pub fn inc(&self, delta: u64) {
111 self.inner.inc(delta);
112 }
113
114 pub fn set_length(&self, len: u64) {
116 self.inner.set_length(len);
117 }
118
119 pub fn finish(&self) {
121 self.inner.finish();
122 }
123
124 pub fn finish_with_message(&self, msg: impl Into<std::borrow::Cow<'static, str>>) {
126 self.inner.finish_with_message(msg);
127 }
128
129 pub fn reset(&self) {
131 self.inner.reset();
132 }
133
134 pub fn finish_and_clear(&self) {
136 self.inner.finish_and_clear();
137 }
138
139 pub fn inner(&self) -> &IndicatifBar {
141 &self.inner
142 }
143}
144
145pub struct MultiProgress {
147 inner: IndicatifMultiProgress,
148}
149
150impl MultiProgress {
151 #[must_use]
152 pub fn new() -> Self {
153 Self {
154 inner: IndicatifMultiProgress::new(),
155 }
156 }
157
158 #[must_use]
160 pub fn from_raw(mp: IndicatifMultiProgress) -> Self {
161 Self { inner: mp }
162 }
163
164 pub fn raw(&self) -> &IndicatifMultiProgress {
166 &self.inner
167 }
168
169 pub fn add_bar(&self, prefix: impl Into<String>, total: u64) -> ProgressBar {
171 let bar = IndicatifBar::new(total);
172 bar.set_style(ProgressStyle::Bar.to_indicatif());
173 bar.set_prefix(prefix.into());
174 let bar = self.inner.add(bar);
175 ProgressBar { inner: bar }
176 }
177
178 pub fn insert_bar_after(
180 &self,
181 after: &ProgressBar,
182 prefix: impl Into<String>,
183 total: u64,
184 ) -> ProgressBar {
185 let bar = IndicatifBar::new(total);
186 bar.set_style(ProgressStyle::Bar.to_indicatif());
187 bar.set_prefix(prefix.into());
188 let bar = self.inner.insert_after(after.inner(), bar);
189 ProgressBar { inner: bar }
190 }
191
192 pub fn add_spinner(&self, prefix: impl Into<String>) -> ProgressBar {
194 let bar = IndicatifBar::new_spinner();
195 bar.set_style(ProgressStyle::Spinner.to_indicatif());
196 bar.set_prefix(prefix.into());
197 bar.enable_steady_tick(Duration::from_millis(120));
198 let bar = self.inner.add(bar);
199 ProgressBar { inner: bar }
200 }
201
202 pub fn add_static_line(
204 &self,
205 prefix: impl Into<String>,
206 msg: impl Into<std::borrow::Cow<'static, str>>,
207 ) -> ProgressBar {
208 let bar = IndicatifBar::new(0);
209 bar.set_style(ProgressStyle::Finished.to_indicatif());
210 bar.set_prefix(prefix.into());
211 bar.finish_with_message(msg);
212 let bar = self.inner.add(bar);
213 ProgressBar { inner: bar }
214 }
215
216 pub fn println(&self, msg: impl AsRef<str>) -> std::io::Result<()> {
218 self.inner.println(msg)
219 }
220
221 pub fn remove(&self, bar: &ProgressBar) {
223 self.inner.remove(bar.inner());
224 }
225
226 pub fn clear(&self) -> std::io::Result<()> {
228 self.inner.clear()
229 }
230}
231
232impl Default for MultiProgress {
233 fn default() -> Self {
234 Self::new()
235 }
236}