From 862caed98b4ba797cb6e021a36ff7c686b5cc8fd Mon Sep 17 00:00:00 2001 From: 4a656666 <4a656666official@gmail.com> Date: Fri, 11 Feb 2022 16:56:27 -0600 Subject: [PATCH] Initial commit --- Cargo.toml | 9 ++++ src/main.rs | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e39b0d4 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "progress" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +termsize = "0.1" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..46082ab --- /dev/null +++ b/src/main.rs @@ -0,0 +1,128 @@ +use std::{process::exit, env::Args}; + +static DEFAULT_MAX: usize = 100; +static DEFAULT_WIDTH: usize = 80; + +fn main() { + let args = std::env::args(); + let config = match Config::new(args) { + Ok(v ) => v, + Err(e) => err(&e) + }; + + // [#####....] ---- 50% + + let percent = config.val * 100 / config.max; + let percent_str = percent.to_string(); + let after_bar = format!(" {} {}% ", "-".repeat(6 - percent_str.len()), percent_str); + let bar_len = config.width - after_bar.len(); + let sep = bar_len * percent / 100; + + let mut bar = String::new(); + + bar.push(if sep > 0 { config.first_char.1 } else { config.first_char.0 }); + for i in 1..bar_len-1 { + bar.push(if sep > i { config.middle_char.1 } else { config.middle_char.0 }); + } + bar.push(if sep > bar_len-1 { config.last_char.1 } else { config.last_char.0 }); + + println!("{}{}", bar, after_bar); +} + +fn err(msg: &str) -> ! { + eprintln!("{}", msg); + show_help(); + exit(1); +} + +fn show_help() { + eprintln!("Usage: progress [--max ] [--width ] [--fira]"); +} + +struct Config { + val: usize, + max: usize, + first_char: (char, char), + middle_char: (char, char), + last_char: (char, char), + width: usize +} + +impl Config { + fn new(mut args: Args) -> Result { + args.next(); + let mut val = None; + let mut max = None; + let mut first_char = ('[', '['); + let mut middle_char = ('.', '#'); + let mut last_char = (']', ']'); + let mut width = None; + + while let Some(next) = args.next() { + if next.starts_with("--") { + if next == "--fira" { + first_char = ('\u{ee00}', '\u{ee03}'); + middle_char = ('\u{ee01}', '\u{ee04}'); + last_char = ('\u{ee02}', '\u{ee05}'); + } else if next == "--max" { + if let Some(_) = max { return Err("can only provide 1 max".to_string()) } + let next = match args.next() { + Some(v) => v, + None => return Err("must provide a max after --max".to_string()) + }; + let max_result = next.parse(); + match max_result { + Ok(v) => max = Some(v), + Err(_) => return Err("max must be a number".to_string()) + } + } else if next == "--width" { + if let Some(_) = width { return Err("can only provide 1 width".to_string()) } + let next = match args.next() { + Some(v) => v, + None => return Err("must provide a width after --width".to_string()) + }; + let max_result = next.parse(); + match max_result { + Ok(v) => width = Some(v), + Err(_) => return Err("width must be a number".to_string()) + } + } else { + return Err(format!("unknown option `{}`", next)); + } + } else { + if let Some(_) = val { return Err("can only provide 1 value".to_string()) } + let val_result = next.parse(); + match val_result { + Ok(v) => val = Some(v), + Err(_) => return Err("max must be a number".to_string()) + } + } + } + + let val = match val { + Some(v) => v, + None => return Err("must provide a value".to_string()) + }; + + let max = max.unwrap_or(DEFAULT_MAX); + + if val > max { + return Err("value cannot be > max".to_string()); + } + + let width = width.unwrap_or_else(|| termsize::get().map_or(DEFAULT_WIDTH, |v| v.cols.into())); + + if width < 11 { + return Err("window not wide enough".to_string()); + } + + Ok(Config { + val, + max, + first_char, + middle_char, + last_char, + width + }) + } +} \ No newline at end of file