Argparse.Parser

A module for parsing arguments from the command line. With this you can turn the following

mycmd greet --overwrite file.txt

Into a data structure.

Application

type alias App result =
{ name : String
, version : String
, commands : GroupParser result
, intro : Document
, outro : Document
}

Defines a command line application.

  • name is the name of the application
  • version is the application version
  • commands is a group of commands that this application recognizes
  • intro and outro is used when the user calls the application without any arguments. They define what text comes before and after the list of supported commands.
run : Array String -> App result -> CommandParseResult result

Takes input from the user in the form of an Array of String, and parses it according to the given App definition.

runCommand :
String
-> Array String
-> Command args flags result
-> CommandParseResult result

Parses tokens against a single Command, without first consuming a command word. Use this to build a tool that has no sub-commands — just flags and arguments, like mytool --loud World — where run would otherwise treat the first token (--loud) as a command name.

appName is only used to render the usage line in --help output. The command word in --help comes from spec.word; pass an empty word for a rootless tool so the usage line reads mytool <args>. --help (and its alias -h) is handled here (it yields HelpText); --version, being application-level, is not — intercept it yourself, as Argparse.Program.runRoot does.

Command

type alias Command args flags result =
{ word : String
, arguments : ArgumentParser args
, flags : FlagParser flags
, commonDescription : Maybe String
, summary : String
, example : Document
, builder : args -> flags -> result
}

Definition of a command.

  • word — the sub-command word the user types (e.g. "add"todo add …).
  • arguments — the positional arguments this command accepts.
  • flags — the flags this command accepts.
  • commonDescription — if Just, a one-line description shown next to this command in the app-level --help listing. Pass Nothing to hide the command from that listing.
  • summary — a sentence or two shown at the top of this command's own --help page.
  • example — a usage example rendered below the summary on this command's --help page.
  • builder — converts the parsed arguments and flags into your own command type.
type CommandParseResult a
= UnknownCommand String
| BadFlags FlagParserError
| BadArguments ArgumentParserError
| HelpText Document
| Success a

The result of parsing user input.

Groups

type GroupParser result

A parser for a group, or collection, of commands. Build one with defineGroup, then pipe it through withCommand and withPrefix to register each command word:

commands : Argparse.Parser.GroupParser Command
commands =
    Argparse.Parser.defineGroup
        |> Argparse.Parser.withCommand addCommand    -- word = "add"
        |> Argparse.Parser.withCommand listCommand   -- word = "list"
        |> Argparse.Parser.withPrefix "remote" remoteCommands

Given an app named "mytool", the resulting CLI accepts:

mytool add ...
mytool list
mytool remote ...

Pass the resulting GroupParser as the commands field of App.

defineGroup : GroupParser result

Defines an empty group of commands. To add commands to this group, you'll need to use withCommand and withPrefix.

withCommand :
Command args flags result
-> GroupParser result
-> GroupParser result

Returns a new group that contains the given command. If there are multiple commands in the group with the same word, then the last registered command wins.

Argparse.Parser.defineGroup
    |> Argparse.Parser.withCommand
        { word = "greet"
        , arguments = Argparse.Parser.oneArg { value = Argparse.Parser.stringParser, help = "Name to greet" }
        , flags = Argparse.Parser.noFlags
        , commonDescription = Just "Say hello."
        , summary = "The `greet` command prints a greeting:"
        , example = PP.words "mytool greet Alice"
        , builder = \name _flags -> Greet name
        }

This makes mytool greet Alice a valid invocation.

withPrefix :
String
-> GroupParser result
-> GroupParser result
-> GroupParser result

Embeds a group of commands into an existing group, accessible by the given prefix.

remoteCommands : Argparse.Parser.GroupParser Command
remoteCommands =
    Argparse.Parser.defineGroup
        |> Argparse.Parser.withCommand addRemoteCommand    -- word = "add"
        |> Argparse.Parser.withCommand listRemoteCommand   -- word = "list"

Argparse.Parser.defineGroup
    |> Argparse.Parser.withPrefix "remote" remoteCommands

This makes mytool remote add ... and mytool remote list valid invocations. mytool remote --help lists the commands under the prefix.

Arguments

type alias ValueParser val =
{ label : String
, fn : String -> Maybe val
, examples : Array String
}

Defines how a raw string argument is converted to a typed value.

  • label — the placeholder name shown in usage lines, e.g. "count" renders as <count>
  • fn — converts the raw string to the target type; return Nothing to signal a parse failure
  • examples — one or more example values shown in --help output

For example, an integer parser:

intParser : Argparse.Parser.ValueParser Int
intParser =
    { label = "count"
    , fn = String.toInt
    , examples = [ "1", "10" ]
    }

-- mytool run --limit 5
Argparse.Parser.flag (Argparse.Parser.LongOnly "limit") intParser "Maximum number of items"
type alias Arg val = { value : ValueParser val, help : String }

A single positional argument: a ValueParser plus a help string describing what the argument means. The help is shown, per argument, in the command's --help output.

type ArgumentParser val

Arguments are values that a Command requires to function. An ArgumentParser is a way of converting an arbitrary number of String inputs into Gren values.

type ArgumentParserError
= ArgumentParserWrongArity ({ expected : Int, actual : Int })
| ArgumentParserInvalidArgument ({ argument : String, title : String, examples : Array String })

There are mainly two things that can go wrong when parsing arguments. You can either get an unexpected number of arguments or one or more of those arguments may fail to parse.

argumentErrorPrettified : ArgumentParserError -> Document

Turns an ArgumentParserError into a prettified String.

noArgs : ArgumentParser {}

Some Commands doesn't require arguments. This parser checks that exactly 0 arguments were provided.

oneArg : Arg val -> ArgumentParser val

Parses exactly one argument.

twoArgs : (a -> b -> c) -> Arg a -> Arg b -> ArgumentParser c

Parses exactly two arguments.

threeArgs :
(a -> b -> c -> d)
-> Arg a
-> Arg b
-> Arg c
-> ArgumentParser d

Parses exactly three arguments.

zeroOrMoreArgs : Arg val -> ArgumentParser (Array val)

Parses zero or more arguments of a single type.

oneOrMoreArgs : Arg val -> ArgumentParser (Array val)

Parses one or more arguments of a single type. Like zeroOrMoreArgs, but fails if no arguments are given.

optionalArg : Arg val -> ArgumentParser (Maybe val)

Parses an optional single argument: zero arguments yields Nothing, exactly one yields Just the parsed value, and anything more is an error.

mapArgs : (a -> b) -> ArgumentParser a -> ArgumentParser b

Maps a successfully parsed set of arguments into something else.

oneOfArgs : Array (ArgumentParser val) -> ArgumentParser val

A list of parsers that will be tried one after another until one succeeds.

Flags

type FlagParser val

Flags are prefixed with -- and are meant to customize a command. Build a FlagParser by seeding initFlags with a record constructor, then chaining toggle and flag:

type alias MyFlags =
    { verbose : Bool
    , output : Maybe Path
    }

myFlags : Argparse.Parser.FlagParser MyFlags
myFlags =
    Argparse.Parser.initFlags (\verbose output -> { verbose = verbose, output = output })
        |> Argparse.Parser.toggle
            (Argparse.Parser.Both { long = "verbose", short = "v" })
            "Show detailed output"
        |> Argparse.Parser.flag
            (Argparse.Parser.LongOnly "output")
            Argparse.Parser.pathParser
            "Write output to this file"

This accepts --verbose (or -v) and --output <path>:

mytool run --verbose --output build/result.txt
type FlagName
= LongOnly String
| ShortOnly String
| Both ({ long : String, short : String })

The name(s) by which a flag is known on the command line. A flag may have a long form (--verbose), a short form (-v), or both. At least one must be provided when calling toggle or flag.

type FlagParserError
= FlagParserFoundValueOnToggle ({ knownFlags : KnownFlags, flagName : String })
| FlagParserMissingValue ({ knownFlags : KnownFlags, flagName : String })
| FlagParserInvalidValue ({ knownFlags : KnownFlags, flagName : String })
| FlagParserUnknownFlag ({ knownFlags : KnownFlags, flagName : String })

There are several things that can go wrong when parsing flags:

  • The parser can find an associated value for a flag that requires none.
  • The parser might not find an associated value for a flag that does require one.
  • The associated value might fail to parse.
  • The flag might be unknown.
flagErrorPrettified : FlagParserError -> Document

Returns a prettified error message for the given FlagParserError.

noFlags : FlagParser {}

A parser that verifies that no flags have been provided.

initFlags : a -> FlagParser a

Defines an empty group of flags. You'll need to register flags using the toggle and flag functions.

toggle :
FlagName
-> String
-> FlagParser (Bool -> b)
-> FlagParser b

Defines a flag that doesn't require an associated value. We're simply checking if the flag is present or not.

flag :
FlagName
-> ValueParser a
-> String
-> FlagParser (Maybe a -> b)
-> FlagParser b

Defines a flag that requires an associated value.

Common parsers

pathParser : ValueParser Path

For FileSystem.Path, like /some/path/file.txt.

Note: expects posix paths.

stringParser : ValueParser String

For any plain String value.

intParser : ValueParser Int

For any Int value.