From 798cb19865e372bc59c6da39349d8e12b58a3b4d Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Fri, 28 Jun 2024 00:05:54 +0200 Subject: [PATCH] feat(cli::args): verbosity flags for log level --- Cargo.toml | 2 +- members/libpt-cli/Cargo.toml | 6 ++ members/libpt-cli/src/args.rs | 135 ++++++++++++++++++++++++++++++++++ members/libpt-cli/src/lib.rs | 2 + 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 members/libpt-cli/src/args.rs diff --git a/Cargo.toml b/Cargo.toml index 1536913..2db2588 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,7 @@ core = [] full = ["default", "core", "log", "bintols"] log = ["dep:libpt-log"] bintols = ["dep:libpt-bintols", "log"] -cli = ["dep:libpt-cli", "core"] +cli = ["dep:libpt-cli", "core", "log"] # py = ["dep:libpt-py"] [lib] diff --git a/members/libpt-cli/Cargo.toml b/members/libpt-cli/Cargo.toml index 55c020c..66ef180 100644 --- a/members/libpt-cli/Cargo.toml +++ b/members/libpt-cli/Cargo.toml @@ -12,9 +12,15 @@ repository.workspace = true keywords.workspace = true categories.workspace = true +[features] +default = ["log"] +log = ["dep:libpt-log"] + [dependencies] +anyhow.workspace = true clap = { version = "4.5.7", features = ["derive"] } comfy-table = "7.1.1" console = "0.15.8" dialoguer = "0.11.0" indicatif = "0.17.8" +libpt-log = {workspace = true, optional = true} diff --git a/members/libpt-cli/src/args.rs b/members/libpt-cli/src/args.rs new file mode 100644 index 0000000..9eba7b2 --- /dev/null +++ b/members/libpt-cli/src/args.rs @@ -0,0 +1,135 @@ +use clap::Parser; +use libpt_log::Level; + +/// Custom help template for displaying command-line usage information +/// +/// This template modifies the default template provided by Clap to include additional information +/// and customize the layout of the help message. +/// +/// Differences from the default template: +/// - Includes the application version and author information at the end +/// +/// Apply like this: +/// ``` +/// # use libpt_cli::args::HELP_TEMPLATE; +/// use clap::Parser; +/// #[derive(Parser, Debug, Clone, PartialEq, Eq, Hash)] +/// #[command(help_template = HELP_TEMPLATE)] +/// pub struct MyArgs { +/// /// show more details +/// #[arg(short, long)] +/// pub verbose: bool, +/// } +/// ``` +/// +/// ## Example +/// +/// Don't forget to set `authors` in your `Cargo.toml`! +/// +/// ```bash +/// $ cargo run -- -h +/// about: short +/// +/// Usage: aaa [OPTIONS] +/// +/// Options: +/// -v, --verbose show more details +/// -h, --help Print help (see more with '--help') +/// -V, --version Print version +/// +/// aaa: 0.1.0 +/// Author: Christoph J. Scherr +/// +/// ``` +pub const HELP_TEMPLATE: &str = r#"{about-section} +{usage-heading} {usage} + +{all-args}{tab} + +{name}: {version} +Author: {author-with-newline} +"#; + +#[derive(Parser, Debug, Clone, PartialEq, Eq, Hash)] +#[command(help_template = HELP_TEMPLATE)] +pub struct DefaultArguments { + /// get a [tracing] log level + /// + /// set the verbosity with repeated '-q' and '-v' flags + #[command(flatten)] + verbose: VerbosityLevel, +} + +#[derive(Parser, Clone, PartialEq, Eq, Hash)] +pub struct VerbosityLevel { + /// make the output more verbose + #[arg( + long, + short = 'v', + action = clap::ArgAction::Count, + global = true, + // help = L::verbose_help(), + // long_help = L::verbose_long_help(), + )] + verbose: u8, + + /// make the output less verbose + /// + /// ( -qqq for completely quiet) + #[arg( + long, + short = 'q', + action = clap::ArgAction::Count, + global = true, + conflicts_with = "verbose", + )] + quiet: u8, +} + +impl VerbosityLevel { + /// true only if no verbose and no quiet was set (user is using defaults) + #[inline] + pub fn changed(&self) -> bool { + self.verbose != 0 || self.quiet != 0 + } + #[inline] + fn value(&self) -> i8 { + let v = Self::level_value(Level::INFO) - (self.quiet as i8) + (self.verbose as i8); + if v > Self::level_value(Level::TRACE) { + Self::level_value(Level::TRACE) + } else { + v + } + } + + /// get the [Level] for that VerbosityLevel + /// + /// [None] means that absolutely no output is wanted (completely quiet) + #[inline] + pub fn level(&self) -> Option { + Some(match self.value() { + 0 => Level::ERROR, + 1 => Level::WARN, + 2 => Level::INFO, + 3 => Level::DEBUG, + 4 => Level::TRACE, + _ => return None, + }) + } + #[inline] + fn level_value(level: Level) -> i8 { + match level { + Level::TRACE => 4, + Level::DEBUG => 3, + Level::INFO => 2, + Level::WARN => 1, + Level::ERROR => 0, + } + } +} + +impl std::fmt::Debug for VerbosityLevel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.level()) + } +} diff --git a/members/libpt-cli/src/lib.rs b/members/libpt-cli/src/lib.rs index ac0634c..f99ccb1 100644 --- a/members/libpt-cli/src/lib.rs +++ b/members/libpt-cli/src/lib.rs @@ -1,7 +1,9 @@ pub mod printing; pub mod repl; +pub mod args; pub use comfy_table; pub use console; pub use dialoguer; pub use indicatif; +pub use clap;