A small, simple and sweet argument parser for Rust
Sap is a minimal, zero-dependency Unix command-line argument parser for Rust. It provides full control over argument parsing with an iterator-based API that handles GNU-style options while maintaining simplicity and flexibility.
- GNU-style option parsing: Support for short (
-a
), long (--verbose
), and combined options (-abc
) - Flexible value handling: Options with values via
--name=value
or separate arguments - POSIX compliance: Handle
--
separator and-
(stdin) arguments correctly - Zero dependencies: Pure Rust implementation with no external crates
- Iterator-based: Works with any
Iterator<Item = Into<String>>
for maximum flexibility - Comprehensive error handling: Descriptive error messages for invalid input
Add Sap to your Cargo.toml
:
[dependencies]
sap = "0.0.5"
use sap::{Parser, Argument};
// Parse from command line arguments
let mut parser = Parser::from_env().unwrap();
while let Some(arg) = parser.forward().unwrap() {
match arg {
Argument::Short('v') => println!("Verbose mode enabled"),
Argument::Long("help") => println!("Help requested"),
Argument::Long("file") => {
if let Some(filename) = parser.value() {
println!("Processing file: {}", filename);
}
}
Argument::Value(val) => println!("Positional argument: {}", val),
Argument::Stdio => println!("Reading from stdin"),
}
}
use sap::{Parser, Argument};
// Parse from any iterator of string-like values
let mut parser = Parser::from_arbitrary(["myprogram", "-v", "--file=input.txt"]).unwrap();
while let Some(arg) = parser.forward().unwrap() {
match arg {
Argument::Short('v') => println!("Verbose mode enabled"),
Argument::Long("file") => {
if let Some(filename) = parser.value() {
println!("Processing file: {}", filename);
}
}
Argument::Value(val) => println!("Positional argument: {}", val),
_ => {}
}
}
Sap recognizes four types of arguments:
Argument::Short(char)
- Short options like-v
,-x
, and combined ones like-abc
Argument::Long(&str)
- Long options like--verbose
,--file
, including values like--file=foo.txt
Argument::Value(Cow<str>)
- Positional arguments and operandsArgument::Stdio
- The special-
argument (stdin/stdout)
Here's a more comprehensive example showing a typical CLI application:
use sap::{Parser, Argument, Result};
fn main() -> Result<()> {
let mut parser = Parser::from_env()?;
let mut verbose = false;
let mut output_file = None;
let mut input_files = Vec::new();
while let Some(arg) = parser.forward()? {
match arg {
Argument::Short('v') | Argument::Long("verbose") => {
verbose = true;
}
Argument::Short('h') | Argument::Long("help") => {
print_help(parser.name());
return Ok(());
}
Argument::Short('o'<
8567
/span>) | Argument::Long("output") => {
output_file = parser.value();
if output_file.is_none() {
eprintln!("Error: --output requires a value");
std::process::exit(1);
}
}
Argument::Value(file) => {
input_files.push(file.into_owned());
}
Argument::Stdio => {
input_files.push("-".to_string());
}
unknown => {
eprintln!("Error: {}", unknown.into_error(parser.value()));
std::process::exit(1);
}
}
}
if verbose {
println!("Verbose mode enabled");
if let Some(ref output) = output_file {
println!("Output file: {}", output);
}
println!("Input files: {:?}", input_files);
}
Ok(())
}
fn print_help(program_name: &str) {
println!("Usage: {} [OPTIONS] [FILES...]", program_name);
println!("Options:");
println!(" -v, --verbose Enable verbose output");
println!(" -o, --output Specify output file");
println!(" -h, --help Show this help message");
}
For comprehensive examples of Sap in action, check out puppyutils - a collection of Unix utilities reimplemented in Rust. Sap was originally created as the argument parser for this project, so you'll find extensive real-world usage patterns.
Special thanks to Esther who wrote the original parser design for this library <3
This project is licensed under the Apache-2.0 License. For more information, please see the LICENSE file.