Home

Awesome

<!-- LOGO --> <p align="center"> <a href="https://github.com/robik/commandr"> <img src="images/logo.png" alt="Logo" width="80" height="80"> </a> <h2 align="center">commandr</h2> <p align="center"> A modern, powerful commmand line argument parser. <br> Batteries included. <br /> <br /> <!-- <a href="https://robik.github.io/commandr/"><strong>๐Ÿ“— Explore the docs ยป</strong></a> --> <br /> <a href="https://github.com/robik/commandr/issues">โ—๏ธ Report a bug</a> ยท <a href="https://github.com/robik/commandr/issues">๐Ÿ’ก Request feature</a> <br /> <br /> <img src="https://img.shields.io/dub/v/commandr?style=flat-square"> <img src="https://img.shields.io/github/issues/robik/commandr.svg?style=flat-square"> <img src="https://img.shields.io/github/license/robik/commandr.svg?style=flat-square"> <img src="https://img.shields.io/badge/language-D-red?style=flat-square"> <br /> </p> </p>

commandr handles all kinds of command-line arguments with a nice and clean interface.<br/> Comes with help generation, shell auto-complete scripts and validation.

Table of Contents

Preview

<p align="center"> <img src="./images/help.png"> </p>

Installation

Add this entry to your dub.json file:

  "dependencies": {
    ...
    "commandr": "~>0.1"
    ...
  }

FAQ

Features

Getting Started

Basic Usage

Simple example showing how to create a basic program and parse arguments:

import std.stdio;
import commandr;

void main(string[] args) {
    auto a = new Program("test", "1.0")
          .summary("Command line parser")
          .author("John Doe <me@foo.bar.com>")
          .add(new Flag("v", null, "turns on more verbose output")
              .name("verbose")
              .repeating)
          .add(new Option(null, "test", "some teeeest"))
          .add(new Argument("path", "Path to file to edit"))
          .parse(args);

      writeln("verbosity level", a.occurencesOf("verbose"));
      writeln("arg: ", a.arg("path"));
}

Subcommands

You can create subcommands in your program or command using .add. You can nest commands.

Adding subcommands adds a virtual required argument at the end to your program. This makes you unable to declare repeating or optional arguments (because you cannot have required argument past these).

Default command can be set with .defaultCommand(name) call after defining all commands.

After parsing, every subcommand gets its own ProgramArgs instance, forming a hierarchy. Nested args inherit arguments from parent, so that options defined higher in hierarchy are copied. ProgramArgs defines a helper method on, that allows to dispatch method on specified command.

auto args = new Program("test", "1.0")
      .add(new Flag("v", null, "turns on more verbose output")
          .name("verbose")
          .repeating)
      .add(new Command("greet")
          .add(new Argument("name", "name of person to greet")))
      .add(new Command("farewell")
          .add(new Argument("name", "name of person to say farewell")))
      .parse(args);

args
  .on("greet", (args) {
    // args.flag("verbose") works
    writefln("Hello %s!", args.arg("name"));
  })
  .on("farewell", (args) {
    writefln("Bye %s!", args.arg("name"));
  });

Delegate passed to on function receives ProgramArgs instance for that subcommand. Because it is also ProgramArgs, on chain can be nested, as in:

// assuming program has nested subcommands

a.on("branch", (args) {
  args
    .on("add", (args) {
      writefln("adding branch %s", args.arg("name"));
    })
    .on("rm", (args) {
      writefln("removing branch %s", args.arg("name"));
    });
});

Validation

You can attach one or more validators to options and arguments with validate method. Every validator has its own helper function that simplifies adding it do option (usually starting with accepts):

new Program("test")
  // adding validator manually
  .add(new Option("s", "scope", "")
      .validate(new EnumValidator(["local", "global", "system"]))
  )
  // helper functionnew Program("test")
  .add(new Option("s", "scope", "")
      .acceptsValues(["local", "global", "system"]));

Built-in validators

You can create custom validators either by implementing IValidator interface, or by using DelegateValidator:

new Program("test")
  // adding validator manually
  .add(new Option("s", "scope", "")
      .validateEachWith(opt => opt.isDirectory, "must be a valid directory")
  );

Printing help

You can print help for program or any subcommand with printHelp() function:

program.printHelp(); // prints program help
program.commands["test"].printHelp();

To customise help output, pass HelpOutput struct instance:

HelpOutput helpOptions;
helpOptions.colors = false;
helpOptions.optionsLimit = 2;

program.printHelp(helpOptions);

Bash autocompletion

Commandr can generate BASH autocompletion script. During installation of your program you can save the generated script to /etc/bash_completion.d/<programname>.bash (or any other path depending on distro).

import commandr;
import commandr.completion.bash;

string script = program.createBashCompletionScript();
// save script to file

Configuration

TODO

Cheat-Sheet

Defining entries

Overview of available entries that can be added to program or command with .add method:

WhatTypeExampleDefinition
Flagbool--verbosenew Flag(abbrev?, full?, summary?)
Optionstring[]--db=testnew Option(abbrev?, full?, summary?)
Argumentstring[]123new Argument(name, summary?)

Reading values

Shows how to access values after parsing args.

Examples assume args variable contains result of parse() or parseArgs() function calls (an instance of ProgramArgs)

ProgramArgs args = program.parse(args);
WhatTypeFetch
Flagboolargs.flag(name)
Flagintargs.occurencesOf(name)
Optionstringargs.option(name)
Optionstring[]args.options(name)
Argumentstringargs.arg(name)
Argumentstring[]args.args(name)

Property Matrix

<!-- :heavy_check_mark: โŒ -->

Table below shows which fields exist and which don't (or should not be used).

Column name contains name of the method to set the value. All methods return this to allow chaining.

NameProgramCommandFlagOptionArgument
.name:heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark::heavy_check_mark:
.version_:heavy_check_mark::heavy_check_mark:โŒ๏ธโŒโŒ
.summary:heavy_check_mark:๏ธ๏ธ:heavy_check_mark:โŒ๏ธโŒโŒ
.descriptionโŒ๏ธโŒ:heavy_check_mark:๏ธ:heavy_check_mark::heavy_check_mark:
.abbrevโŒโŒ:heavy_check_mark::heavy_check_mark:โŒ
.fullโŒโŒ:heavy_check_mark:๏ธ๏ธ:heavy_check_mark:โŒ
.tagโŒโŒโŒ๏ธ:heavy_check_mark::heavy_check_mark:๏ธ
.defaultValueโŒโŒโŒ๏ธ:heavy_check_mark::heavy_check_mark:๏ธ
.requiredโŒโŒโŒ๏ธ:heavy_check_mark::heavy_check_mark:๏ธ
.optionalโŒโŒโŒ๏ธ:heavy_check_mark::heavy_check_mark:๏ธ
.repeatingโŒโŒ:heavy_check_mark:๏ธ:heavy_check_mark::heavy_check_mark:๏ธ
.topicโŒ:heavy_check_mark:โŒ๏ธโŒโŒ
.topicGroup:heavy_check_mark::heavy_check_mark:โŒ๏ธโŒโŒ
.authors:heavy_check_mark:โŒโŒ๏ธโŒโŒ
.binaryName:heavy_check_mark:โŒโŒ๏ธโŒโŒ

Roadmap

Current major missing features are:

See the open issues for a list of proposed features (and known issues).