From 4a1a6171a151a4254c2ff97ca4432d767d520375 Mon Sep 17 00:00:00 2001 From: Avril Date: Thu, 24 Dec 2020 01:34:36 +0000 Subject: [PATCH] start usage message --- src/arg/mod.rs | 127 ++--------------------------- src/arg/usage.rs | 202 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 122 deletions(-) create mode 100644 src/arg/usage.rs diff --git a/src/arg/mod.rs b/src/arg/mod.rs index ee7ebb9..eb9b464 100644 --- a/src/arg/mod.rs +++ b/src/arg/mod.rs @@ -2,6 +2,8 @@ use super::*; use std::fmt; +mod usage; + /// The name of the process that was invoked #[inline] pub fn prog_name() -> &'static str { @@ -11,127 +13,9 @@ use std::fmt; &NAME[..] } -#[inline] fn options() -> impl Iterator -{ - struct Opt(&'static [&'static str], Option<&'static str>, &'static str, usize, Option<&'static str>, Option<&'static [&'static str]>); - - impl Opt - { - const fn with_def(self, vl: &'static str) -> Self - { - Self(self.0, self.1, self.2, self.3, Some(vl), self.5) - } - const fn with_slice(self, vl: &'static [&'static str]) -> Self - { - Self(self.0, self.1, self.2, self.3, self.4, Some(vl)) - } - } - - /// Macro for printing the options - /// - /// # Usage - /// Any combination of the following: - /// ``` - /// opt!("--long", "--other"; "Description"); // --long, --other: Description - /// opt!("--long", "--other"; * 2 "Description"); // --long, --other: Description - /// opt!("--long", "--other" => "value name"; "Description"); // --long, --other : Description - /// opt!("--long"; "Description", ""); // --long, --other: Description (default) - /// opt!("--long"; "Description", "Value"); // --long, --other: Description (default: `Value`) - /// opt!("--long"; "Description", ["OTHER", "OTHER 2"], "value"); // --long, --other: Description (see `OTHER`, `OTHER 2`) (default: `value`) - /// ``` - macro_rules! opt { - ($($name:literal),* => $num:literal; $desc:literal $(, [$($see:literal),*])? $(, $def:literal)?) => { - { - let o = Opt(&[$($name),*], Some($num), $desc, 1, None, None); - $(let o = o.with_def($def);)? - $(let o = o.with_slice(&[$($see),*]);)? - o - } - }; - ($($name:literal),* => $num:literal; * $tabs:literal $desc:literal $(, [$($see:literal),*])? $(, $def:literal)?) => { - { - let o = Opt(&[$($name),*], Some($num), $desc, $tabs, None, None); - $(let o = o.with_def($def);)? - $(let o = o.with_slice(&[$($see),*]);)? - o - } - }; - ($($name:literal),*; $desc:literal $(, [$($see:literal),*])? $(, $def:literal)?) => { - { - let o = Opt(&[$($name),*], None, $desc, 1, None, None); - $(let o = o.with_def($def);)? - $(let o = o.with_slice(&[$($see),*]);)? - o - } - }; - ($($name:literal),*; * $tabs:literal $desc:literal $(, [$($see:literal),*])? $(, $def:literal)?) => { - { - let o = Opt(&[$($name),*], None, $desc, $tabs, None, None); - $(let o = o.with_def($def);)? - $(let o = o.with_slice(&[$($see),*]);)? - o - } - }; - } - impl fmt::Display for Opt - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - write!(f, " {}", self.0.iter().join(", "))?; - if let Some(mx) = self.1 { - use recolored::Colorize; - write!(f, " <{}>", mx.italic())?; - } - write!(f, ":")?; - for ch in std::iter::repeat('\t').take(self.3) - { - use std::fmt::Write; - f.write_char(ch)?; - } - - write!(f,"{}", self.2)?; - { - use recolored::Colorize; - - match self.5 { - Some(&[]) => (), - Some(strings) => { - write!(f, " (see {})", strings.iter().map(|x| iter!["`".clear(), x.underline(), "`".clear()]).flat_join(", "))?; - } - _ => (), - } - - match self.4 { - Some("") => { - write!(f, " ({})", "default".bold().bright_red())?; - }, - Some(string) => { - write!(f, " ({}: `{}`)", "default".bold().bright_red(), string.bright_blue())?; - }, - None => (), - } - } - Ok(()) - } - } - - iter![ - opt!("--limit", "-l" => "max children"; "Limit the number of child processes running at once."), - opt!("--auto-limit", "-m"; * 2 "Limit to max number of CPUs + 1", ""), - opt!("--unlimit", "-U"; * 3 "No limit to number of processes spawned at once"), - opt!("--completion", "-c" => "action"; "Set the default action on completion", ["ACTIONS", "COMPLETION"], "ignore"), - opt!("--silent", "-s"; * 3 "Output no messages other than that of child processes"), - opt!("--stdout" => "where"; * 2 "Set default redirect option for childrens' `stdout`", ["ACTIONS"] ,"inherit"), - opt!("--stderr" => "where"; * 2 "Set default redirect option for childrens' `stderr`", ["ACTIONS"], "inherit"), - opt!("--stdin" => "where"; * 2 "Set default redirect option for childrens' `stdin`", ["ACTIONS"], "close") - ] -} - /// Print usage pub fn print_usage() -{ - use recolored::Colorize; - +{ println!(r#"batchtask v{version} - advanced process batching by {author} with <3 (licensed GPL3+)"#, version = env!("CARGO_PKG_VERSION"), @@ -140,12 +24,11 @@ pub fn print_usage() Usage: {prog} [OPTIONS]... Usage: {prog} --help -[{OPTIONS}]: {opts} "#, prog = prog_name(), - OPTIONS = "OPTIONS".bright_blue().bold(), - opts = options().map(|x| lazy_format!("{}", x)).join("\n")); + //OPTIONS = "OPTIONS".bright_blue().bold(), + opts = usage::sections().map(|x| lazy_format!("{}", x)).join("\n").trim()); } /// Print usage then exit diff --git a/src/arg/usage.rs b/src/arg/usage.rs new file mode 100644 index 0000000..bc84cc1 --- /dev/null +++ b/src/arg/usage.rs @@ -0,0 +1,202 @@ + +use super::*; + +struct Opt(&'static [&'static str], Option<&'static str>, &'static str, usize, Option<&'static str>, Option<&'static [&'static str]>); + +impl Opt +{ + const fn with_def(self, vl: &'static str) -> Self + { + Self(self.0, self.1, self.2, self.3, Some(vl), self.5) + } + const fn with_slice(self, vl: &'static [&'static str]) -> Self + { + Self(self.0, self.1, self.2, self.3, self.4, Some(vl)) + } +} + +/// Macro for printing the options +/// +/// # Usage +/// Any combination of the following: +/// ``` +/// opt!("--long", "--other"; "Description"); // --long, --other: Description +/// opt!("--long", "--other"; * 2 "Description"); // --long, --other: Description +/// opt!("--long", "--other" => "value name"; "Description"); // --long, --other : Description +/// opt!("--long"; "Description", ""); // --long, --other: Description (default) +/// opt!("--long"; "Description", "Value"); // --long, --other: Description (default: `Value`) +/// opt!("--long"; "Description", ["OTHER", "OTHER 2"], "value"); // --long, --other: Description (see `OTHER`, `OTHER 2`) (default: `value`) +/// ``` +#[macro_export] macro_rules! opt { + (where $desc:literal) => { + Opt(&[], None, $desc, 2, None, None) + }; + (in $supersection:literal) => { + Opt(&[], None, $supersection, 1, None, None) + }; + + ($section:literal) => { + Opt(&[], None, $section, 0, None, None) + }; + + () => { + Opt(&[], None, "", 0, None, None) + }; + + ($($name:literal),* => $num:literal; $desc:literal $(, [$($see:literal),*])? $(, $def:literal)?) => { + { + let o = Opt(&[$($name),*], Some($num), $desc, 1, None, None); + $(let o = o.with_def($def);)? + $(let o = o.with_slice(&[$($see),*]);)? + o + } + }; + ($($name:literal),* => $num:literal; * $tabs:literal $desc:literal $(, [$($see:literal),*])? $(, $def:literal)?) => { + { + let o = Opt(&[$($name),*], Some($num), $desc, $tabs, None, None); + $(let o = o.with_def($def);)? + $(let o = o.with_slice(&[$($see),*]);)? + o + } + }; + ($($name:literal),*; $desc:literal $(, [$($see:literal),*])? $(, $def:literal)?) => { + { + let o = Opt(&[$($name),*], None, $desc, 1, None, None); + $(let o = o.with_def($def);)? + $(let o = o.with_slice(&[$($see),*]);)? + o + } + }; + ($($name:literal),*; * $tabs:literal $desc:literal $(, [$($see:literal),*])? $(, $def:literal)?) => { + { + let o = Opt(&[$($name),*], None, $desc, $tabs, None, None); + $(let o = o.with_def($def);)? + $(let o = o.with_slice(&[$($see),*]);)? + o + } + }; +} +impl fmt::Display for Opt +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + { + use recolored::Colorize; + match (self.0, self.2, self.3) { + (&[], "", _) => return Ok(()), + (&[], desc, 2) => { + for line in desc.split('\n') { + writeln!(f, "> {}", line)?; + } + return Ok(()); + }, + (&[], desc, 1) => return write!(f, "[{}]:", desc.bold().bright_blue()), + (&[], desc, _) if desc.starts_with("\n") => return write!(f, "\n>>> {}:", &desc[1..].bright_cyan()), + (&[], desc, _) => return write!(f, ">>> {}:", desc.bright_cyan()), + _ => (), + }; + + let wt = self.0.iter().join(", "); + if wt.starts_with("-") { + write!(f, " {}", wt)?; + } else { + write!(f, " {}", wt.bright_blue())?; + } + } + if let Some(mx) = self.1 { + use recolored::Colorize; + write!(f, " <{}>", mx.italic())?; + } + write!(f, ":")?; + for ch in std::iter::repeat('\t').take(self.3) + { + use std::fmt::Write; + f.write_char(ch)?; + } + + write!(f,"{}", self.2)?; + { + use recolored::Colorize; + + match self.5 { + Some(&[]) => (), + Some(strings) => { + write!(f, " (see {})", strings.iter().map(|x| iter!["`".clear(), x.underline(), "`".clear()]).flat_join(", "))?; + } + _ => (), + } + + match self.4 { + Some("") => { + write!(f, " ({})", "default".bold().bright_red())?; + }, + Some(string) => { + write!(f, " ({}: `{}`)", "default".bold().bright_red(), string.bright_blue())?; + }, + None => (), + } + } + Ok(()) + } +} + +/// The `options` section +#[inline] fn options() -> impl Iterator +{ + iter![ + opt!(in "OPTIONS"), + + opt!("--limit", "-l" => "max children"; "Limit the number of child processes running at once."), + opt!("--auto-limit", "-m"; * 2 "Limit to max number of CPUs + 1", ""), + opt!("--unlimit", "-U"; * 3 "No limit to number of processes spawned at once"), + opt!("--completion", "-c" => "action"; "Set the default action on completion", ["ACTIONS", "COMPLETION"], "ignore"), + opt!("--silent", "-s"; * 3 "Output no messages other than that of child processes"), + + opt!("\nChild I/O"), + opt!(where "Defaults for I/O redirections of children\nThese can be overwritten individually with explicit inputs."), + opt!("--stdout" => "where"; * 2 "Set default redirect option for childrens' `stdout`", ["ACTIONS"] ,"inherit"), + opt!("--stderr" => "where"; * 2 "Set default redirect option for childrens' `stderr`", ["ACTIONS"], "inherit"), + opt!("--stdin" => "where"; * 2 "Set default redirect option for childrens' `stdin`", ["ACTIONS"], "close"), + + opt!() + ] +} + +/// The `actions` sections +#[inline] fn actions() -> impl Iterator +{ + iter![ + opt!(in "ACTIONS"), + opt!(where "Certain options have specific actions"), + + opt!("I/O"), + opt!(where "Child I/O related operations"), + opt!("inherit"; * 3 "Inherit the i/o from parent (this) process"), + opt!("close"; * 4 "Close the I/O"), + opt!("ignore"; * 3 "Don't close the stream, but don't do anything with it"), + opt!("file" => "filename"; * 2 "Use this file as input / output.\n\t\t\t\tFor input, if the file is not readable or nonexistant, it causes a panic.\n\t\t\t\tFor output, it appends to the file or uses a new one for output.\n\t\t\t\tIf this is not possible, it causes a panic.\n\t\t\t\tTo overwrite the files instead of appending, use file:clobber"), + opt!("file:clobber" => "filename"; "Only valid for outputs, overwrite the file and write to it, instead of appending"), + opt!("stderr"; * 3 "Redirect stdout to the same location as stderr.\n\t\t\t\tIf there is a cycle detected here, or it is used for anything other that stdout, there is a panic"), + opt!("stdout"; * 3 "Redirect stderr to the same location as stdout.\n\t\t\t\tIf there is a cycle detected here, or it is used for anything other that stdout, there is a panic"), + + opt!() + ] +} + +#[inline] fn completion() -> impl Iterator +{ + iter![ + opt!(in "COMPLETION"), + opt!(where "Directives for how to handle process completion"), + + opt!() + ] +} + +/// Get the sections as display iterators +pub fn sections() -> impl Iterator +{ + options() + .chain(actions()) + .chain(completion()) +}