Modules

Args

moduleSource
macOSLinuxWindowswasm

#import "Extensions/Args";

A typed, compile-time-generated command-line parser for jaic programs, in the spirit of Rust's clap derive. A jaic extension, not official Jai: other Jai compilers have no such module, and it may change between jaic releases. See docs/extensions/args.md.

ExampleOpen in playground ↗
Args :: #import "Extensions/Args";

Cli :: struct {
    paths: [..] string; @positional
    check: bool;       @short=c
    jobs:  int = 4;    @short=j @env=TOOL_JOBS @range(1,64)
}
HELP :: Args.Help(Cli).{ about = "Does things.", paths = "Files to read", check = "Only check", jobs = "Parallel jobs" };

main :: () {
    cli, set := Args.parse(Cli, HELP);  // --help, --version, errors (exit 2) are handled
    if set.jobs print("jobs: %\n", cli.jobs);  // set.<field> is true when the user supplied it
}
Show moreShow less

The fields of Cli are the options; notes (@short=c) refine them. At compile time the struct is read once and the parser is written out as plain Jai (see generate.jai), so the per-argument work is string comparisons and direct stores into the fields.

Procedures#

General#

($T: Type, $help: Help(T), argv: [] string, environment: [] string = .[]) -> (T, Error, Is_Set(T))

Parses argv (element 0 is the program name) into a T. Never prints and never exits. error.kind is .NONE on success; .HELP and .VERSION carry the text to print in error.text. On any error the returned struct holds what was parsed so far. environment holds "NAME=value" entries that win over the process environment when an @env option is looked up (for tests; leave it empty to read the real one).

Args :: #import "Extensions/Args";

Cli :: struct {
    paths: [..] string; @positional
    check: bool; @short=c
    jobs: int = 4; @short=j @env=TOOL_JOBS @range(1,64)
}
HELP :: Args.Help(Cli).{ about = "Does things.", paths = "Files to read", check = "Only check", jobs = "Parallel jobs" };

main :: () {
    cli, error, set := Args.try_parse(Cli, HELP, .["tool", "-c", "--jobs=8", "a.jai", "b.jai"]);
    assert(error.kind == .NONE);
    assert(cli.check && cli.jobs == 8 && cli.paths.count == 2 && cli.paths[1] == "b.jai");
    assert(set.jobs && set.check && set.paths);

    // The environment argument stands in for the process's own, and the option given on the line wins.
    cli, error, set = Args.try_parse(Cli, HELP, .["tool"], .["TOOL_JOBS=16"]);
    assert(error.kind == .NONE && cli.jobs == 16 && set.jobs);

    // A failure is returned, never printed: the kind says what went wrong, the message says it in words.
    cli, error, set = Args.try_parse(Cli, HELP, .["tool", "--jobs", "100"]);
    assert(error.kind != .NONE && error.message.count > 0);
    cli, error, set = Args.try_parse(Cli, HELP, .["tool", "--help"]);
    assert(error.kind == .HELP && error.text.count > 0);
}
↗
($T: Type, $help: Help(T)) -> (T, Is_Set(T))

Parses the process's arguments. --help and --version print and exit 0; a bad command line prints the error with a usage hint to stderr and exits 2.

($T: Type, $help: Help(T), shell: Shell, program := "") -> string

The completion script for shell, to be saved where that shell loads completions from. The program name is argv[0]'s basename unless program says otherwise.

($T: Type, $help: Help(T), program := "", color := false) -> string

The help text of the whole program (what --help prints), for tools that show it themselves.

Render#

(stream: Stream) -> bool

Whether output to stream should be coloured, by the colour mode and then the environment.

(error: Error)

Prints a parse error the way the compilers print theirs:

Types#

:: enum

Why parsing stopped. HELP and VERSION are not failures: error.text is what to print.

:: enum

Which terminals get colour in help and errors: AUTO follows NO_COLOR, FORCE_COLOR, CLICOLOR_FORCE, TERM and whether the stream is a terminal.

Helpstruct
:: struct

The help strings for T: about and version, then one string per option, named after the field. A subcommand's field holds that subcommand's own Help. A field not named in the literal has no help; that is a compile-time warning unless the field is @hidden.

Is_Setstruct
:: struct

One bool per field of T: true when the user supplied the option (on the command line or through its @env). A subcommand field holds the Is_Set of that subcommand's struct.