Skip to main content

nanoargs/
lib.rs

1//! # nanoargs
2//!
3//! A minimal, zero-dependency argument parser for Rust CLI applications.
4//! Part of the [nano crate family](https://crates.io/search?q=nano).
5//!
6//! nanoargs gives you flags, options, positional arguments, subcommands,
7//! environment variable fallbacks, typed parsing, auto-generated help text,
8//! version handling, and optional colored help — all without pulling in a single
9//! transitive dependency.
10//!
11//! ## Quick Start
12//!
13//! ```rust
14//! use nanoargs::{ArgBuilder, Flag, Opt, Pos};
15//!
16//! let parser = ArgBuilder::new()
17//!     .name("myapp")
18//!     .description("A sample CLI tool")
19//!     .flag(Flag::new("verbose").desc("Enable verbose output").short('v'))
20//!     .option(Opt::new("output").placeholder("FILE").desc("Output file path").short('o'))
21//!     .positional(Pos::new("input").desc("Input file").required())
22//!     .build()
23//!     .unwrap();
24//!
25//! // Parse from a Vec<String>:
26//! // let result = parser.parse(args)?;
27//!
28//! // Or parse from std::env::args():
29//! // let result = parser.parse_env()?;
30//! ```
31//!
32//! ## Features
33//!
34//! | Feature | Description |
35//! |---------|-------------|
36//! | Flags | Boolean switches like `--verbose` / `-v` |
37//! | Options | Key-value pairs like `--output file.txt` or `-o=file.txt` |
38//! | Positionals | Ordered arguments like `<input>` (required) or `[extra]` (optional) |
39//! | Subcommands | Nested command trees with independent argument sets |
40//! | Short flag clusters | Combined flags like `-abc` and `-aboval` |
41//! | Typed parsing | `get_option_or_default::<T>()`, `get_option_required::<T>()`, and more |
42//! | Env var fallback | `.env("MY_VAR")` on options, with CLI > env > default precedence |
43//! | Multi-value options | `.multi()` to collect repeated `--tag a --tag b` into a `Vec` |
44//! | Hidden arguments | `.hidden()` to keep flags/options out of help text |
45//! | Default values | `.default("value")` for optional options |
46//! | Required arguments | `.required()` on options and positionals |
47//! | Auto help | Built-in `-h` / `--help` with column-aligned output |
48//! | Version flag | `.version("1.0.0")` enables `--version` / `-V` |
49//! | Colored output | Opt-in `color` feature for ANSI-styled help and errors via [`nanocolor`](https://crates.io/crates/nanocolor) |
50//! | Shell completions | Generate completion scripts for Bash, Zsh, Fish, and PowerShell via [`ArgParser::generate_completions`] |
51//!
52//! ## Builder API
53//!
54//! All argument definitions flow through [`ArgBuilder`] using a chainable builder pattern:
55//!
56//! ```rust
57//! # use nanoargs::{ArgBuilder, Flag, Opt, Pos};
58//! let parser = ArgBuilder::new()
59//!     .name("greet")
60//!     .version("1.0.0")
61//!     .flag(Flag::new("loud").desc("Shout the greeting").short('l'))
62//!     .option(Opt::new("name").placeholder("NAME").desc("Who to greet").short('n').required())
63//!     .option(Opt::new("times").placeholder("N").desc("Repeat count").default("1"))
64//!     .positional(Pos::new("extra").desc("Extra words"))
65//!     .build()
66//!     .unwrap();
67//! ```
68//!
69//! Construct argument definitions using [`Flag`], [`Opt`], and [`Pos`], chain
70//! modifiers like `.required()`, `.default()`, `.env()`, `.multi()`, `.hidden()`,
71//! then pass them directly to the builder methods.
72//!
73//! ## Parsing and Results
74//!
75//! ```rust,no_run
76//! # use nanoargs::ArgBuilder;
77//! # let parser = ArgBuilder::new().build().unwrap();
78//! let result = parser.parse_env().unwrap();
79//!
80//! // Flags return bool
81//! let verbose = result.get_flag("verbose");
82//!
83//! // Options return Option<&str>
84//! let output = result.get_option("output");
85//!
86//! // Typed parsing with default (returns Result — Err on bad parse)
87//! let count: u32 = result.get_option_or_default("times", 1).unwrap();
88//!
89//! // Or require it (returns Result for ? operator)
90//! // let count: u32 = result.get_option_required("times")?;
91//!
92//! // Lazy default via closure
93//! // let count: u32 = result.get_option_or("times", || expensive_default())?;
94//!
95//! // Low-level typed parse: Option<Result<T, Err>>
96//! let parsed: Option<Result<u32, _>> = result.get_option_parsed("times");
97//!
98//! // Multi-value options return &[String]
99//! let tags = result.get_option_values("tags");
100//!
101//! // Typed multi-values with fallback
102//! // let tags: Vec<String> = result.get_option_values_or_default("tags", vec![])?;
103//!
104//! // Positionals in order
105//! let positionals = result.get_positionals();
106//!
107//! // Subcommand access
108//! if let Some(name) = result.subcommand() {
109//!     let sub = result.subcommand_result().unwrap();
110//! }
111//! ```
112//!
113//! ## Subcommands
114//!
115//! ```rust
116//! # use nanoargs::{ArgBuilder, Flag, Pos};
117//! let sub = ArgBuilder::new()
118//!     .positional(Pos::new("file").desc("File to add").required())
119//!     .build().unwrap();
120//!
121//! let parser = ArgBuilder::new()
122//!     .name("git-lite")
123//!     .flag(Flag::new("verbose").desc("Verbose output").short('v'))
124//!     .subcommand("add", "Stage files", sub)
125//!     .build().unwrap();
126//! ```
127//!
128//! Global flags are parsed before the subcommand name. Everything after the
129//! subcommand name is delegated to the subcommand's parser.
130//!
131//! ## Error Handling
132//!
133//! Parsing returns `Result<ParseResult, ParseError>`. The [`ParseError`] variants
134//! cover missing required arguments, missing option values, unknown arguments,
135//! invalid formats, unknown subcommands, and the special `HelpRequested` /
136//! `VersionRequested` cases (which carry the formatted text).
137//!
138//! ## Colored Output
139//!
140//! Enable the `color` Cargo feature for ANSI-styled help text and error messages:
141//!
142//! ```toml
143//! [dependencies]
144//! nanoargs = { version = "0.1", features = ["color"] }
145//! ```
146//!
147//! Colors are applied automatically and suppressed when `NO_COLOR` is set or
148//! stdout is not a TTY (handled by `nanocolor`).
149//!
150//! ## Schema-Free Parsing (Escape Hatch)
151//!
152//! [`parse_loose`] is a convenience escape hatch for throwaway scripts where
153//! defining a full schema is overkill. **It is not the recommended way to
154//! parse arguments** — prefer [`ArgBuilder`] for anything user-facing.
155//!
156//! ```rust,no_run
157//! let result = nanoargs::parse_loose().unwrap();
158//! let verbose = result.get_flag("verbose");
159//! let output = result.get_option("output");
160//! let positionals = result.get_positionals();
161//! ```
162//!
163//! `parse_loose` uses a heuristic (if the next token doesn't start with `-`,
164//! it's consumed as a value), which means `--output -v` silently treats
165//! `--output` as a flag. It also provides no help text, no required-argument
166//! validation, and no typed parsing. For anything beyond a quick script, use
167//! [`ArgBuilder`].
168
169mod builders;
170mod completions;
171mod free;
172mod help;
173mod macros;
174mod parser;
175mod result;
176mod types;
177pub mod validators;
178
179pub use builders::{ArgBuilder, Flag, Opt, Pos};
180pub use completions::Shell;
181pub use free::parse_loose;
182pub use parser::ArgParser;
183pub use result::{OptionError, ParseResult, ParseResultBuilder};
184pub use types::{ConflictDef, FlagDef, GroupDef, OptionDef, ParseError, PositionalDef, SubcommandDef};
185pub use validators::{max_length, min_length, non_empty, one_of, path_exists, range, Validator};
186
187#[cfg(test)]
188mod tests;