# aopt A flexible and typed getopt like command line framwork for rust. ## Features - Option support - Prefixed option support, such as `-f`, `--flag`, `-flag` or `--/flag`. - Option value support, such as `-f 42`, `--flag 3.14` or `--flag=foo`. - Multiple style option support, such as `-f 42`, `-f=42` or `-f42`. - Combing style support, such as `-abc` is same as `-a` `-b` `-c`. - Positional arguments support, see [`Index`](crate::opt::Index). - Special option `-` and `--` support, see [`Stop`](crate::value::Stop) and [`Stdin`](std::io::Stdin). - Type support, you can validator the value of option during parsing. See the built-in option type [`AOpt`](crate::opt::AOpt) - Non UTF8 arguments support - Callback support Can set callback which will called during parsing, see [`Parser`](crate::parser::Parser) and [`Invoker`](crate::ctx::Invoker). - Value support By default aopt will saving the raw value and parsed value in [`ValStorer`](crate::value::ValStorer). - Policy support - [`DelayPolicy`](crate::parser::DelayPolicy) process positional arguments before any other option. - [`FwdPolicy`](crate::parser::FwdPolicy) process options before positional arguments. - [`PrePolicy`](crate::parser::PrePolicy) can help you process the options partial. - Derive support - Checkout [`cote`](https://docs.rs/cote/latest/cote/index.html) crate for derive support and help message generate. ## Setup `cargo add aopt` ### `sync` feature If you want the utils of current crate implement `Send` and `Sync`, you can enable `sync` feature. ## Simple flow chart ```txt +---------------------------------------+ | Policy | | | +--------------+ | +-----------+ +------------+ | +-------------+ | | | | | | | | Invoke | | | Arguments +---->| | Checker | | Process |<----+----------------+ Invoker | | | | | | | | | the callback | | +--------------+ | +---^-------+ ++-----^-----+ | +-------------+ | | | | | | | | | | +------+--------------+-----+-----------+ | | | | | | | Save the values |Process the arguments | | | | | | Check the options | | | | | | | | | +----v-----+-----------+ | | | +---------+ Option Set | | | +----------------------+ ``` ## Example - Using [`AFwdParser`](crate::ext::AFwdParser) parsing process the command line. ```rust ,no_run use aopt::prelude::*; use std::ops::Deref; fn main() -> Result<(), Box> { let mut parser = AFwdParser::default(); parser.validator_mut().add_prefix("+"); parser.add_opt("--depth=i")?.set_value_t(0i64); // int option parser.add_opt("-/r=b")?; // boolean flag parser .add_opt("--source=s!")? // ! means the option is force required .add_alias("+S") .on( |set: &mut ASet, _: &mut ASer, ctx: &Ctx| { let val = ctx.value::()?; let depth: &i64 = set["--depth"].val()?; println!("Adding location({}) with depth({})", val, depth); Ok(Some((val, *depth))) }, )?; parser.add_opt("destination=p!@-0")?.on( |_: &mut ASet, _: &mut ASer, ctx: &Ctx| { let val = ctx.value::()?; println!("Save destination location({})", val); Ok(Some(val)) }, )?; parser.add_opt("main=m")?.on( |set: &mut ASet, _: &mut ASer, ctx: &Ctx| { let val = ctx.value::()?; let src = set["--source"].vals::<(String, i64)>()?; let dest: &String = set["destination"].val()?; for (item, depth) in src { println!( "Application {} will copy location({item}, depth={depth}) to destination({})", val, dest ); } Ok(Some(val)) }, )?; parser.parse_env()?.unwrap(); Ok(()) } ``` * `app.exe --depth=98 +S github --depth=42 +S gitlab gitcode` output ```txt Adding location(github) with depth(98) Adding location(gitlab) with depth(42) Save destination location(gitcode) Application target\debug\example.exe will copy location(github, depth=98) to destination(gitcode) Application target\debug\example.exe will copy location(gitlab, depth=42) to destination(gitcode) ``` - Using [`getopt!`](crate::getopt) parsing multiple sub command. ```rust ,no_run use aopt::prelude::*; use aopt::Error; use std::ops::Deref; fn main() -> Result<(), Box> { let mut list = AFwdParser::default(); let mut update = AFwdParser::default(); let mut install = AFwdParser::default(); list.add_opt("list=c")?; list.add_opt("ls=c")?; list.add_opt("-debug=b")?; list.add_opt("-force=b")?.add_alias("-f"); list.add_opt("-local-only=b")?.add_alias("-l"); list.add_opt("-source".infer::())? .add_alias("-s") .set_value(String::from("lib.rs")); list.add_opt("main=m")? .fallback(|set: &mut ASet, _: &mut ASer, _: &Ctx| { println!( "invoke list command: debug={:?}, force={:?}, local-only={:?}, source={:?}", set["-debug"].val::()?, set["-force"].val::()?, set["-local-only"].val::()?, set["-source"].val::()?, ); Ok(None::<()>) })?; update.add_opt("update=c")?; update.add_opt("up=c")?; update.add_opt("-debug=b")?; update.add_opt("-force=b")?.add_alias("-f"); update.add_opt("-source=s")?.add_alias("-s"); update .add_opt("main=m")? .on(|set: &mut ASet, _: &mut ASer, _: &Ctx| { println!( "invoke update command: debug={:?}, force={:?}, source={:?}", set["-debug"].val::()?, set["-force"].val::()?, set["-source"].val::()?, ); Ok(Some(true)) })?; install.add_opt("install=c")?; install.add_opt("in=c")?; install.add_opt("-debug=b")?; install.add_opt("-/override=b")?.add_alias("-/o"); install.add_opt("-source=s")?.add_alias("-s"); install.add_opt("name=p!@2")?.on( |set: &mut ASet, _: &mut ASer, ctx: &Ctx| { let val = ctx.value::()?; if val == "software" { println!( "invoke install command: debug={:?}, override={:?}, source={:?}", set["-debug"].val::()?, set["-/override"].val::()?, set["-source"].val::()?, ); Ok(Some(val)) } else { Err(aopt::raise_error!("command not matched")) } }, )?; getopt!(Args::from_env(), &mut list, &mut update, &mut install)?; Ok(()) } ``` * `app.exe ls -debug` output invoke list command: debug=true, force=false, local-only=false, source="lib.rs" * `app.exe update -force -source=crates.io` output invoke update command: debug=false, force=true, source="crates.io" * `app.exe in software -/o -s crates.io` output invoke install command: debug=false, override=true, source="crates.io" * `app.exe in aopt` output Error: command not matched ## More - simple-find-file A simple file search tools, try it using [`cargo install --path simple-find-file`](https://github.com/araraloren/aopt/tree/main/simple-find-file). - snowball-follow Get the follow count of stock in `xueqiu.com`, try it using [`cargo install --path snowball-follow`](https://github.com/araraloren/aopt/tree/main/snowball-follow) - index constituent Search and list the constituent of index, try it using [`cargo install --path index-constituent`](https://github.com/araraloren/aopt/tree/main/index-constituent) ## Release log Follow the [link](https://github.com/araraloren/aopt/blob/main/aopt/Release.md). ## LICENSE MPL-2.0