ZIG-CLAP(1)

NAME

zig-clapCommand line argument parsing library

SYNOPSIS

$https://github.com/Hejsil/zig-clap/releases

INFO

1.5k stars
96 forks
0 views

DESCRIPTION

Command line argument parsing library

README

zig-clap

A simple and easy to use command line argument parser library for Zig.

Installation

Developers tend to either use

  • The latest tagged release of Zig
  • The latest build of Zigs master branch

Depending on which developer you are, you need to run different zig fetch commands:

# Version of zig-clap that works with a tagged release of Zig
# Replace `<REPLACE ME>` with the version of zig-clap that you want to use
# See: https://github.com/Hejsil/zig-clap/releases
zig fetch --save https://github.com/Hejsil/zig-clap/archive/refs/tags/<REPLACE ME>.tar.gz

Version of zig-clap that works with latest build of Zigs master branch

zig fetch --save git+https://github.com/Hejsil/zig-clap

Then add the following to build.zig:

const clap = b.dependency("clap", .{});
exe.root_module.addImport("clap", clap.module("clap"));

Features

  • Short arguments -a
    • Chaining -abc where a and b do not take values.
    • Multiple specifications are tallied (e.g. -v -v).
  • Long arguments --long
  • Supports both passing values using spacing and = (-a 100, -a=100)
    • Short args also support passing values with no spacing or = (-a100)
    • This all works with chaining (-ba 100, -ba=100, -ba100)
  • Supports options that can be specified multiple times (-e 1 -e 2 -e 3)
  • Print help message from parameter specification.
  • Parse help message to parameter specification.

API Reference

Automatically generated API Reference for the project can be found at https://Hejsil.github.io/zig-clap. Note that Zig autodoc is in beta; the website may be broken or incomplete.

Examples

clap.parse

The simplest way to use this library is to just call the clap.parse function.

pub fn main(init: std.process.Init) !void {
    // First we specify what parameters our program can take.
    // We can use `parseParamsComptime` to parse a string into an array of `Param(Help)`.
    const params = comptime clap.parseParamsComptime(
        \\-h, --help             Display this help and exit.
        \\-n, --number <usize>   An option parameter, which takes a value.
        \\-s, --string <str>...  An option parameter which can be specified multiple times.
        \\<str>...
        \\
    );
// Initialize our diagnostics, which can be used for reporting useful errors.
// This is optional. You can also pass `.{}` to `clap.parse` if you don&#39;t
// care about the extra information `Diagnostics` provides.
var diag = clap.Diagnostic{};
var res = clap.parse(clap.Help, &amp;params, clap.parsers.default, init.minimal.args, .{
    .diagnostic = &amp;diag,
    .allocator = init.gpa,
}) catch |err| {
    // Report useful error and exit.
    try diag.reportToFile(init.io, .stderr(), err);
    return err;
};
defer res.deinit();

if (res.args.help != 0)
    std.debug.print(&quot;--help\n&quot;, .{});
if (res.args.number) |n|
    std.debug.print(&quot;--number = {}\n&quot;, .{n});
for (res.args.string) |s|
    std.debug.print(&quot;--string = {s}\n&quot;, .{s});
for (res.positionals[0]) |pos|
    std.debug.print(&quot;{s}\n&quot;, .{pos});

}

const clap = @import("clap"); const std = @import("std");

The result will contain an args field and a positionals field. args will have one field for each non-positional parameter of your program. The name of the field will be the longest name of the parameter. positionals will be a tuple with one field for each positional parameter.

The fields in args and positionals are typed. The type is based on the name of the value the parameter takes. Since --number takes a usize the field res.args.number has the type usize.

Note that this is only the case because clap.parsers.default has a field called usize which contains a parser that returns usize. You can pass in something other than clap.parsers.default if you want some other mapping.

pub fn main(init: std.process.Init) !void {
    // First we specify what parameters our program can take.
    // We can use `parseParamsComptime` to parse a string into an array of `Param(Help)`.
    const params = comptime clap.parseParamsComptime(
        \\-h, --help             Display this help and exit.
        \\-n, --number <INT>     An option parameter, which takes a value.
        \\-a, --answer <ANSWER>  An option parameter which takes an enum.
        \\-s, --string <STR>...  An option parameter which can be specified multiple times.
        \\<FILE>...
        \\
    );
// Declare our own parsers which are used to map the argument strings to other
// types.
const YesNo = enum { yes, no };
const parsers = comptime .{
    .STR = clap.parsers.string,
    .FILE = clap.parsers.string,
    .INT = clap.parsers.int(usize, 10),
    .ANSWER = clap.parsers.enumeration(YesNo),
};

var diag = clap.Diagnostic{};
var res = clap.parse(clap.Help, &amp;params, parsers, init.minimal.args, .{
    .diagnostic = &amp;diag,
    .allocator = init.gpa,
    // The assignment separator can be configured. `--number=1` and `--number:1` is now
    // allowed.
    .assignment_separators = &quot;=:&quot;,
}) catch |err| {
    // Report useful error and exit.
    try diag.reportToFile(init.io, .stderr(), err);
    return err;
};
defer res.deinit();

if (res.args.help != 0)
    std.debug.print(&quot;--help\n&quot;, .{});
if (res.args.number) |n|
    std.debug.print(&quot;--number = {}\n&quot;, .{n});
if (res.args.answer) |a|
    std.debug.print(&quot;--answer = {s}\n&quot;, .{@tagName(a)});
for (res.args.string) |s|
    std.debug.print(&quot;--string = {s}\n&quot;, .{s});
for (res.positionals[0]) |pos|
    std.debug.print(&quot;{s}\n&quot;, .{pos});

}

const clap = @import("clap"); const std = @import("std");

Subcommands

There is an option for clap.parse and clap.parseEx called terminating_positional. It allows for users of clap to implement subcommands in their cli application:

// These are our subcommands.
const SubCommands = enum {
    help,
    math,
};

const main_parsers = .{ .command = clap.parsers.enumeration(SubCommands), };

// The parameters for main. Parameters for the subcommands are specified further down. const main_params = clap.parseParamsComptime( \-h, --help Display this help and exit. \<command> \ );

// To pass around arguments returned by clap, clap.Result and clap.ResultEx can be used to // get the return type of clap.parse and clap.parseEx. const MainArgs = clap.ResultEx(clap.Help, &main_params, main_parsers);

pub fn main(init: std.process.Init) !void { var iter = try init.minimal.args.iterateAllocator(init.gpa); defer iter.deinit();

_ = iter.next();

var diag = clap.Diagnostic{};
var res = clap.parseEx(clap.Help, &amp;main_params, main_parsers, &amp;iter, .{
    .diagnostic = &amp;diag,
    .allocator = init.gpa,

    // Terminate the parsing of arguments after parsing the first positional (0 is passed
    // here because parsed positionals are, like slices and arrays, indexed starting at 0).
    //
    // This will terminate the parsing after parsing the subcommand enum and leave `iter`
    // not fully consumed. It can then be reused to parse the arguments for subcommands.
    .terminating_positional = 0,
}) catch |err| {
    try diag.reportToFile(init.io, .stderr(), err);
    return err;
};
defer res.deinit();

if (res.args.help != 0)
    std.debug.print(&quot;--help\n&quot;, .{});

const command = res.positionals[0] orelse return error.MissingCommand;
switch (command) {
    .help =&gt; std.debug.print(&quot;--help\n&quot;, .{}),
    .math =&gt; try mathMain(init.io, init.gpa, &amp;iter, res),
}

}

fn mathMain(io: std.Io, gpa: std.mem.Allocator, iter: *std.process.Args.Iterator, main_args: MainArgs) !void { // The parent arguments are not used here, but there are cases where it might be useful, so // this example shows how to pass the arguments around. _ = main_args;

// The parameters for the subcommand.
const params = comptime clap.parseParamsComptime(
    \\-h, --help  Display this help and exit.
    \\-a, --add   Add the two numbers
    \\-s, --sub   Subtract the two numbers
    \\&lt;isize&gt;
    \\&lt;isize&gt;
    \\
);

// Here we pass the partially parsed argument iterator.
var diag = clap.Diagnostic{};
var res = clap.parseEx(clap.Help, &amp;params, clap.parsers.default, iter, .{
    .diagnostic = &amp;diag,
    .allocator = gpa,
}) catch |err| {
    try diag.reportToFile(io, .stderr(), err);
    return err; // propagate error
};
defer res.deinit();

const a = res.positionals[0] orelse return error.MissingArg1;
const b = res.positionals[1] orelse return error.MissingArg1;
if (res.args.help != 0)
    std.debug.print(&quot;--help\n&quot;, .{});
if (res.args.add != 0)
    std.debug.print(&quot;added: {}\n&quot;, .{a + b});
if (res.args.sub != 0)
    std.debug.print(&quot;subtracted: {}\n&quot;, .{a - b});

}

const clap = @import("clap"); const std = @import("std");

streaming.Clap

The streaming.Clap is the base of all the other parsers. It's a streaming parser that uses an args.Iterator to provide it with arguments lazily.

pub fn main(init: std.process.Init) !void {
    // First we specify what parameters our program can take.
    const params = [_]clap.Param(u8){
        .{
            .id = 'h',
            .names = .{ .short = 'h', .long = "help" },
        },
        .{
            .id = 'n',
            .names = .{ .short = 'n', .long = "number" },
            .takes_value = .one,
        },
        .{ .id = 'f', .takes_value = .one },
    };
var iter = try init.minimal.args.iterateAllocator(init.gpa);
defer iter.deinit();

// Skip exe argument.
_ = iter.next();

// Initialize our diagnostics, which can be used for reporting useful errors.
// This is optional. You can also leave the `diagnostic` field unset if you
// don&#39;t care about the extra information `Diagnostic` provides.
var diag = clap.Diagnostic{};
var parser = clap.streaming.Clap(u8, std.process.Args.Iterator){
    .params = &amp;params,
    .iter = &amp;iter,
    .diagnostic = &amp;diag,
};

// Because we use a streaming parser, we have to consume each argument parsed individually.
while (parser.next() catch |err| {
    // Report useful error and exit.
    try diag.reportToFile(init.io, .stderr(), err);
    return err;
}) |arg| {
    // arg.param will point to the parameter which matched the argument.
    switch (arg.param.id) {
        &#39;h&#39; =&gt; std.debug.print(&quot;Help!\n&quot;, .{}),
        &#39;n&#39; =&gt; std.debug.print(&quot;--number = {s}\n&quot;, .{arg.value.?}),

        // arg.value == null, if arg.param.takes_value == .none.
        // Otherwise, arg.value is the value passed with the argument, such as &quot;-a=10&quot;
        // or &quot;-a 10&quot;.
        &#39;f&#39; =&gt; std.debug.print(&quot;{s}\n&quot;, .{arg.value.?}),
        else =&gt; unreachable,
    }
}

}

const clap = @import("clap"); const std = @import("std");

$ zig-out/bin/streaming-clap --help --number=1 f=10
Help!
--number = 1
f=10

Currently, this parser is the only parser that allows an array of Param that is generated at runtime.

help

help prints a simple list of all parameters the program can take. It expects the Id to have a description method and a value method so that it can provide that in the output. HelpOptions is passed to help to control how the help message is printed.

pub fn main(init: std.process.Init) !void {
    const params = comptime clap.parseParamsComptime(
        \\-h, --help     Display this help and exit.
        \\-v, --version  Output version information and exit.
        \\
    );
var res = try clap.parse(clap.Help, &amp;params, clap.parsers.default, init.minimal.args, .{ .allocator = init.gpa });
defer res.deinit();

// `clap.help` is a function that can print a simple help message. It can print any `Param`
// where `Id` has a `description` and `value` method (`Param(Help)` is one such parameter).
// The last argument contains options as to how `help` should print those parameters. Using
// `.{}` means the default options.
if (res.args.help != 0)
    return clap.helpToFile(init.io, .stderr(), clap.Help, &amp;params, .{});

}

const clap = @import("clap"); const std = @import("std");

$ zig-out/bin/help --help
    -h, --help
            Display this help and exit.

    -v, --version
            Output version information and exit.

usage

usage prints a small abbreviated version of the help message. It expects the Id to have a value method so it can provide that in the output.

pub fn main(init: std.process.Init) !void {
    const params = comptime clap.parseParamsComptime(
        \\-h, --help         Display this help and exit.
        \\-v, --version      Output version information and exit.
        \\    --value <str>  An option parameter, which takes a value.
        \\
    );
var res = try clap.parse(clap.Help, &amp;params, clap.parsers.default, init.minimal.args, .{ .allocator = init.gpa });
defer res.deinit();

// `clap.usageToFile` is a function that can print a simple usage string. It can print any
// `Param` where `Id` has a `value` method (`Param(Help)` is one such parameter).
if (res.args.help != 0)
    return clap.usageToFile(init.io, .stdout(), clap.Help, &amp;params);

}

const clap = @import("clap"); const std = @import("std");

$ zig-out/bin/usage --help
[-hv] [--value <str>]

SEE ALSO

clihub3/4/2026ZIG-CLAP(1)