1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
use std::{sync::mpsc::channel, time::Duration};
use cliclack::{clear_screen, intro, log::remark, outro, outro_cancel, progress_bar};
use console::{style, Term};
use rand::random_range;
enum Message {
Interrupt,
}
fn main() -> std::io::Result<()> {
let (tx, rx) = channel();
// Set a no-op Ctrl-C handler which allows to catch
// `ErrorKind::Interrupted` error on `term.read_key()`.
ctrlc::set_handler(move || {
tx.send(Message::Interrupt).ok();
})
.expect("setting Ctrl-C handler");
// Clear the screen and print the header.
clear_screen()?;
intro(style(" progress bar ").on_cyan().black())?;
remark("Press Ctrl-C")?;
// Create a new progress bar and set the text to "Installation".
let progress = progress_bar(100);
progress.start("Copying files...");
// Simulate doing some stuff....
for _ in 0..100 {
// Use a random timeout to simulate some work.
let timeout = Duration::from_millis(random_range(10..75));
// Check if we received a message from the channel.
if let Ok(Message::Interrupt) = rx.recv_timeout(timeout) {
// Clear the garbage appearing because of Ctrl-C.
let term = Term::stderr();
term.clear_line()?;
term.move_cursor_up(1)?;
progress.cancel("Copying files");
outro_cancel("Interrupted")?;
return Ok(());
}
// Otherwise, we increase the progress bar by the delta 1.
progress.inc(1);
}
// Once we're done, we stop the progress bar and print the outro message.
// This removes the progress bar and prints the message to the terminal.
progress.stop("Copying files");
outro("Done!")?;
Ok(())
}