std/cli

Command lines: a program with several commands, flags, options and positional arguments, its help text and its errors, declared once. It is the standard library's answer to Rust's clap.

const cli = command "greet" {
  description "Greets people"
  flag "shout", help: "Write the greeting in capitals"
  option<Int>("times", help: "How often", default: 1)
  arguments "names", help: "Who to greet"
  run { input =>
    for name in input.arguments("names") {
      print "Hello, {name}"
    }
  }
}

cli.run Process.arguments()

There are no annotations and no reflection in the language, so the declaration is a builder on receiver closures, the same means project.trb uses. Nothing is registered by scanning: a subcommand is part of the tree because a command block names it.

The help text and the errors are generated. --help and -h print the help text of the command the line chose, help followed by the names of a command prints that one, and a wrong line ends with a message that names the command and the argument (CliError) and exit code 2.

The package is pure except for Command.run. Command.parse reads a list of strings and answers a Parsed or a CliError; Command.help answers the help text. A test hands them argument lists and compares what comes back.

Options are typed. option<Int>("jobs", default: 4) is read as input.option<Int>("jobs"). Int, Float64, Bool and String are Arguments, and a type of the program joins them with an extend.

Options may be optional or repeatable, and a command may pass its arguments on. optional<Path>("output") is read as input.optional<Path>("output"), a Path?; repeatable<String>("filter") as input.repeated<String>("filter"), a list in the order of the line; arguments("rest", passthrough: true) collects the first positional argument and everything behind it, flags too, for a command that hands them to another program.

Modules

Everything