{"id":15099839,"url":"https://github.com/hejsil/zig-clap","last_synced_at":"2025-05-14T17:05:18.151Z","repository":{"id":42389275,"uuid":"125213768","full_name":"Hejsil/zig-clap","owner":"Hejsil","description":"Command line argument parsing library","archived":false,"fork":false,"pushed_at":"2025-05-07T13:41:00.000Z","size":456,"stargazers_count":1234,"open_issues_count":9,"forks_count":75,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-05-14T17:04:22.581Z","etag":null,"topics":["argument-parser","argument-parsing","command-line","command-line-parser","parsed-arguments","zig-package","ziglang"],"latest_commit_sha":null,"homepage":"","language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Hejsil.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["Hejsil"]}},"created_at":"2018-03-14T13:06:16.000Z","updated_at":"2025-05-14T15:34:24.000Z","dependencies_parsed_at":"2023-11-16T12:25:20.012Z","dependency_job_id":"aa91967d-d38a-40b6-b6d8-f94b817e4e6a","html_url":"https://github.com/Hejsil/zig-clap","commit_stats":{"total_commits":253,"total_committers":34,"mean_commits":"7.4411764705882355","dds":0.7035573122529644,"last_synced_commit":"7003678307b72bc25869308d7435a79114d1ac42"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hejsil%2Fzig-clap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hejsil%2Fzig-clap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hejsil%2Fzig-clap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hejsil%2Fzig-clap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hejsil","download_url":"https://codeload.github.com/Hejsil/zig-clap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254190396,"owners_count":22029632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argument-parser","argument-parsing","command-line","command-line-parser","parsed-arguments","zig-package","ziglang"],"created_at":"2024-09-25T17:28:16.232Z","updated_at":"2025-05-14T17:05:18.081Z","avatar_url":"https://github.com/Hejsil.png","language":"Zig","readme":"# zig-clap\n\nA simple and easy to use command line argument parser library for Zig.\n\n## Installation\n\nDevelopers tend to either use\n* The latest tagged release of Zig\n* The latest build of Zigs master branch\n\nDepending on which developer you are, you need to run different `zig fetch` commands:\n\n```sh\n# Version of zig-clap that works with a tagged release of Zig\n# Replace `\u003cREPLACE ME\u003e` with the version of zig-clap that you want to use\n# See: https://github.com/Hejsil/zig-clap/releases\nzig fetch --save https://github.com/Hejsil/zig-clap/archive/refs/tags/\u003cREPLACE ME\u003e.tar.gz\n\n# Version of zig-clap that works with latest build of Zigs master branch\nzig fetch --save git+https://github.com/Hejsil/zig-clap\n```\n\nThen add the following to `build.zig`:\n\n```zig\nconst clap = b.dependency(\"clap\", .{});\nexe.root_module.addImport(\"clap\", clap.module(\"clap\"));\n```\n\n## Features\n\n* Short arguments `-a`\n  * Chaining `-abc` where `a` and `b` does not take values.\n  * Multiple specifications are tallied (e.g. `-v -v`).\n* Long arguments `--long`\n* Supports both passing values using spacing and `=` (`-a 100`, `-a=100`)\n  * Short args also support passing values with no spacing or `=` (`-a100`)\n  * This all works with chaining (`-ba 100`, `-ba=100`, `-ba100`)\n* Supports options that can be specified multiple times (`-e 1 -e 2 -e 3`)\n* Print help message from parameter specification.\n* Parse help message to parameter specification.\n\n## API Reference\n\nAutomatically generated API Reference for the project can be found at\nhttps://Hejsil.github.io/zig-clap. Note that Zig autodoc is in beta; the website\nmay be broken or incomplete.\n\n## Examples\n\n### `clap.parse`\n\nThe simplest way to use this library is to just call the `clap.parse` function.\n\n```zig\npub fn main() !void {\n    var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n    defer _ = gpa.deinit();\n\n    // First we specify what parameters our program can take.\n    // We can use `parseParamsComptime` to parse a string into an array of `Param(Help)`.\n    const params = comptime clap.parseParamsComptime(\n        \\\\-h, --help             Display this help and exit.\n        \\\\-n, --number \u003cusize\u003e   An option parameter, which takes a value.\n        \\\\-s, --string \u003cstr\u003e...  An option parameter which can be specified multiple times.\n        \\\\\u003cstr\u003e...\n        \\\\\n    );\n\n    // Initialize our diagnostics, which can be used for reporting useful errors.\n    // This is optional. You can also pass `.{}` to `clap.parse` if you don't\n    // care about the extra information `Diagnostics` provides.\n    var diag = clap.Diagnostic{};\n    var res = clap.parse(clap.Help, \u0026params, clap.parsers.default, .{\n        .diagnostic = \u0026diag,\n        .allocator = gpa.allocator(),\n    }) catch |err| {\n        // Report useful error and exit.\n        diag.report(std.io.getStdErr().writer(), err) catch {};\n        return err;\n    };\n    defer res.deinit();\n\n    if (res.args.help != 0)\n        std.debug.print(\"--help\\n\", .{});\n    if (res.args.number) |n|\n        std.debug.print(\"--number = {}\\n\", .{n});\n    for (res.args.string) |s|\n        std.debug.print(\"--string = {s}\\n\", .{s});\n    for (res.positionals[0]) |pos|\n        std.debug.print(\"{s}\\n\", .{pos});\n}\n\nconst clap = @import(\"clap\");\nconst std = @import(\"std\");\n\n```\n\nThe result will contain an `args` field and a `positionals` field. `args` will have one field for\neach non-positional parameter of your program. The name of the field will be the longest name of the\nparameter. `positionals` will be a tuple with one field for each positional parameter.\n\nThe fields in `args` and `postionals` are typed. The type is based on the name of the value the\nparameter takes. Since `--number` takes a `usize` the field `res.args.number` has the type `usize`.\n\nNote that this is only the case because `clap.parsers.default` has a field called `usize` which\ncontains a parser that returns `usize`. You can pass in something other than `clap.parsers.default`\nif you want some other mapping.\n\n```zig\npub fn main() !void {\n    var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n    defer _ = gpa.deinit();\n\n    // First we specify what parameters our program can take.\n    // We can use `parseParamsComptime` to parse a string into an array of `Param(Help)`.\n    const params = comptime clap.parseParamsComptime(\n        \\\\-h, --help             Display this help and exit.\n        \\\\-n, --number \u003cINT\u003e     An option parameter, which takes a value.\n        \\\\-a, --answer \u003cANSWER\u003e  An option parameter which takes an enum.\n        \\\\-s, --string \u003cSTR\u003e...  An option parameter which can be specified multiple times.\n        \\\\\u003cFILE\u003e...\n        \\\\\n    );\n\n    // Declare our own parsers which are used to map the argument strings to other\n    // types.\n    const YesNo = enum { yes, no };\n    const parsers = comptime .{\n        .STR = clap.parsers.string,\n        .FILE = clap.parsers.string,\n        .INT = clap.parsers.int(usize, 10),\n        .ANSWER = clap.parsers.enumeration(YesNo),\n    };\n\n    var diag = clap.Diagnostic{};\n    var res = clap.parse(clap.Help, \u0026params, parsers, .{\n        .diagnostic = \u0026diag,\n        .allocator = gpa.allocator(),\n        // The assignment separator can be configured. `--number=1` and `--number:1` is now\n        // allowed.\n        .assignment_separators = \"=:\",\n    }) catch |err| {\n        diag.report(std.io.getStdErr().writer(), err) catch {};\n        return err;\n    };\n    defer res.deinit();\n\n    if (res.args.help != 0)\n        std.debug.print(\"--help\\n\", .{});\n    if (res.args.number) |n|\n        std.debug.print(\"--number = {}\\n\", .{n});\n    if (res.args.answer) |a|\n        std.debug.print(\"--answer = {s}\\n\", .{@tagName(a)});\n    for (res.args.string) |s|\n        std.debug.print(\"--string = {s}\\n\", .{s});\n    for (res.positionals[0]) |pos|\n        std.debug.print(\"{s}\\n\", .{pos});\n}\n\nconst clap = @import(\"clap\");\nconst std = @import(\"std\");\n\n```\n\n### Subcommands\n\nThere is an option for `clap.parse` and `clap.parseEx` called `terminating_positional`. It allows\nfor users of `clap` to implement subcommands in their cli application:\n\n```zig\n// These are our subcommands.\nconst SubCommands = enum {\n    help,\n    math,\n};\n\nconst main_parsers = .{\n    .command = clap.parsers.enumeration(SubCommands),\n};\n\n// The parameters for `main`. Parameters for the subcommands are specified further down.\nconst main_params = clap.parseParamsComptime(\n    \\\\-h, --help  Display this help and exit.\n    \\\\\u003ccommand\u003e\n    \\\\\n);\n\n// To pass around arguments returned by clap, `clap.Result` and `clap.ResultEx` can be used to\n// get the return type of `clap.parse` and `clap.parseEx`.\nconst MainArgs = clap.ResultEx(clap.Help, \u0026main_params, main_parsers);\n\npub fn main() !void {\n    var gpa_state = std.heap.GeneralPurposeAllocator(.{}){};\n    const gpa = gpa_state.allocator();\n    defer _ = gpa_state.deinit();\n\n    var iter = try std.process.ArgIterator.initWithAllocator(gpa);\n    defer iter.deinit();\n\n    _ = iter.next();\n\n    var diag = clap.Diagnostic{};\n    var res = clap.parseEx(clap.Help, \u0026main_params, main_parsers, \u0026iter, .{\n        .diagnostic = \u0026diag,\n        .allocator = gpa,\n\n        // Terminate the parsing of arguments after parsing the first positional (0 is passed\n        // here because parsed positionals are, like slices and arrays, indexed starting at 0).\n        //\n        // This will terminate the parsing after parsing the subcommand enum and leave `iter`\n        // not fully consumed. It can then be reused to parse the arguments for subcommands.\n        .terminating_positional = 0,\n    }) catch |err| {\n        diag.report(std.io.getStdErr().writer(), err) catch {};\n        return err;\n    };\n    defer res.deinit();\n\n    if (res.args.help != 0)\n        std.debug.print(\"--help\\n\", .{});\n\n    const command = res.positionals[0] orelse return error.MissingCommand;\n    switch (command) {\n        .help =\u003e std.debug.print(\"--help\\n\", .{}),\n        .math =\u003e try mathMain(gpa, \u0026iter, res),\n    }\n}\n\nfn mathMain(gpa: std.mem.Allocator, iter: *std.process.ArgIterator, main_args: MainArgs) !void {\n    // The parent arguments are not used here, but there are cases where it might be useful, so\n    // this example shows how to pass the arguments around.\n    _ = main_args;\n\n    // The parameters for the subcommand.\n    const params = comptime clap.parseParamsComptime(\n        \\\\-h, --help  Display this help and exit.\n        \\\\-a, --add   Add the two numbers\n        \\\\-s, --sub   Subtract the two numbers\n        \\\\\u003cisize\u003e\n        \\\\\u003cisize\u003e\n        \\\\\n    );\n\n    // Here we pass the partially parsed argument iterator.\n    var diag = clap.Diagnostic{};\n    var res = clap.parseEx(clap.Help, \u0026params, clap.parsers.default, iter, .{\n        .diagnostic = \u0026diag,\n        .allocator = gpa,\n    }) catch |err| {\n        diag.report(std.io.getStdErr().writer(), err) catch {};\n        return err;\n    };\n    defer res.deinit();\n\n    const a = res.positionals[0] orelse return error.MissingArg1;\n    const b = res.positionals[1] orelse return error.MissingArg1;\n    if (res.args.help != 0)\n        std.debug.print(\"--help\\n\", .{});\n    if (res.args.add != 0)\n        std.debug.print(\"added: {}\\n\", .{a + b});\n    if (res.args.sub != 0)\n        std.debug.print(\"subtracted: {}\\n\", .{a - b});\n}\n\nconst clap = @import(\"clap\");\nconst std = @import(\"std\");\n\n```\n\n### `streaming.Clap`\n\nThe `streaming.Clap` is the base of all the other parsers. It's a streaming parser that uses an\n`args.Iterator` to provide it with arguments lazily.\n\n```zig\npub fn main() !void {\n    const allocator = std.heap.page_allocator;\n\n    // First we specify what parameters our program can take.\n    const params = [_]clap.Param(u8){\n        .{\n            .id = 'h',\n            .names = .{ .short = 'h', .long = \"help\" },\n        },\n        .{\n            .id = 'n',\n            .names = .{ .short = 'n', .long = \"number\" },\n            .takes_value = .one,\n        },\n        .{ .id = 'f', .takes_value = .one },\n    };\n\n    var iter = try std.process.ArgIterator.initWithAllocator(allocator);\n    defer iter.deinit();\n\n    // Skip exe argument.\n    _ = iter.next();\n\n    // Initialize our diagnostics, which can be used for reporting useful errors.\n    // This is optional. You can also leave the `diagnostic` field unset if you\n    // don't care about the extra information `Diagnostic` provides.\n    var diag = clap.Diagnostic{};\n    var parser = clap.streaming.Clap(u8, std.process.ArgIterator){\n        .params = \u0026params,\n        .iter = \u0026iter,\n        .diagnostic = \u0026diag,\n    };\n\n    // Because we use a streaming parser, we have to consume each argument parsed individually.\n    while (parser.next() catch |err| {\n        // Report useful error and exit.\n        diag.report(std.io.getStdErr().writer(), err) catch {};\n        return err;\n    }) |arg| {\n        // arg.param will point to the parameter which matched the argument.\n        switch (arg.param.id) {\n            'h' =\u003e std.debug.print(\"Help!\\n\", .{}),\n            'n' =\u003e std.debug.print(\"--number = {s}\\n\", .{arg.value.?}),\n\n            // arg.value == null, if arg.param.takes_value == .none.\n            // Otherwise, arg.value is the value passed with the argument, such as \"-a=10\"\n            // or \"-a 10\".\n            'f' =\u003e std.debug.print(\"{s}\\n\", .{arg.value.?}),\n            else =\u003e unreachable,\n        }\n    }\n}\n\nconst clap = @import(\"clap\");\nconst std = @import(\"std\");\n\n```\n\nCurrently, this parser is the only parser that allows an array of `Param` that is generated at runtime.\n\n### `help`\n\n`help` prints a simple list of all parameters the program can take. It expects the `Id` to have a\n`description` method and an `value` method so that it can provide that in the output. `HelpOptions`\nis passed to `help` to control how the help message is printed.\n\n```zig\npub fn main() !void {\n    var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n    defer _ = gpa.deinit();\n\n    const params = comptime clap.parseParamsComptime(\n        \\\\-h, --help     Display this help and exit.\n        \\\\-v, --version  Output version information and exit.\n        \\\\\n    );\n\n    var res = try clap.parse(clap.Help, \u0026params, clap.parsers.default, .{\n        .allocator = gpa.allocator(),\n    });\n    defer res.deinit();\n\n    // `clap.help` is a function that can print a simple help message. It can print any `Param`\n    // where `Id` has a `description` and `value` method (`Param(Help)` is one such parameter).\n    // The last argument contains options as to how `help` should print those parameters. Using\n    // `.{}` means the default options.\n    if (res.args.help != 0)\n        return clap.help(std.io.getStdErr().writer(), clap.Help, \u0026params, .{});\n}\n\nconst clap = @import(\"clap\");\nconst std = @import(\"std\");\n\n```\n\n```\n$ zig-out/bin/help --help\n    -h, --help\n            Display this help and exit.\n\n    -v, --version\n            Output version information and exit.\n```\n\n### `usage`\n\n`usage` prints a small abbreviated version of the help message. It expects the `Id` to have a\n`value` method so it can provide that in the output.\n\n```zig\npub fn main() !void {\n    var gpa = std.heap.GeneralPurposeAllocator(.{}){};\n    defer _ = gpa.deinit();\n\n    const params = comptime clap.parseParamsComptime(\n        \\\\-h, --help         Display this help and exit.\n        \\\\-v, --version      Output version information and exit.\n        \\\\    --value \u003cstr\u003e  An option parameter, which takes a value.\n        \\\\\n    );\n\n    var res = try clap.parse(clap.Help, \u0026params, clap.parsers.default, .{\n        .allocator = gpa.allocator(),\n    });\n    defer res.deinit();\n\n    // `clap.usage` is a function that can print a simple help message. It can print any `Param`\n    // where `Id` has a `value` method (`Param(Help)` is one such parameter).\n    if (res.args.help != 0)\n        return clap.usage(std.io.getStdErr().writer(), clap.Help, \u0026params);\n}\n\nconst clap = @import(\"clap\");\nconst std = @import(\"std\");\n\n```\n\n```\n$ zig-out/bin/usage --help\n[-hv] [--value \u003cstr\u003e]\n```\n\n","funding_links":["https://github.com/sponsors/Hejsil"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhejsil%2Fzig-clap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhejsil%2Fzig-clap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhejsil%2Fzig-clap/lists"}