# 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 |
| |
| 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.
```no_run
use aopt::prelude::*;
use std::ops::Deref;
fn main() -> Result<(), Box<dyn std::error::Error>> {
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, mut val: ctx::Value<String>| {
let depth: &i64 = set["--depth"].val()?;
println!("Adding location({}) with depth({})", val.deref(), depth);
Ok(Some((val.take(), *depth)))
},
)?;
parser.add_opt("destination=p!@-0")?.on(
|_: &mut ASet, _: &mut ASer, mut val: ctx::Value<String>| {
println!("Save destination location({})", val.deref());
Ok(Some(val.take()))
},
)?;
parser.add_opt("main=m")?.on(
|set: &mut ASet, _: &mut ASer, mut val: ctx::Value<String>| {
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.deref(),
dest
);
}
Ok(Some(val.take()))
},
)?;
parser.parse_env()?.unwrap();
Ok(())
}
```
- Using [`getopt!`](crate::getopt) parsing multiple sub command.
```no_run
use aopt::prelude::*;
use aopt::Error;
use std::ops::Deref;
fn main() -> Result<(), Box<dyn std::error::Error>> {
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::<String>())?
.add_alias("-s")
.set_value(String::from("lib.rs"));
list.add_opt("main=m")?
.fallback(|set: &mut ASet, _: &mut ASer| {
println!(
"invoke list command: debug={:?}, force={:?}, local-only={:?}, source={:?}",
set["-debug"].val::<bool>()?,
set["-force"].val::<bool>()?,
set["-local-only"].val::<bool>()?,
set["-source"].val::<String>()?,
);
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| {
println!(
"invoke update command: debug={:?}, force={:?}, source={:?}",
set["-debug"].val::<bool>()?,
set["-force"].val::<bool>()?,
set["-source"].val::<String>()?,
);
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, mut val: ctx::Value<String>| {
if val.deref() == "software" {
println!(
"invoke install command: debug={:?}, override={:?}, source={:?}",
set["-debug"].val::<bool>()?,
set["-/override"].val::<bool>()?,
set["-source"].val::<String>()?,
);
Ok(Some(val.take()))
} 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=AStr("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