The ultimate zig library for seamless command-line parsing. Effortlessly handles options, subcommands, and custom arguments with ease.
Inspired by clap-rs and andrewrk/ziglang: src-self-hosted/arg.zig
yazap Zig main master0.6.3
0.14.0
0.5.1
0.12.0
, 0.12.1
and 0.13.0
<= 0.5.0
Not supported to any
=
, space, or no space (-f=value
, -f value
, -fvalue
).=
or without space (-f=v1,v2,v3
, -fv1:v2:v3
).-abc
).=
(-abc=val
, -abc=v1,v2,v3
).-a 1 -a 2 -a 3
).command <positional_arg>
command <arg1> <arg2> <arg3>
command subcommand
command subcommand subsubcommand
Custom Argument definition:
-f v1,v2,v3
).-abc value, -abc v1,v2,v3
).zig fetch --save git+https://github.com/prajwalch/yazap
build.zig
:const yazap = b.dependency("yazap", .{}); exe.root_module.addImport("yazap", yazap.module("yazap"));
For detailed and comprehensive documentation, please visit this link.
Warning
The documentation site is currently broken, in the meantime check out the source code.
To begin using yazap
, the first step is to create an instance of App by calling App.init(allocator, "Your app name", "optional description")
. This function internally creates a root command for your application.
var app = App.init(allocator, "myls", "My custom ls"); defer app.deinit();Obtaining the Root Command
The App itself does not provide any methods for adding arguments to your command. Its main purpose is to initialize the library, to invoke the parser with necessary arguments, and to deinitilize the library.
To add arguments and subcommands, acquire the root command by calling App.rootCommand()
. This gives you access to the core command of your application by returning a pointer to it.
var myls = app.rootCommand();
Once you have obtained the root command, you can proceed to add arguments and subcommands using the methods available in the Command
. For a complete list of available methods, refer to the Command API documentation.
try myls.addArg(Arg.positional("FILE", null, null)); try myls.addArg(Arg.booleanOption("all", 'a', "Don't ignore the hidden directories")); try myls.addArg(Arg.booleanOption("recursive", 'R', "List subdirectories recursively")); try myls.addArg(Arg.booleanOption("one-line", '1', null)); try myls.addArg(Arg.booleanOption("size", 's', null)); try myls.addArg(Arg.booleanOption("version", null, null)); try myls.addArg(Arg.singleValueOption("ignore", 'I', null)); try myls.addArg(Arg.singleValueOption("hide", null, null)); try myls.addArg(Arg.singleValueOptionWithValidValues( "color", 'C', "Colorize the output", &[_][]const u8{ "always", "auto", "never" } ));
Alternatively, you can add multiple arguments in a single function call using Command.addArgs()
:
try myls.addArgs(&[_]Arg { Arg.positional("FILE", null, null), Arg.booleanOption("all", 'a', "Don't ignore the hidden directories"), Arg.booleanOption("recursive", 'R', "List subdirectories recursively"), Arg.booleanOption("one-line", '1', null), Arg.booleanOption("size", 's', null), Arg.booleanOption("version", null, null), Arg.singleValueOption("ignore", 'I', null), Arg.singleValueOption("hide", null, null), Arg.singleValueOptionWithValidValues( "color", 'C', "Colorize the output", &[_][]const u8{ "always", "auto", "never" } ), });
Note that for any option that accepts value, you can set its value placeholder to display in the help message. If you don't set the placeholder, the option name will be displayed by default.
var ignore_opt = Arg.singleValueOption("ignore", 'I', null); ignore_opt.setValuePlaceholder("PATTERN"); var hide_opt = Arg.singleValueOption("hide", null, null); hide_opt.setValuesPlaceholder("PATTERN"); var color_opt = Arg.singleValueOptionWithValidValues( "color", 'C', "Colorize the output", &[_][]const u8{ "always", "auto", "never" } ); color_opt.setValuePlaceholder("WHEN"); try myls.addArgs(&[_]Arg{ ignore_opt, hide_opt, color_opt });
To create a subcommand, use App.createCommand("name", "optional description")
then you can add its own arguments and subcommands just like the root command. After you finish adding arguments, add it as a root subcommand by calling Command.addSubcommand()
.
var update_cmd = app.createCommand("update", "Update the app or check for new updates"); try update_cmd.addArg(Arg.booleanOption("check-only", null, "Only check for new update")); try update_cmd.addArg(Arg.singleValueOptionWithValidValues( "branch", 'b', "Branch to update", &[_][]const u8{ "stable", "nightly", "beta" } )); try myls.addSubcommand(update_cmd);
Once you have finished adding all the arguments and subcommands, call App.parseProcess()
to start parsing the arguments given to the current process. This function internally utilizes std.process.argsAlloc
to obtain the raw arguments. Alternatively, you can use App.parseFrom()
and pass your own raw arguments, which can be useful during testing. Both functions returns ArgMatches
.
const matches = try app.parseProcess(); if (matches.containsArg("version")) { log.info("v0.1.0", .{}); return; } if (matches.getSingleValue("FILE")) |f| { log.info("List contents of {f}"); return; } if (matches.subcommandMatches("update")) |update_cmd_matches| { if (update_cmd_matches.containsArg("check-only")) { std.log.info("Check and report new update", .{}); return; } if (update_cmd_matches.getSingleValue("branch")) |branch| { std.log.info("Branch to update: {s}", .{branch}); return; } return; } if (matches.containsArg("all")) { log.info("show all", .{}); return; } if (matches.containsArg("recursive")) { log.info("show recursive", .{}); return; } if (matches.getSingleValue("ignore")) |pattern| { log.info("ignore pattern = {s}", .{pattern}); return; } if (matches.containsArg("color")) { const when = matches.getSingleValue("color").?; log.info("color={s}", .{when}); return; }
-h
and --h
flag is globally available to all the commands and subcommands and handled automatically when they are passed to command line. However, if you need to manually display the help message there are currently two ways to do it.
App.displayHelp()
and App.displaySubcommandHelp()
.
App.displayHelp()
displays the help message for the root command and other hand App.displaySubcommandHelp()
displays the help message for the active subcommand.
For e.x.: if gh auth login
were passed then App.displayHelp()
would display the help for gh
and App.displaySubcommandHelp()
display the help for login
.
Example:
if (!matches.containsArgs()) { try app.displayHelp(); return; } if (matches.subcommandMatches("update")) |update_cmd_matches| { if (!update_cmd_matches.containsArgs()) { try app.displaySubcommandHelp(); return; } }2. By setting
.help_on_empty_args
property to the command.
The .help_on_empty_args
property which when set to a command, it instructs the handler to display the help message for that particular command when arguments are not provided. It behaves exactly like the code shown at the example above.
Example:
var app = App.init(allocator, "myls", "My custom ls"); defer app.deinit(); var myls = app.rootCommand(); myls.setProperty(.help_on_empty_args); var update_cmd = app.createCommand("update", "Update the app or check for new updates"); update_cmd.setProperty(.help_on_empty_args); try myls.addSubcommand(update_cmd); const matches = try myls.parseProcess(); // --snip--
const std = @import("std"); const yazap = @import("yazap"); const allocator = std.heap.page_allocator; const log = std.log; const App = yazap.App; const Arg = yazap.Arg; pub fn main() anyerror!void { var app = App.init(allocator, "myls", "My custom ls"); defer app.deinit(); var myls = app.rootCommand(); myls.setProperty(.help_on_empty_args); try myls.addArgs(&[_]Arg { Arg.positional("FILE", null, null), Arg.booleanOption("all", 'a', "Don't ignore the hidden directories"), Arg.booleanOption("recursive", 'R', "List subdirectories recursively"), Arg.booleanOption("one-line", '1', null), Arg.booleanOption("size", 's', null), Arg.booleanOption("version", null, null), }); var ignore_opt = Arg.singleValueOption("ignore", 'I', null); ignore_opt.setValuePlaceholder("PATTERN"); var hide_opt = Arg.singleValueOption("hide", null, null); hide_opt.setValuesPlaceholder("PATTERN"); var color_opt = Arg.singleValueOptionWithValidValues( "color", 'C', "Colorize the output", &[_][]const u8{ "always", "auto", "never" } ); color_opt.setValuePlaceholder("WHEN"); try myls.addArgs(&[_]Arg{ ignore_opt, hide_opt, color_opt }); // Update subcommand. var update_cmd = app.createCommand("update", "Update the app or check for new updates"); update_cmd.setProperty(.help_on_empty_args); try update_cmd.addArg(Arg.booleanOption("check-only", null, "Only check for new update")); try update_cmd.addArg(Arg.singleValueOptionWithValidValues( "branch", 'b', "Branch to update", &[_][]const u8{ "stable", "nightly", "beta" } )); try myls.addSubcommand(update_cmd); // Get the parse result. const matches = try app.parseProcess(); if (matches.containsArg("version")) { log.info("v0.1.0", .{}); return; } if (matches.getSingleValue("FILE")) |f| { log.info("List contents of {f}"); return; } if (matches.subcommandMatches("update")) |update_cmd_matches| { if (update_cmd_matches.containsArg("check-only")) { std.log.info("Check and report new update", .{}); return; } if (update_cmd_matches.getSingleValue("branch")) |branch| { std.log.info("Branch to update: {s}", .{branch}); return; } return; } if (matches.containsArg("all")) { log.info("show all", .{}); return; } if (matches.containsArg("recursive")) { log.info("show recursive", .{}); return; } if (matches.getSingleValue("ignore")) |pattern| { log.info("ignore pattern = {s}", .{pattern}); return; } if (matches.containsArg("color")) { const when = matches.getSingleValue("color").?; log.info("color={s}", .{when}); return; } }
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4