1extern crate yansi;
2
3use std::fmt::Display;
4use std::io::{stdout, Write};
5use std::ops::FnOnce;
6use yansi::Paint;
7
8const DEFAULT_PADDING: usize = 12;
10
11pub struct Progress<'a> {
13 action: &'a str,
15 description: &'a str,
17 padding: usize,
19 value: u8,
21}
22
23impl<'a> Progress<'a> {
25 pub fn new(action: &'a str, description: &'a str, padding: usize) -> Progress<'a> {
27 Progress {
28 action,
29 description,
30 padding,
31 value: 0,
32 }
33 }
34
35 pub fn initialize(&mut self) {
37 self.set_from(0, 100, 0);
38 }
39
40 pub fn set(&mut self, value: usize) {
42 self.set_from(0, 100, value)
43 }
44
45 pub fn increment(&mut self, offset: usize) {
47 self.set(self.value as usize + offset);
48 }
49
50 pub fn set_from(&mut self, min: usize, max: usize, value: usize) {
53 self.value = (((value - min) * 100) / (max - min)) as u8;
54 print!(
55 "\r{:>3$} [{:>3}%] {:<4$}",
56 Paint::yellow(self.action),
57 self.value,
58 self.description,
59 self.padding,
60 self.description.len()
61 );
62 stdout().flush().unwrap_or_default();
63 }
64
65 fn ok<R>(&mut self, result: &R)
68 where
69 R: Display,
70 {
71 self.value = 100;
72 println!(
73 "\r{:>3$} [{:>3}%] {:<4$}",
74 Paint::green(self.action),
75 self.value,
76 result,
77 self.padding,
78 self.description.len()
79 );
80 }
81
82 fn err<E>(&mut self, error: &E)
85 where
86 E: Display,
87 {
88 println!(
89 "\r{:>3$} [{:>3}%] {:<4$}",
90 Paint::red(self.action),
91 self.value,
92 error,
93 self.padding,
94 self.description.len()
95 );
96 }
97}
98
99pub fn proceed<F, R, D, E>(action: &str, description: &str, function: F) -> Result<R, E>
102where
103 F: FnOnce(&mut Progress) -> Result<(R, D), E>,
104 D: Display,
105 E: Display,
106{
107 proceed_padded(action, description, function, DEFAULT_PADDING)
108}
109
110pub fn proceed_padded<F, R, D, E>(
112 action: &str,
113 description: &str,
114 function: F,
115 padding: usize,
116) -> Result<R, E>
117where
118 F: FnOnce(&mut Progress) -> Result<(R, D), E>,
119 D: Display,
120 E: Display,
121{
122 let mut progress = Progress::new(action, description, padding);
123 progress.initialize();
124 match function(&mut progress) {
125 Ok(result) => {
126 progress.ok(&result.1);
127 Ok(result.0)
128 }
129 Err(error) => {
130 progress.err(&error);
131 Err(error)
132 }
133 }
134}
135
136pub fn success(action: &str, description: &str) {
138 success_padded(action, description, DEFAULT_PADDING);
139}
140
141pub fn success_padded(action: &str, description: &str, padding: usize) {
143 println!("\r{:>2$} {:}", Paint::green(action), description, padding);
144}
145
146pub fn error(action: &str, description: &str) {
148 error_padded(action, description, DEFAULT_PADDING);
149}
150
151pub fn error_padded(action: &str, description: &str, padding: usize) {
153 println!("\r{:>2$} {:}", Paint::red(action), description, padding);
154}
155
156pub fn warning(action: &str, description: &str) {
158 warning_padded(action, description, DEFAULT_PADDING);
159}
160
161pub fn warning_padded(action: &str, description: &str, padding: usize) {
163 println!("\r{:>2$} {:}", Paint::yellow(action), description, padding);
164}
165
166pub fn info(action: &str, description: &str) {
168 info_padded(action, description, DEFAULT_PADDING);
169}
170
171pub fn info_padded(action: &str, description: &str, padding: usize) {
173 println!("\r{:>2$} {:}", Paint::cyan(action), description, padding);
174}