Backlog/lib/zargs/README.md

280 lines
7.3 KiB
Markdown

# zargs - Zero-overhead Argument Parser for Zig
A type-safe, compile-time command-line argument parser for Zig that uses struct introspection to automatically generate parsers.
## Features
-**Type-safe**: Arguments are defined as struct fields with compile-time type checking
-**Zero runtime overhead**: All metadata extraction happens at compile time
-**Flexible syntax**: Supports `--flag`, `--flag=value`, `-f`, `-f value`, and multi-flags (`-abc`)
-**Rich types**: Bool, integers, strings, enums, lists, and optional types
-**Automatic help**: Generates professional help text from struct metadata
-**Multi-module**: Multiple modules can register arguments with collision detection
-**Memory safe**: No leaks, proper cleanup with `defer`
-**Zero dependencies**: Pure Zig, no external dependencies
## Quick Start
```zig
const std = @import("std");
const zargs = @import("zargs");
const Config = struct {
verbose: bool = false,
output: []const u8 = "output.txt",
count: u32 = 10,
pub const meta = .{
.verbose = .{ .short = 'v', .help = "Enable verbose output" },
.output = .{ .short = 'o', .help = "Output file path" },
.count = .{ .short = 'c', .help = "Number of items" },
};
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
const config = zargs.parse(Config, allocator, args) catch |err| {
if (err == error.HelpRequested) return;
return err;
};
std.debug.print("Output: {s}\n", .{config.output});
}
```
## Usage
### Define Your Configuration
```zig
const Config = struct {
// Boolean flag (default: false)
verbose: bool = false,
// String argument (default: "output.txt")
output: []const u8 = "output.txt",
// Integer argument (default: 10)
count: u32 = 10,
// Enum argument (default: .balanced)
mode: enum { fast, slow, balanced } = .balanced,
// Optional argument (default: null)
name: ?[]const u8 = null,
// String list (can be repeated or comma-separated)
files: []const []const u8 = &[_][]const u8{},
// Add metadata for help text and short flags
pub const meta = .{
.verbose = .{
.short = 'v',
.help = "Enable verbose output",
},
.output = .{
.short = 'o',
.help = "Output file path",
},
.count = .{
.short = 'c',
.help = "Number of items to process",
},
.mode = .{
.short = 'm',
.help = "Processing mode",
},
.name = .{
.help = "Optional name parameter",
},
.files = .{
.short = 'f',
.help = "Input files (can be repeated)",
},
};
};
```
### Parse Arguments
```zig
// Simple parsing (shows help automatically)
const config = try zargs.parse(Config, allocator, args);
// Advanced: manual registry for multi-module apps
var registry = zargs.ArgumentRegistry.init(allocator);
defer registry.deinit();
try registry.registerMetadata(Module1Config, "Module1");
try registry.registerMetadata(Module2Config, "Module2");
try zargs.parseArgv(&registry, args);
const mod1 = try zargs.populateStruct(Module1Config, &registry, allocator);
const mod2 = try zargs.populateStruct(Module2Config, &registry, allocator);
```
## Command-Line Syntax
### Boolean Flags
```bash
./program --verbose # Sets verbose = true
./program -v # Short form
./program -vdq # Multi-flag (sets verbose, debug, quiet)
```
### String Arguments
```bash
./program --output=file.txt # With equals
./program --output file.txt # Space-separated
./program -o file.txt # Short form
```
### Integer Arguments
```bash
./program --count=42
./program --count 0xFF # Hex supported
./program --count 0b1010 # Binary supported
```
### Enum Arguments
```bash
./program --mode=fast
./program --mode slow
```
### List Arguments
```bash
./program --files=a.txt,b.txt,c.txt # Comma-separated
./program --files=a.txt --files=b.txt # Repeated (both work!)
```
### Help
```bash
./program --help
./program -h
```
## Supported Types
- **Booleans**: `bool`
- **Integers**: `u8`, `u16`, `u32`, `u64`, `i8`, `i16`, `i32`, `i64`
- **Strings**: `[]const u8`
- **Enums**: Any Zig enum type
- **Lists**: `[]const []const u8` (string lists)
- **Optionals**: `?T` for any supported type `T`
## Help Text Generation
zargs automatically generates professional help text:
```
Usage: program [OPTIONS]
Options:
-h, --help Show this help message
-c, --count <NUM> Number of items to process
-m, --mode <CHOICE> Processing mode
-o, --output <VALUE> Output file path [default: output.txt]
-v, --verbose Enable verbose output [default: false]
```
## Advanced Features
### Collision Detection
When multiple modules register the same argument name:
- **Compatible** (same type): Allowed, warns
- **Incompatible** (different types): Compile error
```zig
// Both modules can register --verbose (bool)
try registry.registerMetadata(Module1, "Module1"); // has verbose: bool
try registry.registerMetadata(Module2, "Module2"); // has verbose: bool - OK!
// This would error at compile time:
// Module1 has verbose: bool
// Module2 has verbose: u32 - COMPILE ERROR!
```
### Custom Metadata
```zig
pub const meta = .{
.field_name = .{
.short = 'x', // Short flag (optional)
.help = "Description", // Help text (optional)
.required = true, // Override default requirement (optional)
},
};
```
## Examples
See the `examples/` directory for complete examples:
- `simple.zig` - Basic single-struct usage
- `multi_module.zig` - Multiple modules with shared registry
## Building
Requires Zig 0.14 or later (tested with Zig 0.15.2).
```bash
zig build
zig build test
```
## API Reference
### Main Functions
- `parse(T, allocator, argv)` - Parse arguments into struct T
- `parseWithRegistry(T, registry, allocator, argv)` - Parse with existing registry
### Core Types
- `ArgumentRegistry` - Central registry for argument metadata
- `ArgumentType` - Enum of supported argument types
- `ParsedValue` - Tagged union of parsed values
- `ArgumentMetadata` - Complete metadata for an argument
### Utilities
- `generateHelpText(registry, allocator, program_name)` - Generate help text
- `parseArgv(registry, argv)` - Parse argv into registry
- `populateStruct(T, registry, allocator)` - Populate struct from parsed values
## Design Philosophy
zargs is designed for **game engines and plugin architectures** where:
- Arguments are scattered across many modules
- Not all modules may load in every run
- Comprehensive documentation is still needed
- Type safety is non-negotiable
## Version
Current version: `0.1.0-dev`
## License
[Add your license here]
## Contributing
Contributions welcome! Please ensure:
- All tests pass (`zig build test`)
- No memory leaks (tests check with `std.testing.allocator`)
- Code follows existing style
- New features have tests and documentation
## Acknowledgments
Built with ❤️ in Zig, following best practices from the Zig standard library.