Skip to content
baskingspotPublic

About

Command-line flags for Zig, the getopt_long way: -xvf, --out=file, and a while loop.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

cli

Command-line flags for Zig, the getopt_long way: -xvf, --out=file, and a while loop.

Every command-line tool ends up with the same loop over argv. Writing it isn't hard. It's tedious, and the edges are where it goes wrong: -xvf is three flags, -ofile and -o file mean the same thing, --out=file splits on the first =, and after -- a token that starts with a dash is a path. cli handles those edges and hands you one token at a time. Which flags exist, what their values mean, and what the help text says stay in your code, where you can read them.

while (args.next()) |tok| switch (tok) {
    .positional => |path| try paths.append(arena, path),
    .option => |opt| {
        if (opt.is("output", 'o')) {
            output = args.takeValue(opt) orelse return 2;
        } else if (opt.isSwitch("verbose", 'v')) {
            verbose = true;
        } else return 2;
    },
};

cli.Args reads argv one token at a time and never builds an argv slice. On POSIX it allocates nothing. It writes nothing either: help text and error messages belong to the command.

What is in it

  • The cursor: Args.next() yields .positional or .option, and takeValue reads the value that goes with an option.
  • Grammar: --name, --name=value, -abc, -ovalue, and -o value. - is positional.
  • Short clusters: -lah and -vvvv, and a flag that takes the rest of its cluster as a value.
  • The separator: after --, every token is positional, even -weird-name.
  • Subcommands: an enum and a switch. cli.Args does not see them.
  • Values: strings at the boundary, and cli.parse for a primitive or a type's own parse.
  • Help and errors, input and output, tests, and patterns: the command writes the help text, the caller owns the writers, fromSlice tests a parse function, and fixed arity, repeated flags, and counters are short loops.

Not implemented:

  • Generated help, man pages, and shell completions: the command writes its own help text.
  • A typed flag table or derive: a new flag is one more if in the loop.
  • Long-option abbreviations, --no- negation, and a special -n=value form.

Install

zig fetch --save https://baskingspot.dev/cli/v0.3.1.tar.gz

Add the module to your build:

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

Args.init is the allocation-free POSIX constructor. Args.initAllocator is the portable form for Windows and WASI. Both capture the first argv token as args.program_name.

cli builds with Zig 0.16 and 0.17.

Documentation

  • The guide says how the cursor works and how to build a command around it, with examples that compile.
  • The API reference documents every symbol.
  • examples/ has a kitchen-sink program and five focused ones: git, ls, tar, verbose, and codec.

Work on it

just ci

nix develop provides the toolchain. just lists the recipes, and just ci runs what CI runs.

License

MIT. See LICENSE. The logo files in docs/static/ are baskingspot marks and are not covered by it. See docs/static/LICENSE.

How it's made

Built with LLM assistance. How, in detail.

baskingspot

About

Command-line flags for Zig, the getopt_long way: -xvf, --out=file, and a while loop.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages