You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
7.1 KiB
225 lines
7.1 KiB
use clap::{self, App, AppSettings, Arg}; |
|
|
|
fn add_input(app: App) -> App { |
|
app.arg( |
|
Arg::new("input") |
|
.about("Input file") |
|
.default_value("-") |
|
.long_about("If not present or a single dash, standard input will be used"), |
|
) |
|
} |
|
|
|
fn add_min_max(app: App) -> App { |
|
app.arg( |
|
Arg::new("max") |
|
.long("max") |
|
.short('M') |
|
.about("Filter out values bigger than this") |
|
.takes_value(true), |
|
) |
|
.arg( |
|
Arg::new("min") |
|
.long("min") |
|
.short('m') |
|
.about("Filter out values smaller than this") |
|
.takes_value(true), |
|
) |
|
} |
|
|
|
fn add_regex(app: App) -> App { |
|
const LONG_RE_ABOUT: &str = "\ |
|
A regular expression used for capturing the values to be plotted inside input |
|
lines. |
|
|
|
By default this will use a capture group named `value`. If not present, it will |
|
use first capture group. |
|
|
|
If no regex is used, a number per line is expected (something that can be parsed |
|
as float). |
|
|
|
Examples of regex are ' 200 \\d+ ([0-9.]+)' (where there is one anonymous capture |
|
group) and 'a(a)? (?P<value>[0-9.]+)' (where there are two capture groups, and |
|
the named one will be used). |
|
"; |
|
app.arg( |
|
Arg::new("regex") |
|
.long("regex") |
|
.short('R') |
|
.about("Use a regex to capture input values") |
|
.long_about(LONG_RE_ABOUT) |
|
.takes_value(true), |
|
) |
|
} |
|
|
|
fn add_width(app: App) -> App { |
|
app.arg( |
|
Arg::new("width") |
|
.long("width") |
|
.short('w') |
|
.about("Use this many characters as terminal width") |
|
.default_value("110") |
|
.takes_value(true), |
|
) |
|
} |
|
|
|
fn add_intervals(app: App) -> App { |
|
app.arg( |
|
Arg::new("intervals") |
|
.long("intervals") |
|
.short('i') |
|
.about("Use no more than this amount of buckets to classify data") |
|
.default_value("20") |
|
.takes_value(true), |
|
) |
|
} |
|
|
|
pub fn get_app() -> App<'static> { |
|
let mut hist = App::new("hist") |
|
.version(clap::crate_version!()) |
|
.setting(AppSettings::ColoredHelp) |
|
.about("Plot an histogram from input values"); |
|
hist = add_input(add_regex(add_width(add_min_max(add_intervals(hist))))); |
|
|
|
let mut plot = App::new("plot") |
|
.version(clap::crate_version!()) |
|
.setting(AppSettings::ColoredHelp) |
|
.about("Plot an 2d x-y graph where y-values are averages of input values") |
|
.arg( |
|
Arg::new("height") |
|
.long("height") |
|
.short('h') |
|
.about("Use that many `rows` for the plot") |
|
.default_value("40") |
|
.takes_value(true), |
|
); |
|
plot = add_input(add_regex(add_width(add_min_max(plot)))); |
|
|
|
let mut matches = App::new("matches") |
|
.version(clap::crate_version!()) |
|
.setting(AppSettings::ColoredHelp) |
|
.setting(AppSettings::AllowMissingPositional) |
|
.about("Plot barchar with counts of occurences of matches params"); |
|
matches = add_input(add_width(matches)).arg( |
|
Arg::new("match") |
|
.about("Count maches for those strings") |
|
.required(true) |
|
.takes_value(true) |
|
.multiple(true), |
|
); |
|
|
|
let mut timehist = App::new("timehist") |
|
.version(clap::crate_version!()) |
|
.setting(AppSettings::ColoredHelp) |
|
.about("Plot histogram with amount of matches over time") |
|
.arg( |
|
Arg::new("format") |
|
.long("format") |
|
.short('f') |
|
.about("Use this string formatting") |
|
.takes_value(true), |
|
); |
|
timehist = add_input(add_width(add_regex(add_intervals(timehist)))); |
|
|
|
App::new("lowcharts") |
|
.author(clap::crate_authors!()) |
|
.version(clap::crate_version!()) |
|
.about(clap::crate_description!()) |
|
.max_term_width(100) |
|
.setting(AppSettings::ColoredHelp) |
|
.setting(AppSettings::SubcommandRequired) |
|
.arg( |
|
Arg::new("color") |
|
.short('c') |
|
.long("color") |
|
.about("Use colors in the output") |
|
.possible_values(&["auto", "no", "yes"]) |
|
.default_value("auto") |
|
.takes_value(true), |
|
) |
|
.arg( |
|
Arg::new("verbose") |
|
.short('v') |
|
.long("verbose") |
|
.about("Be more verbose") |
|
.takes_value(false), |
|
) |
|
.subcommand(hist) |
|
.subcommand(plot) |
|
.subcommand(matches) |
|
.subcommand(timehist) |
|
} |
|
|
|
#[cfg(test)] |
|
mod tests { |
|
|
|
use super::*; |
|
|
|
#[test] |
|
fn hist_subcommand_arg_parsing() { |
|
let arg_vec = vec!["lowcharts", "--verbose", "hist", "foo"]; |
|
let m = get_app().get_matches_from(arg_vec); |
|
assert!(m.is_present("verbose")); |
|
if let Some(sub_m) = m.subcommand_matches("hist") { |
|
assert_eq!("foo", sub_m.value_of("input").unwrap()); |
|
assert!(sub_m.value_of("max").is_none()); |
|
assert!(sub_m.value_of("min").is_none()); |
|
assert!(sub_m.value_of("regex").is_none()); |
|
assert_eq!("110", sub_m.value_of("width").unwrap()); |
|
assert_eq!("20", sub_m.value_of("intervals").unwrap()); |
|
} else { |
|
assert!(false, "Subcommand `hist` not detected"); |
|
} |
|
} |
|
|
|
#[test] |
|
fn plot_subcommand_arg_parsing() { |
|
let arg_vec = vec![ |
|
"lowcharts", |
|
"plot", |
|
"--max", |
|
"1.1", |
|
"-m", |
|
"0.9", |
|
"--height", |
|
"11", |
|
]; |
|
let m = get_app().get_matches_from(arg_vec); |
|
assert!(!m.is_present("verbose")); |
|
if let Some(sub_m) = m.subcommand_matches("plot") { |
|
assert_eq!("-", sub_m.value_of("input").unwrap()); |
|
assert_eq!("1.1", sub_m.value_of("max").unwrap()); |
|
assert_eq!("0.9", sub_m.value_of("min").unwrap()); |
|
assert_eq!("11", sub_m.value_of("height").unwrap()); |
|
} else { |
|
assert!(false, "Subcommand `plot` not detected"); |
|
} |
|
} |
|
|
|
#[test] |
|
fn matches_subcommand_arg_parsing() { |
|
let arg_vec = vec!["lowcharts", "matches", "-", "A", "B", "C"]; |
|
let m = get_app().get_matches_from(arg_vec); |
|
if let Some(sub_m) = m.subcommand_matches("matches") { |
|
assert_eq!("-", sub_m.value_of("input").unwrap()); |
|
assert_eq!( |
|
// vec![String::from("A"), String::from("B"), String::from("C")], |
|
vec!["A", "B", "C"], |
|
sub_m.values_of("match").unwrap().collect::<Vec<&str>>() |
|
); |
|
} else { |
|
assert!(false, "Subcommand `matches` not detected"); |
|
} |
|
} |
|
|
|
#[test] |
|
fn timehist_subcommand_arg_parsing() { |
|
let arg_vec = vec!["lowcharts", "timehist", "--regex", "foo", "some"]; |
|
let m = get_app().get_matches_from(arg_vec); |
|
if let Some(sub_m) = m.subcommand_matches("timehist") { |
|
assert_eq!("some", sub_m.value_of("input").unwrap()); |
|
assert_eq!("foo", sub_m.value_of("regex").unwrap()); |
|
} else { |
|
assert!(false, "Subcommand `timehist` not detected"); |
|
} |
|
} |
|
}
|
|
|