From c84672cf780ce3e6bf268fb67c04cb9e022afd87 Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Thu, 27 Jun 2024 15:45:29 +0200 Subject: [PATCH] rust statusbars are actually pretty amazing --- Cargo.lock | 42 +++++++++ Cargo.toml | 2 + members/statusline/Cargo.toml | 8 ++ members/statusline/src/main.rs | 156 +++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 members/statusline/Cargo.toml create mode 100644 members/statusline/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index d3c20af..b7ccc07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1224,12 +1224,34 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + [[package]] name = "inflections" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "intl-memoizer" version = "0.5.2" @@ -1565,6 +1587,12 @@ dependencies = [ "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.36.0" @@ -1790,6 +1818,12 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + [[package]] name = "powerfmt" version = "0.2.0" @@ -2227,6 +2261,14 @@ dependencies = [ "rusqlite", ] +[[package]] +name = "statusline" +version = "0.1.0" +dependencies = [ + "indicatif", + "rand", +] + [[package]] name = "strsim" version = "0.11.1" diff --git a/Cargo.toml b/Cargo.toml index c029e98..5c58efe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,9 +25,11 @@ members = [ "members/diesel-demo", "members/ptlog", "members/hello-world", + "members/statusline", ] default-members = [ ".", + "members/statusline", "members/ptlog", "members/diesel-demo", "members/onlytoken", diff --git a/members/statusline/Cargo.toml b/members/statusline/Cargo.toml new file mode 100644 index 0000000..aa59eac --- /dev/null +++ b/members/statusline/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "statusline" +version = "0.1.0" +edition = "2021" + +[dependencies] +indicatif = "0.17.8" +rand = "0.8.5" diff --git a/members/statusline/src/main.rs b/members/statusline/src/main.rs new file mode 100644 index 0000000..3e832ce --- /dev/null +++ b/members/statusline/src/main.rs @@ -0,0 +1,156 @@ +// most of this is stolen from the indicatif examples (also MIT) + +use std::cmp::min; +use std::fmt::Write; +use std::thread::{self, sleep_ms}; +use std::time::Duration; + +use indicatif::{MultiProgress, ProgressBar, ProgressIterator, ProgressState, ProgressStyle}; +use rand::Rng; + +fn main() { + // b0(); + // b1(); + // b2(); + b3(); + b4(); + b5(); + b6(); +} + +fn b0() { + let bar = ProgressBar::new(1_000); + for _ in 0..1_000 { + bar.inc(1); + sleep_ms(1); + } + bar.finish(); +} + +fn b1() { + let bar = ProgressBar::new_spinner(); + bar.enable_steady_tick(Duration::from_millis(100)); + for _ in 0..1_000 { + bar.inc(1); + sleep_ms(1); + } + bar.finish(); +} + +fn b2() { + for _ in (0..1_000).progress() { + sleep_ms(1); + } +} + +fn b3() { + let bar = ProgressBar::new(1_000); + bar.set_style( + ProgressStyle::with_template( + "[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", + ) + .unwrap() + .progress_chars("▄▌_"), + ); + for _ in 0..1_000 { + bar.inc(1); + sleep_ms(1); + } + bar.finish(); +} + +fn b4() { + use indicatif::{HumanBytes, HumanCount, HumanDuration, HumanFloatCount}; + + assert_eq!("3.00 MiB", HumanBytes(3 * 1024 * 1024).to_string()); + assert_eq!( + "8 seconds", + HumanDuration(Duration::from_secs(8)).to_string() + ); + assert_eq!("33,857,009", HumanCount(33857009).to_string()); + assert_eq!( + "33,857,009.1235", + HumanFloatCount(33857009.123456).to_string() + ); +} + +fn b5() { + let mut downloaded = 0; + let total_size = 231331; + + let pb = ProgressBar::new(total_size); + pb.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})") + .unwrap() + .with_key("eta", |state: &ProgressState, w: &mut dyn Write| write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap()) + .progress_chars("#>-")); + + while downloaded < total_size { + let new = min(downloaded + 223211, total_size); + downloaded = new; + pb.set_position(new); + thread::sleep(Duration::from_millis(12)); + } + + pb.finish_with_message("downloaded"); +} + +fn b6() { + let m = MultiProgress::new(); + let sty = ProgressStyle::with_template( + "[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}", + ) + .unwrap() + .progress_chars("##-"); + + let n = 20; + let pb = m.add(ProgressBar::new(n)); + pb.set_style(sty.clone()); + pb.set_message("todo"); + let pb2 = m.add(ProgressBar::new(n)); + pb2.set_style(sty.clone()); + pb2.set_message("finished"); + + let pb3 = m.insert_after(&pb2, ProgressBar::new(1024)); + pb3.set_style(sty); + + m.println("starting!").unwrap(); + + let mut threads = vec![]; + + let m_clone = m.clone(); + let h3 = thread::spawn(move || { + for i in 0..1024 { + thread::sleep(Duration::from_millis(2)); + pb3.set_message(format!("item #{}", i + 1)); + pb3.inc(1); + } + m_clone.println("pb3 is done!").unwrap(); + pb3.finish_with_message("done"); + }); + + for i in 0..n { + thread::sleep(Duration::from_millis(15)); + if i == n / 3 { + thread::sleep(Duration::from_secs(2)); + } + pb.inc(1); + let m = m.clone(); + let pb2 = pb2.clone(); + threads.push(thread::spawn(move || { + let spinner = m.add(ProgressBar::new_spinner().with_message(i.to_string())); + spinner.enable_steady_tick(Duration::from_millis(100)); + thread::sleep( + rand::thread_rng().gen_range(Duration::from_secs(1)..Duration::from_secs(5)), + ); + pb2.inc(1); + })); + } + pb.finish_with_message("all jobs started"); + + for thread in threads { + let _ = thread.join(); + } + let _ = h3.join(); + pb2.finish_with_message("all jobs done"); + m.clear().unwrap(); +}