travisstaloch/clarp
A command line argument parsing library in zig
Complexity, bloat and long compile times.
Derive command line parsers from union and struct types. Provides nested, context aware usage text similar to the zig compiler. Works with existing data structures you may not control.
field types
clarp_options.fields.<field_name>.utf8
help / usage
parse_options.err_writer
(default std.io.null_writer
)std.debug.print("{help}", .{parse_result});
diagnostics which clearly point to parsing errors
easily dump parse results
std.debug.print("{}", .{parse_result});
derive short names by setting clarp_options.derive_short_names
and override them with FieldOption.short
apply clarp_options
to types you don't control with parseWithOptions()
rename long names with FieldOption.long
long and short options can be parsed with any of these forms:
Long | Short |
---|---|
--foo value |
-f value |
--foo=value |
-f=value |
--foovalue |
-fvalue |
Union types create alternative commands. Commands match field names exactly.
Struct types create sequences of options. Options match field names with leading dashes such as --text_color
for field text_color
. Named options can be parsed out of order. Unnamed, positional parsing may be enabled by setting clarp_options.fields.<field_name>.positional
.
Tuple types create unnamed sequences and are parsed strictly by position.
Bool fields create 'flags' and may be specified as --flag
or true
/false
when unnamed. They are always optional and default to false.
Slice fields require an allocator and consume input until an argument is found which starts with '-' or end of arguments. clarp_options.end_marker
may also be used to mark the end of field's arguments. This may be necessary with unnamed, positional fields. An Allocator can be passed as ParseOptions.allocator
.
This package is developed with zig master branch. There are also tagged releases for previous compiler versions.
You can find many examples in the tests.
# 0.12.0
$ zig fetch --save https://github.com/travisstaloch/clarp/archive/refs/tags/0.12.0.tar.gz
# 0.13 / Nightly
$ zig fetch --save https://github.com/travisstaloch/clarp/archive/<commit hash>.tar.gz
This will add the following
// build.zig.zon
.dependencies = .{
.clarp = .{
.url = "https://github.com/travisstaloch/clarp/archive/<commit-hash>.tar.gz",
.hash = ...,
},
},
// build.zig
pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{...});
const clarp = b.dependency("clarp", .{}).module("clarp");
exe.root_module.addImport("clarp", clarp);
}
This program creates a parser and dumps the result to stderr. It is available here and can be run with $ zig build test-demo -- args
.
const std = @import("std");
const clarp = @import("clarp");
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
const ArgParser = clarp.Parser(union(enum) {
cmd1: struct {
foo: []const u8,
pub const clarp_options = clarp.Options(@This()){
.fields = .{
.foo = .{ .desc = "Foo description." },
},
};
},
cmd2: struct { enum { a, b } = .a },
pub const clarp_options = clarp.Options(@This()){
.fields = .{
.cmd1 = .{ .desc = "Cmd1 description.", .short = "c1" },
.cmd2 = .{ .desc = "Cmd2 description.", .short = "c2" },
},
};
}, .{});
const args = try std.process.argsAlloc(allocator);
const parsed = ArgParser.parse(args, .{
.err_writer = std.io.getStdErr().writer().any(),
}) catch |e| switch (e) {
error.HelpShown => return,
else => return e,
};
std.debug.print("{}\n", .{parsed});
// access parse result
switch (parsed.result) {
.cmd1 => {},
.cmd2 => {},
}
}
When a struct or union contains a pub const clarp_options
declaration, it changes parsing behavior. Nested structs and unions may declare their own clarp_options
.
Runtime parsing options. The second argument to clarp.Parser(T).parse()
.
Comptime global parsing options. The second argument to clarp.Parser()
.
By default, if an arg is help
, --help
or -h
context aware usage is displayed. You may change the help flags by passing an enum type for ParserOptions.help_type
.
$ zig-out/bin/testexe help
Usage: testexe [command]
Commands:
cmd1, c1 Cmd1 description.
cmd2, c2 Cmd2 description.
General Options:
help, --help, -h Print command specific usage.
Notice how this message is derived from the union(enum)
passed to clarp.Parser()
above and that its clarp_options
declaration affects the output, adding the c1
and c2
shorts and descriptions.
$ zig-out/bin/testexe cmd1 help
Usage: testexe cmd1 [options]
Cmd1 description.
Options:
--foo: string Foo description.
General Options:
help, --help, -h Print command specific usage.
Here are some results from the ArgParser
we defined above in Full Example.
$ zig-out/bin/testexe cmd1 --foo 'opt1 value'
cmd1:
foo: "opt1 value"
$ zig-out/bin/testexe c1 --foo 'opt1 value'
cmd1:
foo: "opt1 value"
$ zig-out/bin/testexe c2 b
cmd2:
0: b
$ zig-out/bin/testexe foo
Usage: testexe [command]
Commands:
cmd1, c1 Cmd1 description.
cmd2, c2 Cmd2 description.
General Options:
help, --help, -h Print command specific usage.
error at argument 1: foo
^~~
error: UnknownCommand
#... stack trace omitted