use std::ffi::OsString;
use clap::Parser;
use rtb_app::app::App;
pub fn parse_passthrough<T: Parser>(app: &App) -> miette::Result<T> {
parse_from_trailing::<T>(app.trailing_args())
}
fn parse_from_trailing<T: Parser>(trailing: &[OsString]) -> miette::Result<T> {
let name = <T as clap::CommandFactory>::command().get_name().to_owned();
let mut argv: Vec<OsString> = Vec::with_capacity(trailing.len() + 1);
argv.push(OsString::from(name));
argv.extend(trailing.iter().cloned());
match T::try_parse_from(argv) {
Ok(parsed) => Ok(parsed),
Err(e) => {
use clap::error::ErrorKind;
if matches!(e.kind(), ErrorKind::DisplayHelp | ErrorKind::DisplayVersion) {
print!("{e}");
std::process::exit(0);
}
Err(miette::miette!("{e}"))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, PartialEq, Eq, Parser)]
#[command(name = "demo")]
struct Demo {
#[arg(long)]
region: Option<String>,
#[arg(long)]
force: bool,
}
#[test]
fn parses_trailing_flags() {
let args =
vec![OsString::from("--region"), OsString::from("eu"), OsString::from("--force")];
let parsed: Demo = parse_from_trailing(&args).unwrap();
assert_eq!(parsed, Demo { region: Some("eu".into()), force: true });
}
#[test]
fn empty_trailing_yields_defaults() {
let parsed: Demo = parse_from_trailing(&[]).unwrap();
assert_eq!(parsed, Demo { region: None, force: false });
}
#[test]
fn unknown_flag_is_an_error_not_a_panic() {
let args = vec![OsString::from("--nope")];
assert!(parse_from_trailing::<Demo>(&args).is_err());
}
}