Initial commit
This commit is contained in:
parent
fb8edf220b
commit
862caed98b
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
@ -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"
|
128
src/main.rs
Normal file
128
src/main.rs
Normal file
|
@ -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 <value> [--max <max>] [--width <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<Config, String> {
|
||||||
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue