pub struct Loader { /* private fields */ }Expand description
A living progress reveal.
Create one with Loader::new, advance it, and finish.
Dropping the last handle finishes it for you, so the terminal is always
restored. Not Clone; for cross-thread updates take a Handle.
Implementations§
Source§impl Loader
impl Loader
Sourcepub fn new(total: u64) -> Self
pub fn new(total: u64) -> Self
A determinate loader for total units of work, using the built-in dragon.
Examples found in repository?
21fn main() {
22 match std::env::args().nth(1).as_deref() {
23 Some("iter") => {
24 for _ in (0..100).inkling() {
25 work(20);
26 }
27 }
28 Some("spinner") => {
29 let loader = Loader::spinner();
30 loader.set_message("Doing something mysterious");
31 work(2500);
32 loader.finish();
33 }
34 Some("threads") => {
35 let loader = Loader::new(120);
36 loader.set_message("Four workers, one dragon");
37 thread::scope(|s| {
38 for _ in 0..4 {
39 let handle = loader.handle();
40 s.spawn(move || {
41 for _ in 0..30 {
42 work(30);
43 handle.inc(1);
44 }
45 });
46 }
47 });
48 loader.finish();
49 }
50 Some("rainbow") => {
51 let loader = Loader::builder()
52 .total(100)
53 .style(inkling::render::Style::rainbow())
54 .message("Tasting the rainbow")
55 .start();
56 for _ in 0..100 {
57 work(20);
58 loader.inc(1);
59 }
60 loader.finish();
61 }
62 _ => {
63 let total: u64 = 100;
64 let loader = Loader::new(total);
65 loader.set_message("Summoning the dragon");
66 for _ in 0..total {
67 work(20);
68 loader.inc(1);
69 }
70 loader.finish();
71 }
72 }
73}Sourcepub fn spinner() -> Self
pub fn spinner() -> Self
An indeterminate loader (a spinner) for work whose length you do not know.
Examples found in repository?
21fn main() {
22 match std::env::args().nth(1).as_deref() {
23 Some("iter") => {
24 for _ in (0..100).inkling() {
25 work(20);
26 }
27 }
28 Some("spinner") => {
29 let loader = Loader::spinner();
30 loader.set_message("Doing something mysterious");
31 work(2500);
32 loader.finish();
33 }
34 Some("threads") => {
35 let loader = Loader::new(120);
36 loader.set_message("Four workers, one dragon");
37 thread::scope(|s| {
38 for _ in 0..4 {
39 let handle = loader.handle();
40 s.spawn(move || {
41 for _ in 0..30 {
42 work(30);
43 handle.inc(1);
44 }
45 });
46 }
47 });
48 loader.finish();
49 }
50 Some("rainbow") => {
51 let loader = Loader::builder()
52 .total(100)
53 .style(inkling::render::Style::rainbow())
54 .message("Tasting the rainbow")
55 .start();
56 for _ in 0..100 {
57 work(20);
58 loader.inc(1);
59 }
60 loader.finish();
61 }
62 _ => {
63 let total: u64 = 100;
64 let loader = Loader::new(total);
65 loader.set_message("Summoning the dragon");
66 for _ in 0..total {
67 work(20);
68 loader.inc(1);
69 }
70 loader.finish();
71 }
72 }
73}Sourcepub fn builder() -> Builder
pub fn builder() -> Builder
Configure a loader with custom art, ordering, style, or message.
Examples found in repository?
21fn main() {
22 match std::env::args().nth(1).as_deref() {
23 Some("iter") => {
24 for _ in (0..100).inkling() {
25 work(20);
26 }
27 }
28 Some("spinner") => {
29 let loader = Loader::spinner();
30 loader.set_message("Doing something mysterious");
31 work(2500);
32 loader.finish();
33 }
34 Some("threads") => {
35 let loader = Loader::new(120);
36 loader.set_message("Four workers, one dragon");
37 thread::scope(|s| {
38 for _ in 0..4 {
39 let handle = loader.handle();
40 s.spawn(move || {
41 for _ in 0..30 {
42 work(30);
43 handle.inc(1);
44 }
45 });
46 }
47 });
48 loader.finish();
49 }
50 Some("rainbow") => {
51 let loader = Loader::builder()
52 .total(100)
53 .style(inkling::render::Style::rainbow())
54 .message("Tasting the rainbow")
55 .start();
56 for _ in 0..100 {
57 work(20);
58 loader.inc(1);
59 }
60 loader.finish();
61 }
62 _ => {
63 let total: u64 = 100;
64 let loader = Loader::new(total);
65 loader.set_message("Summoning the dragon");
66 for _ in 0..total {
67 work(20);
68 loader.inc(1);
69 }
70 loader.finish();
71 }
72 }
73}More examples
36fn main() {
37 let args: Vec<String> = std::env::args().skip(1).collect();
38 let rainbow = args.iter().any(|a| a == "rainbow");
39 let geodesic = args.iter().any(|a| a == "geodesic");
40 let art_path = args.iter().find(|a| a.ends_with(".txt")).cloned();
41 let started = Instant::now();
42 let gold = Color::Rgb {
43 r: 232,
44 g: 180,
45 b: 85,
46 };
47
48 // Clear to a fresh screen and print the tool banner.
49 let _ = execute!(
50 io::stdout(),
51 Clear(ClearType::All),
52 MoveTo(0, 0),
53 Print("\r\n "),
54 SetForegroundColor(gold),
55 Print("dragonctl"),
56 ResetColor,
57 Print(" v0.2.0\r\n\r\n")
58 );
59
60 step("\u{2713}", Color::Green, "Initializing demo environment");
61 pause(450);
62 step("\u{2713}", Color::Green, "Updating base image index");
63 pause(500);
64 step("\u{2193}", Color::Cyan, "Downloading base image");
65 let _ = execute!(io::stdout(), Print("\r\n"));
66
67 // The download itself, paced unevenly: a connect stall, a hiccup, a burst, a
68 // mid stall, and a slow tail.
69 let total: u64 = 48 * 1024 * 1024;
70 let mb = 1024.0 * 1024.0;
71 let schedule: &[(f64, u64)] = &[
72 (0.0, 600),
73 (5.0, 300),
74 (8.0, 250),
75 (8.0, 650),
76 (16.0, 220),
77 (27.0, 180),
78 (38.0, 200),
79 (45.0, 450),
80 (56.0, 200),
81 (67.0, 220),
82 (78.0, 260),
83 (87.0, 320),
84 (93.0, 480),
85 (97.0, 520),
86 (100.0, 300),
87 ];
88
89 let style = if rainbow {
90 Style::rainbow()
91 } else {
92 Style::default()
93 };
94 let mut builder = Loader::builder().total(total).style(style);
95 if geodesic {
96 builder = builder.ordering(Geodesic::default());
97 }
98 if let Some(path) = &art_path {
99 let text = std::fs::read_to_string(path).unwrap_or_else(|e| {
100 eprintln!("could not read {path}: {e}");
101 std::process::exit(1);
102 });
103 builder = builder.art(inkling::Art::parse(&text));
104 }
105 let loader = builder.start();
106 for &(percent, dwell) in schedule {
107 let done = (percent / 100.0 * total as f64) as u64;
108 loader.set(done);
109 loader.set_message(format!(
110 "dragon.iso {:.1} / {:.1} MB",
111 done as f64 / mb,
112 total as f64 / mb
113 ));
114 pause(dwell);
115 }
116 loader.finish();
117
118 // A finish that ties it together.
119 let _ = execute!(io::stdout(), Print("\r\n"));
120 step(
121 "\u{2713}",
122 Color::Green,
123 "Verified checksum sha256:a1b2c3d4e5",
124 );
125 pause(400);
126 let _ = execute!(
127 io::stdout(),
128 Print("\r\n "),
129 SetForegroundColor(Color::Green),
130 Print("Done"),
131 ResetColor,
132 Print(format!(
133 " in {:.1}s. dragon.iso (48.0 MB) ready.\r\n\r\n",
134 started.elapsed().as_secs_f64()
135 ))
136 );
137 let _ = io::stdout().flush();
138}Sourcepub fn inc(&self, delta: u64)
pub fn inc(&self, delta: u64)
Advance the position by delta.
Examples found in repository?
21fn main() {
22 match std::env::args().nth(1).as_deref() {
23 Some("iter") => {
24 for _ in (0..100).inkling() {
25 work(20);
26 }
27 }
28 Some("spinner") => {
29 let loader = Loader::spinner();
30 loader.set_message("Doing something mysterious");
31 work(2500);
32 loader.finish();
33 }
34 Some("threads") => {
35 let loader = Loader::new(120);
36 loader.set_message("Four workers, one dragon");
37 thread::scope(|s| {
38 for _ in 0..4 {
39 let handle = loader.handle();
40 s.spawn(move || {
41 for _ in 0..30 {
42 work(30);
43 handle.inc(1);
44 }
45 });
46 }
47 });
48 loader.finish();
49 }
50 Some("rainbow") => {
51 let loader = Loader::builder()
52 .total(100)
53 .style(inkling::render::Style::rainbow())
54 .message("Tasting the rainbow")
55 .start();
56 for _ in 0..100 {
57 work(20);
58 loader.inc(1);
59 }
60 loader.finish();
61 }
62 _ => {
63 let total: u64 = 100;
64 let loader = Loader::new(total);
65 loader.set_message("Summoning the dragon");
66 for _ in 0..total {
67 work(20);
68 loader.inc(1);
69 }
70 loader.finish();
71 }
72 }
73}Sourcepub fn set(&self, pos: u64)
pub fn set(&self, pos: u64)
Set the absolute position.
Examples found in repository?
36fn main() {
37 let args: Vec<String> = std::env::args().skip(1).collect();
38 let rainbow = args.iter().any(|a| a == "rainbow");
39 let geodesic = args.iter().any(|a| a == "geodesic");
40 let art_path = args.iter().find(|a| a.ends_with(".txt")).cloned();
41 let started = Instant::now();
42 let gold = Color::Rgb {
43 r: 232,
44 g: 180,
45 b: 85,
46 };
47
48 // Clear to a fresh screen and print the tool banner.
49 let _ = execute!(
50 io::stdout(),
51 Clear(ClearType::All),
52 MoveTo(0, 0),
53 Print("\r\n "),
54 SetForegroundColor(gold),
55 Print("dragonctl"),
56 ResetColor,
57 Print(" v0.2.0\r\n\r\n")
58 );
59
60 step("\u{2713}", Color::Green, "Initializing demo environment");
61 pause(450);
62 step("\u{2713}", Color::Green, "Updating base image index");
63 pause(500);
64 step("\u{2193}", Color::Cyan, "Downloading base image");
65 let _ = execute!(io::stdout(), Print("\r\n"));
66
67 // The download itself, paced unevenly: a connect stall, a hiccup, a burst, a
68 // mid stall, and a slow tail.
69 let total: u64 = 48 * 1024 * 1024;
70 let mb = 1024.0 * 1024.0;
71 let schedule: &[(f64, u64)] = &[
72 (0.0, 600),
73 (5.0, 300),
74 (8.0, 250),
75 (8.0, 650),
76 (16.0, 220),
77 (27.0, 180),
78 (38.0, 200),
79 (45.0, 450),
80 (56.0, 200),
81 (67.0, 220),
82 (78.0, 260),
83 (87.0, 320),
84 (93.0, 480),
85 (97.0, 520),
86 (100.0, 300),
87 ];
88
89 let style = if rainbow {
90 Style::rainbow()
91 } else {
92 Style::default()
93 };
94 let mut builder = Loader::builder().total(total).style(style);
95 if geodesic {
96 builder = builder.ordering(Geodesic::default());
97 }
98 if let Some(path) = &art_path {
99 let text = std::fs::read_to_string(path).unwrap_or_else(|e| {
100 eprintln!("could not read {path}: {e}");
101 std::process::exit(1);
102 });
103 builder = builder.art(inkling::Art::parse(&text));
104 }
105 let loader = builder.start();
106 for &(percent, dwell) in schedule {
107 let done = (percent / 100.0 * total as f64) as u64;
108 loader.set(done);
109 loader.set_message(format!(
110 "dragon.iso {:.1} / {:.1} MB",
111 done as f64 / mb,
112 total as f64 / mb
113 ));
114 pause(dwell);
115 }
116 loader.finish();
117
118 // A finish that ties it together.
119 let _ = execute!(io::stdout(), Print("\r\n"));
120 step(
121 "\u{2713}",
122 Color::Green,
123 "Verified checksum sha256:a1b2c3d4e5",
124 );
125 pause(400);
126 let _ = execute!(
127 io::stdout(),
128 Print("\r\n "),
129 SetForegroundColor(Color::Green),
130 Print("Done"),
131 ResetColor,
132 Print(format!(
133 " in {:.1}s. dragon.iso (48.0 MB) ready.\r\n\r\n",
134 started.elapsed().as_secs_f64()
135 ))
136 );
137 let _ = io::stdout().flush();
138}Sourcepub fn set_length(&self, total: u64)
pub fn set_length(&self, total: u64)
Change the total amount of work.
Sourcepub fn set_message<S: Into<String>>(&self, msg: S)
pub fn set_message<S: Into<String>>(&self, msg: S)
Set a short caption shown beneath the art.
Examples found in repository?
21fn main() {
22 match std::env::args().nth(1).as_deref() {
23 Some("iter") => {
24 for _ in (0..100).inkling() {
25 work(20);
26 }
27 }
28 Some("spinner") => {
29 let loader = Loader::spinner();
30 loader.set_message("Doing something mysterious");
31 work(2500);
32 loader.finish();
33 }
34 Some("threads") => {
35 let loader = Loader::new(120);
36 loader.set_message("Four workers, one dragon");
37 thread::scope(|s| {
38 for _ in 0..4 {
39 let handle = loader.handle();
40 s.spawn(move || {
41 for _ in 0..30 {
42 work(30);
43 handle.inc(1);
44 }
45 });
46 }
47 });
48 loader.finish();
49 }
50 Some("rainbow") => {
51 let loader = Loader::builder()
52 .total(100)
53 .style(inkling::render::Style::rainbow())
54 .message("Tasting the rainbow")
55 .start();
56 for _ in 0..100 {
57 work(20);
58 loader.inc(1);
59 }
60 loader.finish();
61 }
62 _ => {
63 let total: u64 = 100;
64 let loader = Loader::new(total);
65 loader.set_message("Summoning the dragon");
66 for _ in 0..total {
67 work(20);
68 loader.inc(1);
69 }
70 loader.finish();
71 }
72 }
73}More examples
36fn main() {
37 let args: Vec<String> = std::env::args().skip(1).collect();
38 let rainbow = args.iter().any(|a| a == "rainbow");
39 let geodesic = args.iter().any(|a| a == "geodesic");
40 let art_path = args.iter().find(|a| a.ends_with(".txt")).cloned();
41 let started = Instant::now();
42 let gold = Color::Rgb {
43 r: 232,
44 g: 180,
45 b: 85,
46 };
47
48 // Clear to a fresh screen and print the tool banner.
49 let _ = execute!(
50 io::stdout(),
51 Clear(ClearType::All),
52 MoveTo(0, 0),
53 Print("\r\n "),
54 SetForegroundColor(gold),
55 Print("dragonctl"),
56 ResetColor,
57 Print(" v0.2.0\r\n\r\n")
58 );
59
60 step("\u{2713}", Color::Green, "Initializing demo environment");
61 pause(450);
62 step("\u{2713}", Color::Green, "Updating base image index");
63 pause(500);
64 step("\u{2193}", Color::Cyan, "Downloading base image");
65 let _ = execute!(io::stdout(), Print("\r\n"));
66
67 // The download itself, paced unevenly: a connect stall, a hiccup, a burst, a
68 // mid stall, and a slow tail.
69 let total: u64 = 48 * 1024 * 1024;
70 let mb = 1024.0 * 1024.0;
71 let schedule: &[(f64, u64)] = &[
72 (0.0, 600),
73 (5.0, 300),
74 (8.0, 250),
75 (8.0, 650),
76 (16.0, 220),
77 (27.0, 180),
78 (38.0, 200),
79 (45.0, 450),
80 (56.0, 200),
81 (67.0, 220),
82 (78.0, 260),
83 (87.0, 320),
84 (93.0, 480),
85 (97.0, 520),
86 (100.0, 300),
87 ];
88
89 let style = if rainbow {
90 Style::rainbow()
91 } else {
92 Style::default()
93 };
94 let mut builder = Loader::builder().total(total).style(style);
95 if geodesic {
96 builder = builder.ordering(Geodesic::default());
97 }
98 if let Some(path) = &art_path {
99 let text = std::fs::read_to_string(path).unwrap_or_else(|e| {
100 eprintln!("could not read {path}: {e}");
101 std::process::exit(1);
102 });
103 builder = builder.art(inkling::Art::parse(&text));
104 }
105 let loader = builder.start();
106 for &(percent, dwell) in schedule {
107 let done = (percent / 100.0 * total as f64) as u64;
108 loader.set(done);
109 loader.set_message(format!(
110 "dragon.iso {:.1} / {:.1} MB",
111 done as f64 / mb,
112 total as f64 / mb
113 ));
114 pause(dwell);
115 }
116 loader.finish();
117
118 // A finish that ties it together.
119 let _ = execute!(io::stdout(), Print("\r\n"));
120 step(
121 "\u{2713}",
122 Color::Green,
123 "Verified checksum sha256:a1b2c3d4e5",
124 );
125 pause(400);
126 let _ = execute!(
127 io::stdout(),
128 Print("\r\n "),
129 SetForegroundColor(Color::Green),
130 Print("Done"),
131 ResetColor,
132 Print(format!(
133 " in {:.1}s. dragon.iso (48.0 MB) ready.\r\n\r\n",
134 started.elapsed().as_secs_f64()
135 ))
136 );
137 let _ = io::stdout().flush();
138}Sourcepub fn handle(&self) -> Handle
pub fn handle(&self) -> Handle
A cheap, clonable, Send + Sync handle for reporting progress from other
threads. Handles can update but not finish the loader.
Examples found in repository?
21fn main() {
22 match std::env::args().nth(1).as_deref() {
23 Some("iter") => {
24 for _ in (0..100).inkling() {
25 work(20);
26 }
27 }
28 Some("spinner") => {
29 let loader = Loader::spinner();
30 loader.set_message("Doing something mysterious");
31 work(2500);
32 loader.finish();
33 }
34 Some("threads") => {
35 let loader = Loader::new(120);
36 loader.set_message("Four workers, one dragon");
37 thread::scope(|s| {
38 for _ in 0..4 {
39 let handle = loader.handle();
40 s.spawn(move || {
41 for _ in 0..30 {
42 work(30);
43 handle.inc(1);
44 }
45 });
46 }
47 });
48 loader.finish();
49 }
50 Some("rainbow") => {
51 let loader = Loader::builder()
52 .total(100)
53 .style(inkling::render::Style::rainbow())
54 .message("Tasting the rainbow")
55 .start();
56 for _ in 0..100 {
57 work(20);
58 loader.inc(1);
59 }
60 loader.finish();
61 }
62 _ => {
63 let total: u64 = 100;
64 let loader = Loader::new(total);
65 loader.set_message("Summoning the dragon");
66 for _ in 0..total {
67 work(20);
68 loader.inc(1);
69 }
70 loader.finish();
71 }
72 }
73}Sourcepub fn wrap_read<R: Read>(&self, reader: R) -> ProgressReader<R> ⓘ
pub fn wrap_read<R: Read>(&self, reader: R) -> ProgressReader<R> ⓘ
Wrap a reader so every byte read advances the loader. Ideal for downloads: set the length to the content length, then read through the wrapper.
Sourcepub fn finish(&self)
pub fn finish(&self)
Fill the art, leave it on screen, and restore the terminal.
Examples found in repository?
21fn main() {
22 match std::env::args().nth(1).as_deref() {
23 Some("iter") => {
24 for _ in (0..100).inkling() {
25 work(20);
26 }
27 }
28 Some("spinner") => {
29 let loader = Loader::spinner();
30 loader.set_message("Doing something mysterious");
31 work(2500);
32 loader.finish();
33 }
34 Some("threads") => {
35 let loader = Loader::new(120);
36 loader.set_message("Four workers, one dragon");
37 thread::scope(|s| {
38 for _ in 0..4 {
39 let handle = loader.handle();
40 s.spawn(move || {
41 for _ in 0..30 {
42 work(30);
43 handle.inc(1);
44 }
45 });
46 }
47 });
48 loader.finish();
49 }
50 Some("rainbow") => {
51 let loader = Loader::builder()
52 .total(100)
53 .style(inkling::render::Style::rainbow())
54 .message("Tasting the rainbow")
55 .start();
56 for _ in 0..100 {
57 work(20);
58 loader.inc(1);
59 }
60 loader.finish();
61 }
62 _ => {
63 let total: u64 = 100;
64 let loader = Loader::new(total);
65 loader.set_message("Summoning the dragon");
66 for _ in 0..total {
67 work(20);
68 loader.inc(1);
69 }
70 loader.finish();
71 }
72 }
73}More examples
36fn main() {
37 let args: Vec<String> = std::env::args().skip(1).collect();
38 let rainbow = args.iter().any(|a| a == "rainbow");
39 let geodesic = args.iter().any(|a| a == "geodesic");
40 let art_path = args.iter().find(|a| a.ends_with(".txt")).cloned();
41 let started = Instant::now();
42 let gold = Color::Rgb {
43 r: 232,
44 g: 180,
45 b: 85,
46 };
47
48 // Clear to a fresh screen and print the tool banner.
49 let _ = execute!(
50 io::stdout(),
51 Clear(ClearType::All),
52 MoveTo(0, 0),
53 Print("\r\n "),
54 SetForegroundColor(gold),
55 Print("dragonctl"),
56 ResetColor,
57 Print(" v0.2.0\r\n\r\n")
58 );
59
60 step("\u{2713}", Color::Green, "Initializing demo environment");
61 pause(450);
62 step("\u{2713}", Color::Green, "Updating base image index");
63 pause(500);
64 step("\u{2193}", Color::Cyan, "Downloading base image");
65 let _ = execute!(io::stdout(), Print("\r\n"));
66
67 // The download itself, paced unevenly: a connect stall, a hiccup, a burst, a
68 // mid stall, and a slow tail.
69 let total: u64 = 48 * 1024 * 1024;
70 let mb = 1024.0 * 1024.0;
71 let schedule: &[(f64, u64)] = &[
72 (0.0, 600),
73 (5.0, 300),
74 (8.0, 250),
75 (8.0, 650),
76 (16.0, 220),
77 (27.0, 180),
78 (38.0, 200),
79 (45.0, 450),
80 (56.0, 200),
81 (67.0, 220),
82 (78.0, 260),
83 (87.0, 320),
84 (93.0, 480),
85 (97.0, 520),
86 (100.0, 300),
87 ];
88
89 let style = if rainbow {
90 Style::rainbow()
91 } else {
92 Style::default()
93 };
94 let mut builder = Loader::builder().total(total).style(style);
95 if geodesic {
96 builder = builder.ordering(Geodesic::default());
97 }
98 if let Some(path) = &art_path {
99 let text = std::fs::read_to_string(path).unwrap_or_else(|e| {
100 eprintln!("could not read {path}: {e}");
101 std::process::exit(1);
102 });
103 builder = builder.art(inkling::Art::parse(&text));
104 }
105 let loader = builder.start();
106 for &(percent, dwell) in schedule {
107 let done = (percent / 100.0 * total as f64) as u64;
108 loader.set(done);
109 loader.set_message(format!(
110 "dragon.iso {:.1} / {:.1} MB",
111 done as f64 / mb,
112 total as f64 / mb
113 ));
114 pause(dwell);
115 }
116 loader.finish();
117
118 // A finish that ties it together.
119 let _ = execute!(io::stdout(), Print("\r\n"));
120 step(
121 "\u{2713}",
122 Color::Green,
123 "Verified checksum sha256:a1b2c3d4e5",
124 );
125 pause(400);
126 let _ = execute!(
127 io::stdout(),
128 Print("\r\n "),
129 SetForegroundColor(Color::Green),
130 Print("Done"),
131 ResetColor,
132 Print(format!(
133 " in {:.1}s. dragon.iso (48.0 MB) ready.\r\n\r\n",
134 started.elapsed().as_secs_f64()
135 ))
136 );
137 let _ = io::stdout().flush();
138}Sourcepub fn finish_and_clear(&self)
pub fn finish_and_clear(&self)
Finish and erase the art from the screen.