{"id":13710494,"url":"https://github.com/PrajwalCH/yazap","last_synced_at":"2025-05-06T19:32:02.916Z","repository":{"id":48572923,"uuid":"469404225","full_name":"prajwalch/yazap","owner":"prajwalch","description":"🔧 The ultimate Zig library for seamless command line argument parsing. ","archived":false,"fork":false,"pushed_at":"2025-04-23T14:20:29.000Z","size":18481,"stargazers_count":173,"open_issues_count":4,"forks_count":18,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-23T15:30:03.368Z","etag":null,"topics":["argument-parser","argument-parsing","cli","command-line-arguments-parser","flags","parser","subcommands","zig","ziglang"],"latest_commit_sha":null,"homepage":"https://prajwalch.github.io/yazap","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/prajwalch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2022-03-13T14:59:46.000Z","updated_at":"2025-04-23T14:20:33.000Z","dependencies_parsed_at":"2024-07-13T00:25:01.907Z","dependency_job_id":"70916b07-84d8-4c1d-a497-96bccb343694","html_url":"https://github.com/prajwalch/yazap","commit_stats":{"total_commits":697,"total_committers":11,"mean_commits":63.36363636363637,"dds":"0.42898134863701576","last_synced_commit":"e9293645250e2bc172f100bb0467aea55b1d4f3e"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prajwalch%2Fyazap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prajwalch%2Fyazap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prajwalch%2Fyazap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prajwalch%2Fyazap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prajwalch","download_url":"https://codeload.github.com/prajwalch/yazap/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252753536,"owners_count":21798975,"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","cli","command-line-arguments-parser","flags","parser","subcommands","zig","ziglang"],"created_at":"2024-08-02T23:00:57.378Z","updated_at":"2025-05-06T19:31:57.902Z","avatar_url":"https://github.com/prajwalch.png","language":"Zig","funding_links":[],"categories":["Libraries","Zig ⚡","Language Essentials"],"sub_categories":["Command Line and Argument Parser"],"readme":"[![test](https://github.com/PrajwalCH/yazap/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/PrajwalCH/yazap/actions/workflows/test.yml)\r\n[![pages-build-deployment](https://github.com/PrajwalCH/yazap/actions/workflows/pages/pages-build-deployment/badge.svg)](https://github.com/PrajwalCH/yazap/actions/workflows/pages/pages-build-deployment)\r\n\r\n# Yazap\r\n\r\n\u003e [!NOTE]\r\n\u003e This branch targets the [master branch of zig](https://github.com/ziglang/zig).\r\n\u003e See [supported versions table](#supported-versions-table).\r\n\r\nThe ultimate [zig](https://ziglang.org) library for seamless command-line parsing.\r\nEffortlessly handles options, subcommands, and custom arguments with ease.\r\n\r\nInspired by [clap-rs](https://github.com/clap-rs/clap) and [andrewrk/ziglang: src-self-hosted/arg.zig](https://git.sr.ht/~andrewrk/ziglang/tree/725b6ee634f01355da4a6badc5675751b85f0bf0/src-self-hosted/arg.zig)\r\n\r\n## Supported versions table\r\n| yazap                                                             | Zig                                      |\r\n| ----------------------------------------------------------------- | ---------------------------------------- |\r\n| main                                                              | [master](https://github.com/ziglang/zig) |\r\n| [`0.5.1`](https://github.com/prajwalch/yazap/releases/tag/v0.5.1) | `0.12.0`, `0.12.1` and  `0.13.0`         |\r\n| \u003c= `0.5.0`                                                        | Not supported to any                     |\r\n\r\n## Key Features:\r\n\r\n- [**Options (short and long)**](#adding-arguments):\r\n  - Providing values with `=`, space, or no space (`-f=value`, `-f value`, `-fvalue`).\r\n  - Supports delimiter-separated values with `=` or without space (`-f=v1,v2,v3`, `-fv1:v2:v3`).\r\n  - Chaining multiple short boolean options (`-abc`).\r\n  - Providing values and delimiter-separated values for multiple chained options using `=` (`-abc=val`, `-abc=v1,v2,v3`).\r\n  - Specifying an option multiple times (`-a 1 -a 2 -a 3`).\r\n\r\n- [**Positional arguments**](#adding-arguments):\r\n  - Supports positional arguments alongside options for more flexible command-line inputs. For example:\r\n    - `command \u003cpositional_arg\u003e`\r\n    - `command \u003carg1\u003e \u003carg2\u003e \u003carg3\u003e`\r\n\r\n- [**Nested subcommands**](#adding-subcommands):\r\n  - Organize commands with nested subcommands for a structured command-line interface. For example:\r\n    - `command subcommand`\r\n    - `command subcommand subsubcommand`\r\n\r\n- [**Automatic help handling and generation**](#handling-help)\r\n\r\n- **Custom Argument definition**:\r\n  - Define custom [Argument](/src/Arg.zig) types for specific application requirements.\r\n\r\n## Limitations:\r\n\r\n- Does not support delimiter-separated values using space (`-f v1,v2,v3`).\r\n- Does not support providing value and delimiter-separated values for multiple\r\nchained options using space (`-abc value, -abc v1,v2,v3`).\r\n\r\n## Installing\r\n\r\n1. Run the following command:\r\n\r\n```\r\nzig fetch --save git+https://github.com/prajwalch/yazap\r\n```\r\n\r\n2. Add the following to `build.zig`:\r\n\r\n```zig\r\nconst yazap = b.dependency(\"yazap\", .{});\r\nexe.root_module.addImport(\"yazap\", yazap.module(\"yazap\"));\r\n```\r\n\r\n## Documentation\r\n\r\nFor detailed and comprehensive documentation, please visit\r\n[this link](https://prajwalch.github.io/yazap/).\r\n\r\n\u003e [!WARNING]\r\n\u003e The documentation site is currently broken, in the meantime check out the source code.\r\n\r\n## Building and Running Examples\r\n\r\nThe examples can be found [here](/examples). To build all of them, run the\r\nfollowing command on your terminal:\r\n\r\n```bash\r\n$ zig build examples\r\n```\r\n\r\nAfter the compilation finishes, you can run each example by executing the\r\ncorresponding binary:\r\n\r\n```bash\r\n$ ./zig-out/bin/example_name\r\n```\r\n\r\nTo view the usage and available options for each example, you can use `-h` or\r\n`--help` flag:\r\n\r\n```bash\r\n$ ./zig-out/bin/example_name --help\r\n```\r\n\r\n## Usage\r\n\r\n### Initializing Yazap\r\n\r\nTo begin using `yazap`, the first step is to create an instance of \r\n[App](/src/App.zig) by calling\r\n`App.init(allocator, \"Your app name\", \"optional description\")`. This function\r\ninternally creates a root command for your application.\r\n\r\n```zig\r\nvar app = App.init(allocator, \"myls\", \"My custom ls\");\r\ndefer app.deinit();\r\n```\r\n\r\n### Obtaining the Root Command\r\n\r\nThe [App](/src/App.zig) itself does not provide\r\nany methods for adding arguments to your command. Its main purpose is to\r\ninitialize the library, to invoke the parser with necessary arguments, and to\r\ndeinitilize the library. \r\n\r\nTo add arguments and subcommands, acquire the root command by calling `App.rootCommand()`.\r\nThis gives you access to the core command of your application by returning a pointer to it.\r\n\r\n```zig\r\nvar myls = app.rootCommand();\r\n```\r\n\r\n### Adding Arguments\r\n\r\nOnce you have obtained the root command, you can proceed to add arguments and\r\n[subcommands](#adding-subcommands) using the methods available in the `Command`. For a complete list\r\nof available methods, refer to the [Command API](/src/Command.zig)\r\ndocumentation.\r\n\r\n```zig\r\ntry myls.addArg(Arg.positional(\"FILE\", null, null));\r\ntry myls.addArg(Arg.booleanOption(\"all\", 'a', \"Don't ignore the hidden directories\"));\r\ntry myls.addArg(Arg.booleanOption(\"recursive\", 'R', \"List subdirectories recursively\"));\r\ntry myls.addArg(Arg.booleanOption(\"one-line\", '1', null));\r\ntry myls.addArg(Arg.booleanOption(\"size\", 's', null));\r\ntry myls.addArg(Arg.booleanOption(\"version\", null, null));\r\n\r\ntry myls.addArg(Arg.singleValueOption(\"ignore\", 'I', null));\r\ntry myls.addArg(Arg.singleValueOption(\"hide\", null, null));\r\n\r\ntry myls.addArg(Arg.singleValueOptionWithValidValues(\r\n    \"color\",\r\n    'C',\r\n    \"Colorize the output\",\r\n    \u0026[_][]const u8{ \"always\", \"auto\", \"never\" }\r\n));\r\n```\r\n\r\nAlternatively, you can add multiple arguments in a single function call using\r\n`Command.addArgs()`:\r\n\r\n```zig\r\ntry myls.addArgs(\u0026[_]Arg {\r\n    Arg.positional(\"FILE\", null, null),\r\n    Arg.booleanOption(\"all\", 'a', \"Don't ignore the hidden directories\"),\r\n    Arg.booleanOption(\"recursive\", 'R', \"List subdirectories recursively\"),\r\n    Arg.booleanOption(\"one-line\", '1', null),\r\n    Arg.booleanOption(\"size\", 's', null),\r\n    Arg.booleanOption(\"version\", null, null),\r\n\r\n    Arg.singleValueOption(\"ignore\", 'I', null),\r\n    Arg.singleValueOption(\"hide\", null, null),\r\n\r\n    Arg.singleValueOptionWithValidValues(\r\n        \"color\",\r\n        'C',\r\n        \"Colorize the output\",\r\n        \u0026[_][]const u8{ \"always\", \"auto\", \"never\" }\r\n    ),\r\n});\r\n```\r\n\r\nNote that for any option that accepts value, you can set its value placeholder to display in the\r\nhelp message. If you don't set the placeholder, the option name will be displayed by default.\r\n\r\n```zig\r\nvar ignore_opt = Arg.singleValueOption(\"ignore\", 'I', null);\r\nignore_opt.setValuePlaceholder(\"PATTERN\");\r\n\r\nvar hide_opt = Arg.singleValueOption(\"hide\", null, null);\r\nhide_opt.setValuesPlaceholder(\"PATTERN\");\r\n\r\nvar color_opt = Arg.singleValueOptionWithValidValues(\r\n    \"color\",\r\n    'C',\r\n    \"Colorize the output\",\r\n    \u0026[_][]const u8{ \"always\", \"auto\", \"never\" }\r\n);\r\ncolor_opt.setValuePlaceholder(\"WHEN\");\r\n\r\ntry myls.addArgs(\u0026[_]Arg{ ignore_opt, hide_opt, color_opt });\r\n```\r\n\r\n### Adding Subcommands\r\n\r\nTo create a subcommand, use `App.createCommand(\"name\", \"optional description\")` then\r\nyou can add its own arguments and subcommands just like the root command. After you\r\nfinish adding arguments, add it as a root subcommand by calling `Command.addSubcommand()`.\r\n\r\n```zig\r\nvar update_cmd = app.createCommand(\"update\", \"Update the app or check for new updates\");\r\ntry update_cmd.addArg(Arg.booleanOption(\"check-only\", null, \"Only check for new update\"));\r\ntry update_cmd.addArg(Arg.singleValueOptionWithValidValues(\r\n    \"branch\",\r\n    'b',\r\n    \"Branch to update\",\r\n    \u0026[_][]const u8{ \"stable\", \"nightly\", \"beta\" }\r\n));\r\n\r\ntry myls.addSubcommand(update_cmd);\r\n```\r\n\r\n### Parsing Arguments\r\n\r\nOnce you have finished adding all the arguments and subcommands, call `App.parseProcess()`\r\nto start parsing the arguments given to the current process. This function internally utilizes\r\n[`std.process.argsAlloc`](https://ziglang.org/documentation/master/std/#A;std:process.argsAlloc)\r\nto obtain the raw arguments. Alternatively, you can use `App.parseFrom()` and pass your own raw \r\narguments, which can be useful during testing. Both functions returns\r\n[`ArgMatches`](/src/ArgMatches.zig).\r\n\r\n```zig\r\nconst matches = try app.parseProcess();\r\n\r\nif (matches.containsArg(\"version\")) {\r\n    log.info(\"v0.1.0\", .{});\r\n    return;\r\n}\r\n\r\nif (matches.getSingleValue(\"FILE\")) |f| {\r\n    log.info(\"List contents of {f}\");\r\n    return;\r\n}\r\n\r\nif (matches.subcommandMatches(\"update\")) |update_cmd_matches| {\r\n    if (update_cmd_matches.containsArg(\"check-only\")) {\r\n        std.log.info(\"Check and report new update\", .{});\r\n        return;\r\n    }\r\n\r\n    if (update_cmd_matches.getSingleValue(\"branch\")) |branch| {\r\n        std.log.info(\"Branch to update: {s}\", .{branch});\r\n        return;\r\n    }\r\n    return;\r\n}\r\n\r\nif (matches.containsArg(\"all\")) {\r\n    log.info(\"show all\", .{});\r\n    return;\r\n}\r\n\r\nif (matches.containsArg(\"recursive\")) {\r\n    log.info(\"show recursive\", .{});\r\n    return;\r\n}\r\n\r\nif (matches.getSingleValue(\"ignore\")) |pattern| {\r\n    log.info(\"ignore pattern = {s}\", .{pattern});\r\n    return;\r\n}\r\n\r\nif (matches.containsArg(\"color\")) {\r\n    const when = matches.getSingleValue(\"color\").?;\r\n\r\n    log.info(\"color={s}\", .{when});\r\n    return;\r\n}\r\n```\r\n\r\n### Handling Help\r\n\r\n`-h` and `--h` flag is globally available to all the commands and subcommands and \r\nhandled automatically when they are passed to command line. However, if you need to\r\nmanually display the help message there are currently two ways to do it.\r\n\r\n#### 1. By invoking `App.displayHelp()` and `App.displaySubcommandHelp()`.\r\n\r\n`App.displayHelp()` displays the help message for the root command and\r\nother hand `App.displaySubcommandHelp()` displays the help message for the\r\nactive subcommand.\r\n\r\nFor e.x.: if `gh auth login` were passed then `App.displayHelp()` would display the\r\nhelp for `gh` and `App.displaySubcommandHelp()` display the help for `login`.\r\n\r\nExample:\r\n\r\n```zig\r\nif (!matches.containsArgs()) {\r\n    try app.displayHelp();\r\n    return;\r\n}\r\n\r\nif (matches.subcommandMatches(\"update\")) |update_cmd_matches| {\r\n    if (!update_cmd_matches.containsArgs()) {\r\n        try app.displaySubcommandHelp();\r\n        return;\r\n    }\r\n}\r\n```\r\n\r\n#### 2. By setting `.help_on_empty_args` property to the command.\r\n\r\nThe `.help_on_empty_args` property which when set to a command, it instructs\r\nthe handler to display the help message for that particular command when arguments\r\nare not provided. It behaves exactly like the code shown at the example above.\r\n\r\nExample:\r\n\r\n```zig\r\nvar app = App.init(allocator, \"myls\", \"My custom ls\");\r\ndefer app.deinit();\r\n\r\nvar myls = app.rootCommand();\r\nmyls.setProperty(.help_on_empty_args);\r\n\r\nvar update_cmd = app.createCommand(\"update\", \"Update the app or check for new updates\");\r\nupdate_cmd.setProperty(.help_on_empty_args);\r\n\r\ntry myls.addSubcommand(update_cmd);\r\n\r\nconst matches = try myls.parseProcess();\r\n\r\n// --snip--\r\n```\r\n\r\n### Putting it All Together\r\n\r\n```zig\r\nconst std = @import(\"std\");\r\nconst yazap = @import(\"yazap\");\r\n\r\nconst allocator = std.heap.page_allocator;\r\nconst log = std.log;\r\nconst App = yazap.App;\r\nconst Arg = yazap.Arg;\r\n\r\npub fn main() anyerror!void {\r\n    var app = App.init(allocator, \"myls\", \"My custom ls\");\r\n    defer app.deinit();\r\n\r\n    var myls = app.rootCommand();\r\n    myls.setProperty(.help_on_empty_args);\r\n    \r\n    try myls.addArgs(\u0026[_]Arg {\r\n        Arg.positional(\"FILE\", null, null),\r\n        Arg.booleanOption(\"all\", 'a', \"Don't ignore the hidden directories\"),\r\n        Arg.booleanOption(\"recursive\", 'R', \"List subdirectories recursively\"),\r\n        Arg.booleanOption(\"one-line\", '1', null),\r\n        Arg.booleanOption(\"size\", 's', null),\r\n        Arg.booleanOption(\"version\", null, null),\r\n    });\r\n    \r\n    var ignore_opt = Arg.singleValueOption(\"ignore\", 'I', null);\r\n    ignore_opt.setValuePlaceholder(\"PATTERN\");\r\n\r\n    var hide_opt = Arg.singleValueOption(\"hide\", null, null);\r\n    hide_opt.setValuesPlaceholder(\"PATTERN\");\r\n\r\n    var color_opt = Arg.singleValueOptionWithValidValues(\r\n        \"color\",\r\n        'C',\r\n        \"Colorize the output\",\r\n        \u0026[_][]const u8{ \"always\", \"auto\", \"never\" }\r\n    );\r\n    color_opt.setValuePlaceholder(\"WHEN\");\r\n\r\n    try myls.addArgs(\u0026[_]Arg{ ignore_opt, hide_opt, color_opt });\r\n\r\n    // Update subcommand.\r\n    var update_cmd = app.createCommand(\"update\", \"Update the app or check for new updates\");\r\n    update_cmd.setProperty(.help_on_empty_args);\r\n\r\n    try update_cmd.addArg(Arg.booleanOption(\"check-only\", null, \"Only check for new update\"));\r\n    try update_cmd.addArg(Arg.singleValueOptionWithValidValues(\r\n        \"branch\",\r\n        'b',\r\n        \"Branch to update\",\r\n        \u0026[_][]const u8{ \"stable\", \"nightly\", \"beta\" }\r\n    ));\r\n\r\n    try myls.addSubcommand(update_cmd);\r\n\r\n    // Get the parse result.\r\n    const matches = try app.parseProcess();\r\n\r\n    if (matches.containsArg(\"version\")) {\r\n        log.info(\"v0.1.0\", .{});\r\n        return;\r\n    }\r\n\r\n    if (matches.getSingleValue(\"FILE\")) |f| {\r\n        log.info(\"List contents of {f}\");\r\n        return;\r\n    }\r\n\r\n    if (matches.subcommandMatches(\"update\")) |update_cmd_matches| {\r\n        if (update_cmd_matches.containsArg(\"check-only\")) {\r\n            std.log.info(\"Check and report new update\", .{});\r\n            return;\r\n        }\r\n\r\n        if (update_cmd_matches.getSingleValue(\"branch\")) |branch| {\r\n            std.log.info(\"Branch to update: {s}\", .{branch});\r\n            return;\r\n        }\r\n        return;\r\n    }\r\n\r\n    if (matches.containsArg(\"all\")) {\r\n        log.info(\"show all\", .{});\r\n        return;\r\n    }\r\n\r\n    if (matches.containsArg(\"recursive\")) {\r\n        log.info(\"show recursive\", .{});\r\n        return;\r\n    }\r\n\r\n    if (matches.getSingleValue(\"ignore\")) |pattern| {\r\n        log.info(\"ignore pattern = {s}\", .{pattern});\r\n        return;\r\n    }\r\n\r\n    if (matches.containsArg(\"color\")) {\r\n        const when = matches.getSingleValue(\"color\").?;\r\n\r\n        log.info(\"color={s}\", .{when});\r\n        return;\r\n    }\r\n}\r\n```\r\n\r\n## Alternate Parsers\r\n- [Hejsil/zig-clap](https://github.com/Hejsil/zig-clap) - Simple command line argument parsing library\r\n- [winksaville/zig-parse-args](https://github.com/winksaville/zig-parse-args) - Parse command line arguments\r\n- [MasterQ32/zig-args](https://github.com/MasterQ32/zig-args) - Simple-to-use argument parser with struct-based config\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPrajwalCH%2Fyazap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPrajwalCH%2Fyazap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPrajwalCH%2Fyazap/lists"}