use bpaf::*;
mod boilerplate {
use super::*;
pub trait ExtraParsers<T> {
fn my_last(self) -> ParseLast<T>;
}
impl<T> Parser<T> for ParseLast<T> {
fn eval(&self, args: &mut State) -> Result<T, Error> {
self.inner.eval(args)
}
fn meta(&self) -> Meta {
self.inner.meta()
}
}
pub struct ParseLast<T> {
inner: Box<dyn Parser<T>>,
}
impl<T, P> ExtraParsers<T> for P
where
P: Parser<T> + 'static,
T: 'static,
{
fn my_last(self) -> ParseLast<T> {
let p = self
.some("need to specify at least once")
.map(|mut xs| xs.pop().unwrap());
ParseLast { inner: p.boxed() }
}
}
}
pub mod shared {
use super::boilerplate::*;
use bpaf::*;
#[derive(Debug, Clone, Copy, Bpaf)]
pub enum Verbosity {
#[bpaf(short, long)]
Warn,
#[bpaf(short, long)]
Quiet,
#[bpaf(short, long)]
Status,
}
pub fn parse_verbosity() -> impl Parser<Verbosity> {
verbosity().my_last().fallback(Verbosity::Status)
}
pub fn parse_binary() -> impl Parser<bool> {
#[derive(Debug, Clone, Copy, Bpaf, Eq, PartialEq)]
enum Mode {
#[bpaf(short, long)]
Binary,
#[bpaf(short, long)]
Text,
}
mode()
.last()
.fallback(Mode::Text)
.debug_fallback()
.map(|mode| mode == Mode::Binary)
}
}
mod arch {
use bpaf::*;
#[derive(Debug, Clone, Bpaf)]
#[bpaf(command)]
pub struct Arch;
}
mod b2sum {
use super::shared::*;
use bpaf::*;
use std::path::PathBuf;
#[derive(Debug, Clone, Bpaf)]
#[bpaf(command("b2sum"))]
pub struct B2Sum {
#[bpaf(external(parse_binary))]
pub binary: bool,
#[bpaf(short, long)]
pub check: bool,
pub tag: bool,
#[bpaf(external(parse_verbosity))]
pub check_output: Verbosity,
pub strict: bool,
#[bpaf(positional("FILE"))]
pub files: Vec<PathBuf>,
}
}
mod base32 {
use bpaf::*;
use std::path::PathBuf;
fn non_zero(val: Option<usize>) -> Option<usize> {
val.and_then(|v| (v > 0).then_some(v))
}
#[derive(Debug, Clone, Bpaf)]
#[bpaf(command)]
pub struct Base32 {
#[bpaf(long, short)]
pub decode: bool,
#[bpaf(long, short)]
pub ignore_garbage: bool,
#[bpaf(
long,
short,
argument("COLS"),
optional,
map(non_zero),
fallback(Some(76)),
debug_fallback
)]
pub wrap: Option<usize>,
#[bpaf(positional("FILE"))]
pub file: Option<PathBuf>,
}
}
mod basename {
use bpaf::*;
#[derive(Debug, Clone, Bpaf)]
#[bpaf(command)]
pub struct Basename {
#[bpaf(short('a'), long)]
pub multiple: bool,
#[bpaf(short, long, argument("SUFFIX"), optional)]
pub suffix: Option<String>,
#[bpaf(short, long)]
pub zero: bool,
#[bpaf(positional("NAME"), many)]
pub names: Vec<String>,
}
pub fn parse_basename() -> impl Parser<Basename> {
basename().map(|mut b| {
if b.suffix.is_some() {
b.multiple = true;
}
b
})
}
}
mod cat {
use std::path::PathBuf;
use bpaf::*;
#[derive(Debug, Clone, Bpaf)]
struct Extra {
#[bpaf(short('A'), long)]
show_all: bool,
#[bpaf(short('b'), long)]
number_nonblank: bool,
#[bpaf(short('e'))]
show_non_printing_ends: bool,
}
#[derive(Debug, Clone, Bpaf)]
#[bpaf(fallback(NumberingMode::None))]
pub enum NumberingMode {
#[bpaf(hide)]
None,
#[bpaf(short('b'), long("number-nonblank"))]
NonEmpty,
#[bpaf(short('n'), long("number"))]
All,
}
#[derive(Debug, Clone, Bpaf)]
pub struct Cat {
#[bpaf(short('T'), long)]
pub show_tabs: bool,
#[bpaf(short('E'))]
pub show_ends: bool,
#[bpaf(short('n'), long("number"))]
show_nonprinting: bool,
#[bpaf(external(numbering_mode))]
pub number: NumberingMode,
#[bpaf(short('s'), long)]
pub squeeze_blank: bool,
#[bpaf(positional("FILE"), many)]
pub files: Vec<PathBuf>,
}
pub fn parse_cat() -> impl Parser<Cat> {
construct!(extra(), cat())
.map(|(extra, mut cat)| {
if extra.show_all {
cat.show_tabs = true;
cat.show_ends = true;
cat.show_nonprinting = true;
}
if extra.show_non_printing_ends {
cat.show_nonprinting = true;
cat.show_ends = true;
}
if extra.number_nonblank {
cat.number = NumberingMode::NonEmpty;
}
cat
})
.to_options()
.command("cat")
}
}
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub enum Options {
Arch(#[bpaf(external(arch::arch))] arch::Arch),
B2Sum(#[bpaf(external(b2sum::b2_sum))] b2sum::B2Sum),
Base32(#[bpaf(external(base32::base32))] base32::Base32),
Basename(#[bpaf(external(basename::parse_basename))] basename::Basename),
Cat(#[bpaf(external(cat::parse_cat))] cat::Cat),
}
fn main() {
let parser = options();
println!("{:?}", parser.run());
}