procedure/
lib.rs

1extern crate yansi;
2
3use std::fmt::Display;
4use std::io::{stdout, Write};
5use std::ops::FnOnce;
6use yansi::Paint;
7
8/// Determines the default padding
9const DEFAULT_PADDING: usize = 12;
10
11/// Representation of the progress structure.
12pub struct Progress<'a> {
13    /// Used to store the prefix action.
14    action: &'a str,
15    /// Used to store the description of the action.
16    description: &'a str,
17    /// Used to store the padding of the action.
18    padding: usize,
19    /// Stores the current percentage value (from 0-100).
20    value: u8,
21}
22
23/// Implementation of the progress structure.
24impl<'a> Progress<'a> {
25    /// Creates a new progress struct.
26    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    /// Initializes the progress by setting a percentage of 0%.
36    pub fn initialize(&mut self) {
37        self.set_from(0, 100, 0);
38    }
39
40    /// Sets the percentage value from 1 to 100 of the progress.
41    pub fn set(&mut self, value: usize) {
42        self.set_from(0, 100, value)
43    }
44
45    /// Increment the percentage value with the given offset.
46    pub fn increment(&mut self, offset: usize) {
47        self.set(self.value as usize + offset);
48    }
49
50    /// Sets the percentage value automatically given a min, a max and the current value.
51    /// Please note that min < value < max.
52    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    /// Finishes the progress (and sets the percentage to 100%) with the given value.
66    /// The value will replace the action description in the stdout.
67    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    /// Finishes the progress (does not modify the percentage value) with the given error value.
83    /// The value will replace the action description in the stdout.
84    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
99/// Proceeds the execution of `function` with a nice formatted `action`.
100/// The default padding is {DEFAULT_PADDING}.
101pub 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
110/// Proceeds the execution of `function` with a nice formatted `action` given a left `padding`.
111pub 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
136/// Prints a success action with a description.
137pub fn success(action: &str, description: &str) {
138    success_padded(action, description, DEFAULT_PADDING);
139}
140
141/// Prints a success action with a description. Includes an additional padding on the left.
142pub fn success_padded(action: &str, description: &str, padding: usize) {
143    println!("\r{:>2$} {:}", Paint::green(action), description, padding);
144}
145
146/// Prints an error action with a description.
147pub fn error(action: &str, description: &str) {
148    error_padded(action, description, DEFAULT_PADDING);
149}
150
151/// Prints an error action with a description. Includes an additional padding on the left.
152pub fn error_padded(action: &str, description: &str, padding: usize) {
153    println!("\r{:>2$} {:}", Paint::red(action), description, padding);
154}
155
156/// Prints a warning action with a description.
157pub fn warning(action: &str, description: &str) {
158    warning_padded(action, description, DEFAULT_PADDING);
159}
160
161/// Prints a warning action with a description. Includes an additional padding on the left.
162pub fn warning_padded(action: &str, description: &str, padding: usize) {
163    println!("\r{:>2$} {:}", Paint::yellow(action), description, padding);
164}
165
166/// Prints an info action with a description.
167pub fn info(action: &str, description: &str) {
168    info_padded(action, description, DEFAULT_PADDING);
169}
170
171/// Prints an info action with a description. Includes an additional padding on the left.
172pub fn info_padded(action: &str, description: &str, padding: usize) {
173    println!("\r{:>2$} {:}", Paint::cyan(action), description, padding);
174}