stdin stuff
This commit is contained in:
parent
862caed98b
commit
4e05c1a6d4
133
src/main.rs
133
src/main.rs
|
@ -1,4 +1,4 @@
|
||||||
use std::{process::exit, env::Args};
|
use std::{process::exit, env::Args, io::{stdin, Read}, sync::mpsc, thread, time::Instant};
|
||||||
|
|
||||||
static DEFAULT_MAX: usize = 100;
|
static DEFAULT_MAX: usize = 100;
|
||||||
static DEFAULT_WIDTH: usize = 80;
|
static DEFAULT_WIDTH: usize = 80;
|
||||||
|
@ -9,24 +9,66 @@ fn main() {
|
||||||
Ok(v ) => v,
|
Ok(v ) => v,
|
||||||
Err(e) => err(&e)
|
Err(e) => err(&e)
|
||||||
};
|
};
|
||||||
|
|
||||||
// [#####....] ---- 50%
|
|
||||||
|
|
||||||
let percent = config.val * 100 / config.max;
|
if let Some(val) = config.val {
|
||||||
|
let bar = generate_bar(val, config.max, config.width, &config.chars, None);
|
||||||
|
println!("{}", bar);
|
||||||
|
} else {
|
||||||
|
let (tx, rx) = mpsc::sync_channel(256);
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut stdin = stdin();
|
||||||
|
let mut out = [0; 1];
|
||||||
|
loop {
|
||||||
|
if let Ok(count) = stdin.read(&mut out) {
|
||||||
|
tx.send(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let mut val = 0;
|
||||||
|
let mut spin = 0;
|
||||||
|
let now = Instant::now();
|
||||||
|
loop {
|
||||||
|
if let Ok(count) = rx.try_recv() {
|
||||||
|
val += count;
|
||||||
|
}
|
||||||
|
let bar = generate_bar_clamp(val, config.max, config.width, &config.chars, Some(spin));
|
||||||
|
print!("\r{}", bar);
|
||||||
|
if val >= config.max {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spin = ((now.elapsed().as_millis() / 100) % 6) as usize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_bar(val: usize, max: usize, width: usize, chars: &Chars, spin: Option<usize>) -> String {
|
||||||
|
let percent = val * 100 / max;
|
||||||
let percent_str = percent.to_string();
|
let percent_str = percent.to_string();
|
||||||
let after_bar = format!(" {} {}% ", "-".repeat(6 - percent_str.len()), percent_str);
|
let after_bar = if let Some(spin) = spin {
|
||||||
let bar_len = config.width - after_bar.len();
|
format!(" {} {}% {} ", "-".repeat(6 - percent_str.len()), percent_str, if val == max { chars.spin_done() } else { chars.spin(spin) })
|
||||||
|
} else {
|
||||||
|
format!(" {} {}% ", "-".repeat(6 - percent_str.len()), percent_str)
|
||||||
|
};
|
||||||
|
let bar_len = width - after_bar.len();
|
||||||
let sep = bar_len * percent / 100;
|
let sep = bar_len * percent / 100;
|
||||||
|
|
||||||
let mut bar = String::new();
|
let mut bar = String::new();
|
||||||
|
|
||||||
bar.push(if sep > 0 { config.first_char.1 } else { config.first_char.0 });
|
bar.push(chars.first(sep > 0));
|
||||||
for i in 1..bar_len-1 {
|
for i in 1..bar_len-1 {
|
||||||
bar.push(if sep > i { config.middle_char.1 } else { config.middle_char.0 });
|
bar.push(chars.mid(sep > i));
|
||||||
}
|
}
|
||||||
bar.push(if sep > bar_len-1 { config.last_char.1 } else { config.last_char.0 });
|
bar.push(chars.last(sep > bar_len - 1));
|
||||||
|
|
||||||
println!("{}{}", bar, after_bar);
|
format!("{}{}", bar, after_bar)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_bar_clamp(mut val: usize, max: usize, width: usize, chars: &Chars, spin: Option<usize>) -> String {
|
||||||
|
if val > max {
|
||||||
|
val = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_bar(val, max, width, chars, spin)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn err(msg: &str) -> ! {
|
fn err(msg: &str) -> ! {
|
||||||
|
@ -36,16 +78,48 @@ fn err(msg: &str) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_help() {
|
fn show_help() {
|
||||||
eprintln!("Usage: progress <value> [--max <max>] [--width <width>] [--fira]");
|
eprintln!("Usage: progress [<value>] [--max <max>] [--width <width>] [--fira]");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Chars {
|
||||||
|
first: (char, char),
|
||||||
|
mid: (char, char),
|
||||||
|
last: (char, char),
|
||||||
|
spin: [char; 6],
|
||||||
|
spin_done: char
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Chars {
|
||||||
|
fn new(first: (char, char), mid: (char, char), last: (char, char), spin: [char; 6], spin_done: char) -> Self {
|
||||||
|
Self { first, mid, last, spin, spin_done }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first(&self, filled: bool) -> char {
|
||||||
|
if filled { self.first.1 } else { self.first.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mid(&self, filled: bool) -> char {
|
||||||
|
if filled { self.mid.1 } else { self.mid.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last(&self, filled: bool) -> char {
|
||||||
|
if filled { self.last.1 } else { self.last.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spin(&self, n: usize) -> char {
|
||||||
|
self.spin[n % 6]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spin_done(&self) -> char {
|
||||||
|
self.spin_done
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
val: usize,
|
val: Option<usize>,
|
||||||
max: usize,
|
max: usize,
|
||||||
first_char: (char, char),
|
width: usize,
|
||||||
middle_char: (char, char),
|
chars: Chars
|
||||||
last_char: (char, char),
|
|
||||||
width: usize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
@ -53,17 +127,19 @@ impl Config {
|
||||||
args.next();
|
args.next();
|
||||||
let mut val = None;
|
let mut val = None;
|
||||||
let mut max = None;
|
let mut max = None;
|
||||||
let mut first_char = ('[', '[');
|
|
||||||
let mut middle_char = ('.', '#');
|
|
||||||
let mut last_char = (']', ']');
|
|
||||||
let mut width = None;
|
let mut width = None;
|
||||||
|
let mut first_char = ('[', '[');
|
||||||
|
let mut mid_char = ('.', '#');
|
||||||
|
let mut last_char = (']', ']');
|
||||||
|
let mut spin = ['/', '-', '\\', '/', '-', '\\'];
|
||||||
|
|
||||||
while let Some(next) = args.next() {
|
while let Some(next) = args.next() {
|
||||||
if next.starts_with("--") {
|
if next.starts_with("--") {
|
||||||
if next == "--fira" {
|
if next == "--fira" {
|
||||||
first_char = ('\u{ee00}', '\u{ee03}');
|
first_char = ('\u{ee00}', '\u{ee03}');
|
||||||
middle_char = ('\u{ee01}', '\u{ee04}');
|
mid_char = ('\u{ee01}', '\u{ee04}');
|
||||||
last_char = ('\u{ee02}', '\u{ee05}');
|
last_char = ('\u{ee02}', '\u{ee05}');
|
||||||
|
spin = ['\u{ee06}', '\u{ee07}', '\u{ee08}', '\u{ee09}', '\u{ee0a}', '\u{ee0b}'];
|
||||||
} else if next == "--max" {
|
} else if next == "--max" {
|
||||||
if let Some(_) = max { return Err("can only provide 1 max".to_string()) }
|
if let Some(_) = max { return Err("can only provide 1 max".to_string()) }
|
||||||
let next = match args.next() {
|
let next = match args.next() {
|
||||||
|
@ -98,18 +174,9 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let val = match val {
|
|
||||||
Some(v) => v,
|
|
||||||
None => return Err("must provide a value".to_string())
|
|
||||||
};
|
|
||||||
|
|
||||||
let max = max.unwrap_or(DEFAULT_MAX);
|
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()));
|
let width = width.unwrap_or_else(|| termsize::get().map_or(DEFAULT_WIDTH, |v| v.cols.into()));
|
||||||
|
|
||||||
if width < 11 {
|
if width < 11 {
|
||||||
|
@ -117,12 +184,8 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Config {
|
Ok(Config {
|
||||||
val,
|
val, max, width,
|
||||||
max,
|
chars: Chars::new(first_char, mid_char, last_char, spin, '✓'),
|
||||||
first_char,
|
|
||||||
middle_char,
|
|
||||||
last_char,
|
|
||||||
width
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue