|
Packit |
3fa651 |
# optparse-applicative
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
[![Continuous Integration status][status-png]][status]
|
|
Packit |
3fa651 |
[![Hackage page (downloads and API reference)][hackage-png]][hackage]
|
|
Packit |
3fa651 |
[![Hackage-Deps][hackage-deps-png]][hackage-deps]
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
optparse-applicative is a haskell library for parsing options on
|
|
Packit |
3fa651 |
the command line, providing a powerful [applicative] interface
|
|
Packit |
3fa651 |
for composing these options.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
optparse-applicative takes care of reading and validating the
|
|
Packit |
3fa651 |
arguments passed to the command line, handling and reporting errors,
|
|
Packit |
3fa651 |
generating a usage line, a comprehensive help screen, and enabling
|
|
Packit |
3fa651 |
context-sensitive bash completions.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
**Table of Contents**
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
- [Introduction](#introduction)
|
|
Packit |
3fa651 |
- [Quick Start](#quick-start)
|
|
Packit |
3fa651 |
- [Basics](#basics)
|
|
Packit |
3fa651 |
- [Parsers](#parsers)
|
|
Packit |
3fa651 |
- [Applicative](#applicative)
|
|
Packit |
3fa651 |
- [Alternative](#alternative)
|
|
Packit |
3fa651 |
- [Running parsers](#running-parsers)
|
|
Packit |
3fa651 |
- [Builders](#builders)
|
|
Packit |
3fa651 |
- [Regular options](#regular-options)
|
|
Packit |
3fa651 |
- [Flags](#flags)
|
|
Packit |
3fa651 |
- [Arguments](#arguments)
|
|
Packit |
3fa651 |
- [Commands](#commands)
|
|
Packit |
3fa651 |
- [Modifiers](#modifiers)
|
|
Packit |
3fa651 |
- [Custom parsing and error handling](#custom-parsing-and-error-handling)
|
|
Packit |
3fa651 |
- [Parser runners](#parser-runners)
|
|
Packit |
3fa651 |
- [Option readers](#option-readers)
|
|
Packit |
3fa651 |
- [Preferences](#preferences)
|
|
Packit |
3fa651 |
- [Disambiguation](#disambiguation)
|
|
Packit |
3fa651 |
- [Customising the help screen](#customising-the-help-screen)
|
|
Packit |
3fa651 |
- [Command Groups](#command-groups)
|
|
Packit |
3fa651 |
- [Bash completion](#bash-completion)
|
|
Packit |
3fa651 |
- [Actions and completers](#actions-and-completers)
|
|
Packit |
3fa651 |
- [Internals](#internals)
|
|
Packit |
3fa651 |
- [Arrow interface](#arrow-interface)
|
|
Packit |
3fa651 |
- [Applicative Do](#applicative-do)
|
|
Packit |
3fa651 |
- [FAQ](#faq)
|
|
Packit |
3fa651 |
- [How it works](#how-it-works)
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
## Introduction
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The core type in optparse-applicative is a `Parser`
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
data Parser a
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
instance Functor Parser
|
|
Packit |
3fa651 |
instance Applicative Parser
|
|
Packit |
3fa651 |
instance Alternative Parser
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
A value of type `Parser a` represents a specification for a set of
|
|
Packit |
3fa651 |
options, which will yield a value of type `a` when the command line
|
|
Packit |
3fa651 |
arguments are successfully parsed.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
If you are familiar with parser combinator libraries like [parsec],
|
|
Packit |
3fa651 |
[attoparsec], or the json parser [aeson] you will feel right at
|
|
Packit |
3fa651 |
home with optparse-applicative.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
If not, don't worry! All you really need to learn are a few basic
|
|
Packit |
3fa651 |
parsers, and how to compose them as instances of `Applicative` and
|
|
Packit |
3fa651 |
`Alternative`.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
## Quick Start
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Here's a simple example of a parser.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
import Options.Applicative
|
|
Packit |
3fa651 |
import Data.Semigroup ((<>))
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
data Sample = Sample
|
|
Packit |
3fa651 |
{ hello :: String
|
|
Packit |
3fa651 |
, quiet :: Bool
|
|
Packit |
3fa651 |
, enthusiasm :: Int }
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
sample :: Parser Sample
|
|
Packit |
3fa651 |
sample = Sample
|
|
Packit |
3fa651 |
<$> strOption
|
|
Packit |
3fa651 |
( long "hello"
|
|
Packit |
3fa651 |
<> metavar "TARGET"
|
|
Packit |
3fa651 |
<> help "Target for the greeting" )
|
|
Packit |
3fa651 |
<*> switch
|
|
Packit |
3fa651 |
( long "quiet"
|
|
Packit |
3fa651 |
<> short 'q'
|
|
Packit |
3fa651 |
<> help "Whether to be quiet" )
|
|
Packit |
3fa651 |
<*> option auto
|
|
Packit |
3fa651 |
( long "enthusiasm"
|
|
Packit |
3fa651 |
<> help "How enthusiastically to greet"
|
|
Packit |
3fa651 |
<> showDefault
|
|
Packit |
3fa651 |
<> value 1
|
|
Packit |
3fa651 |
<> metavar "INT" )
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The parser is built using an [applicative] style starting from a
|
|
Packit |
3fa651 |
set of basic combinators. In this example, hello is defined as an
|
|
Packit |
3fa651 |
option with a `String` argument, while quiet is a boolean flag
|
|
Packit |
3fa651 |
(called a switch) and enthusiasm gets parsed as an `Int` with help
|
|
Packit |
3fa651 |
of the `Read` type class.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The parser can be used like this:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
main :: IO ()
|
|
Packit |
3fa651 |
main = greet =<< execParser opts
|
|
Packit |
3fa651 |
where
|
|
Packit |
3fa651 |
opts = info (sample <**> helper)
|
|
Packit |
3fa651 |
( fullDesc
|
|
Packit |
3fa651 |
<> progDesc "Print a greeting for TARGET"
|
|
Packit |
3fa651 |
<> header "hello - a test for optparse-applicative" )
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
greet :: Sample -> IO ()
|
|
Packit |
3fa651 |
greet (Sample h False n) = putStrLn $ "Hello, " ++ h ++ replicate n '!'
|
|
Packit |
3fa651 |
greet _ = return ()
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The `greet` function is the entry point of the program, while `opts`
|
|
Packit |
3fa651 |
is a complete description of the program, used when generating a
|
|
Packit |
3fa651 |
help text. The `helper` combinator takes any parser, and adds a
|
|
Packit |
3fa651 |
`help` option to it.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The `hello` option in this example is mandatory since it doesn't
|
|
Packit |
3fa651 |
have a default value, so running the program without any argument
|
|
Packit |
3fa651 |
will display an appropriate error message and a short option summary:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Missing: --hello TARGET
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Usage: hello --hello TARGET [-q|--quiet] [--enthusiasm INT]
|
|
Packit |
3fa651 |
Print a greeting for TARGET
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Running the program with the `--help` option will display the full help text
|
|
Packit |
3fa651 |
containing a detailed list of options with descriptions
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
hello - a test for optparse-applicative
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Usage: hello --hello TARGET [-q|--quiet] [--enthusiasm INT]
|
|
Packit |
3fa651 |
Print a greeting for TARGET
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Available options:
|
|
Packit |
3fa651 |
--hello TARGET Target for the greeting
|
|
Packit |
3fa651 |
-q,--quiet Whether to be quiet
|
|
Packit |
3fa651 |
--enthusiasm INT How enthusiastically to greet (default: 1)
|
|
Packit |
3fa651 |
-h,--help Show this help text
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
## Basics
|
|
Packit |
3fa651 |
### Parsers
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
optparse-applicative provides a number of primitive parsers,
|
|
Packit |
3fa651 |
corresponding to different posix style options, through its *Builder*
|
|
Packit |
3fa651 |
interface. These are detailed in their [own section](#builders)
|
|
Packit |
3fa651 |
below, for now, here's a look at a few more examples to get a feel
|
|
Packit |
3fa651 |
for how parsers can be defined.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Here is a parser for a mandatory option with an argument:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
target :: Parser String
|
|
Packit |
3fa651 |
target = strOption
|
|
Packit |
3fa651 |
( long "hello"
|
|
Packit |
3fa651 |
<> metavar "TARGET"
|
|
Packit |
3fa651 |
<> help "Target for the greeting" )
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
One can see that we are defining an option parser for a `String`
|
|
Packit |
3fa651 |
argument, with *long* option name "hello", *metavariable* "TARGET",
|
|
Packit |
3fa651 |
and the given help text. This means that the `target` parser defined
|
|
Packit |
3fa651 |
above will require an option like
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
--hello world
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
on the command line. The metavariable and the help text will appear
|
|
Packit |
3fa651 |
in the generated help text, but don't otherwise affect the behaviour
|
|
Packit |
3fa651 |
of the parser.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The attributes passed to the option are called *modifiers*, and are
|
|
Packit |
3fa651 |
composed using the [semigroup] operation `(<>)`.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Options with an argument such as `target` are referred to as *regular
|
|
Packit |
3fa651 |
options*, and are very common. Another type of option is a *flag*,
|
|
Packit |
3fa651 |
the simplest of which is a boolean *switch*, for example:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
quiet :: Parser Bool
|
|
Packit |
3fa651 |
quiet = switch ( long "quiet" <> short 'q' <> help "Whether to be quiet" )
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Here we used a `short` modifier to specify a one-letter name for
|
|
Packit |
3fa651 |
the option. This means that this switch can be set either with
|
|
Packit |
3fa651 |
`--quiet` or `-q`.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Flags, unlike regular options, have no arguments. They simply return
|
|
Packit |
3fa651 |
a predetermined value. For the simple switch above, this is `True`
|
|
Packit |
3fa651 |
if the user types the flag, and `False` otherwise.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
There are other kinds of basic parsers, and several ways to configure
|
|
Packit |
3fa651 |
them. These are covered in the [Builders](#builders) section.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Applicative
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Now we may combine the `target` and `quiet` into a single parser that
|
|
Packit |
3fa651 |
accepts both options and returns a combined value. Given a type
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
data Options = Options
|
|
Packit |
3fa651 |
{ optTarget :: String
|
|
Packit |
3fa651 |
, optQuiet :: Bool }
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
and now it's just a matter of using `Applicative`'s apply operator `(<*>)`
|
|
Packit |
3fa651 |
to combine the two previously defined parsers
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
opts :: Parser Options
|
|
Packit |
3fa651 |
opts = Options <$> target <*> quiet
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
No matter which parsers appear first in the sequence, options will
|
|
Packit |
3fa651 |
still be parsed in whatever order they appear in the command line.
|
|
Packit |
3fa651 |
A parser with such a property is sometimes called a *permutation
|
|
Packit |
3fa651 |
parser*.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
In our example, a command line like:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
--target world -q
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
will give the same result as
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
-q --target world
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
It is this property which leads us to an Applicative interface
|
|
Packit |
3fa651 |
instead of a Monadic one, as all option must be considered in
|
|
Packit |
3fa651 |
parallel, and can not depend on the output of other options.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Note, however, that the order of sequencing is still somewhat
|
|
Packit |
3fa651 |
significant, in that it affects the generated help text. Customisation
|
|
Packit |
3fa651 |
can be achieved easily through a lambda abstraction, with [Arrow
|
|
Packit |
3fa651 |
notation](#arrow-interface), or by taking advantage of GHC 8's
|
|
Packit |
3fa651 |
[ApplicativeDo](#applicative-do) extension.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Alternative
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
It is also common to find programs that can be configured in different
|
|
Packit |
3fa651 |
ways through the command line. A typical example is a program that
|
|
Packit |
3fa651 |
can be given a text file as input, or alternatively read it directly
|
|
Packit |
3fa651 |
from the standard input.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
We can model this easily and effectively in Haskell using *sum types*:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
data Input
|
|
Packit |
3fa651 |
= FileInput FilePath
|
|
Packit |
3fa651 |
| StdInput
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
run :: Input -> IO ()
|
|
Packit |
3fa651 |
run = ...
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
We can now define two basic parsers for the components of the sum type:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
fileInput :: Parser Input
|
|
Packit |
3fa651 |
fileInput = FileInput <$> strOption
|
|
Packit |
3fa651 |
( long "file"
|
|
Packit |
3fa651 |
<> short 'f'
|
|
Packit |
3fa651 |
<> metavar "FILENAME"
|
|
Packit |
3fa651 |
<> help "Input file" )
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
stdInput :: Parser Input
|
|
Packit |
3fa651 |
stdInput = flag' StdInput
|
|
Packit |
3fa651 |
( long "stdin"
|
|
Packit |
3fa651 |
<> help "Read from stdin" )
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
As the `Parser` type constructor is an instance of `Alternative`, we can
|
|
Packit |
3fa651 |
compose these parsers with a choice operator `(<|>)`
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
input :: Parser Input
|
|
Packit |
3fa651 |
input = fileInput <|> stdInput
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Now `--file "foo.txt"` will be parsed as `FileInput "foo.txt"`, `--stdin`
|
|
Packit |
3fa651 |
will be parsed as `StdInput`, but a command line containing both options,
|
|
Packit |
3fa651 |
like
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
--file "foo.txt" --stdin
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
will be rejected.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Having `Applicative` and `Alternative` instances, optparse-applicative
|
|
Packit |
3fa651 |
parsers are also able to be composed with standard combinators. For
|
|
Packit |
3fa651 |
example: `optional :: Alternative f => f a -> f (Maybe a)` will
|
|
Packit |
3fa651 |
mean the user is not required to provide input for the affected
|
|
Packit |
3fa651 |
`Parser`.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Running parsers
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Before we can run a `Parser`, we need to wrap it into a `ParserInfo`
|
|
Packit |
3fa651 |
structure, that specifies a number of properties that only apply
|
|
Packit |
3fa651 |
to top level parsers, such as a header describing what the program
|
|
Packit |
3fa651 |
does, to be displayed in the help screen.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The function `info` will help with this step. In the [Quick Start](#quick-start)
|
|
Packit |
3fa651 |
we saw
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
opts :: ParserInfo Sample
|
|
Packit |
3fa651 |
opts = info (sample <**> helper)
|
|
Packit |
3fa651 |
( fullDesc
|
|
Packit |
3fa651 |
<> progDesc "Print a greeting for TARGET"
|
|
Packit |
3fa651 |
<> header "hello - a test for optparse-applicative" )
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The `helper` parser that we added after `opts` just creates a dummy
|
|
Packit |
3fa651 |
`--help` option that displays the help text. Besides that, we just
|
|
Packit |
3fa651 |
set some of the fields of the `ParserInfo` structure with meaningful
|
|
Packit |
3fa651 |
values. Now that we have a `ParserInfo`, we can finally run the
|
|
Packit |
3fa651 |
parser. The simplest way to do so is to simply call the `execParser`
|
|
Packit |
3fa651 |
function in your `main`:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
main :: IO ()
|
|
Packit |
3fa651 |
main = do
|
|
Packit |
3fa651 |
options <- execParser opts
|
|
Packit |
3fa651 |
...
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The `execParser` function takes care of everything, including getting
|
|
Packit |
3fa651 |
the arguments from the command line, displaying errors and help
|
|
Packit |
3fa651 |
screens to the user, and exiting with an appropriate exit code.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
There are other ways to run a `ParserInfo`, in situations where you
|
|
Packit |
3fa651 |
need finer control over the behaviour of your parser, or if you
|
|
Packit |
3fa651 |
want to use it in pure code. They will be covered in [Custom parsing
|
|
Packit |
3fa651 |
and error handling](#custom-parsing-and-error-handling).
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
## Builders
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Builders allow you to define parsers using a convenient combinator-based
|
|
Packit |
3fa651 |
syntax. We have already seen examples of builders in action, like
|
|
Packit |
3fa651 |
`strOption` and `switch`, which we used to define the `opts` parser
|
|
Packit |
3fa651 |
for our "hello" example.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Builders always take a [modifier](#modifiers) argument, which is
|
|
Packit |
3fa651 |
essentially a composition of functions acting on the option, setting
|
|
Packit |
3fa651 |
values for properties or adding features.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Builders work by building the option from scratch, and eventually
|
|
Packit |
3fa651 |
lifting it to a single-option parser, ready to be combined with
|
|
Packit |
3fa651 |
other parsers using normal `Applicative` and `Alternative` combinators.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
See the [haddock documentation][hackage] for `Options.Applicative.Builder`
|
|
Packit |
3fa651 |
for a full list of builders and modifiers.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
There are four different kinds of options in `optparse-applicative`:
|
|
Packit |
3fa651 |
regular options, flags, arguments, and commands. In the following,
|
|
Packit |
3fa651 |
we will go over each one of these and describe the builders that
|
|
Packit |
3fa651 |
can be used to create them.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Regular options
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
A *regular option* is an option which takes a single argument,
|
|
Packit |
3fa651 |
parses it, and returns a value.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
A regular option can have a default value, which is used as the
|
|
Packit |
3fa651 |
result if the option is not found in the command line. An option
|
|
Packit |
3fa651 |
without a default value is considered mandatory, and produces an
|
|
Packit |
3fa651 |
error when not found.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Regular options can have *long* names, or *short* (one-character)
|
|
Packit |
3fa651 |
names, which determine when the option matches and how the argument
|
|
Packit |
3fa651 |
is extracted.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
An option with a long name (say "output") is specified on the command
|
|
Packit |
3fa651 |
line as
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
--output filename.txt
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
or
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
--output=filename.txt
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
while a short name option (say "o") can be specified with
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
-o filename.txt
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
or
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
-ofilename.txt
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Options can have more than one name, usually one long and one short,
|
|
Packit |
3fa651 |
although you are free to create options with an arbitrary combination
|
|
Packit |
3fa651 |
of long and short names.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Regular options returning strings are the most common, and they can
|
|
Packit |
3fa651 |
be created using the `strOption` builder. For example,
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
strOption
|
|
Packit |
3fa651 |
( long "output"
|
|
Packit |
3fa651 |
<> short 'o'
|
|
Packit |
3fa651 |
<> metavar "FILE"
|
|
Packit |
3fa651 |
<> value "out.txt"
|
|
Packit |
3fa651 |
<> help "Write output to FILE" )
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
creates a regular option with a string argument (which can be
|
|
Packit |
3fa651 |
referred to as `FILE` in the help text and documentation), default
|
|
Packit |
3fa651 |
value "out.txt", a long name "output" and a short name "o".
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
A regular `option` can return an object of any type, and takes a
|
|
Packit |
3fa651 |
*reader* parameter which specifies how the argument should be parsed.
|
|
Packit |
3fa651 |
A common reader is `auto`, which requires a `Read` instance for the
|
|
Packit |
3fa651 |
return type and uses it to parse its argument. For example:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
lineCount :: Parser Int
|
|
Packit |
3fa651 |
lineCount = option auto
|
|
Packit |
3fa651 |
( long "lines"
|
|
Packit |
3fa651 |
<> short 'n'
|
|
Packit |
3fa651 |
<> metavar "K"
|
|
Packit |
3fa651 |
<> help "Output the last K lines" )
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
specifies a regular option with an `Int` argument. We added an
|
|
Packit |
3fa651 |
explicit type annotation here, since without it the parser would
|
|
Packit |
3fa651 |
have been polymorphic in the output type. There's usually no need
|
|
Packit |
3fa651 |
to add type annotations, however, because the type will be normally
|
|
Packit |
3fa651 |
inferred from the context in which the parser is used.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Further information on *readers* is available [below](#option-readers).
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Flags
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
A *flag* is just like a regular option, but it doesn't take any
|
|
Packit |
3fa651 |
arguments, it is either present in the command line or not.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
A flag has a default value and an *active value*. If the flag is
|
|
Packit |
3fa651 |
found on the command line, the active value is returned, otherwise
|
|
Packit |
3fa651 |
the default value is used. For example:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
data Verbosity = Normal | Verbose
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
flag Normal Verbose
|
|
Packit |
3fa651 |
( long "verbose"
|
|
Packit |
3fa651 |
<> short 'v'
|
|
Packit |
3fa651 |
<> help "Enable verbose mode" )
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
is a flag parser returning a `Verbosity` value.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Simple boolean flags can be specified using the `switch` builder, like so:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
switch
|
|
Packit |
3fa651 |
( long "keep-tmp-files"
|
|
Packit |
3fa651 |
<> help "Retain all intermediate temporary files" )
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
There is also a `flag'` builder, which has no default value. This
|
|
Packit |
3fa651 |
was demonstrated earlier for our `--stdin` flag example, and is
|
|
Packit |
3fa651 |
usually used as one side of an alternative.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Another interesting use for the `flag'` builder is to count the
|
|
Packit |
3fa651 |
number of instances on the command line, for example, verbosity
|
|
Packit |
3fa651 |
settings could be specified on a scale; the following parser with
|
|
Packit |
3fa651 |
count the number of of instances of `-v` on the command line.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
length <$> many (flag' () (short 'v'))
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Flags can be used together after a single hyphen, so `-vvv` and
|
|
Packit |
3fa651 |
`-v -v -v` will both yield 3 for the above parser.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Arguments
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
An *argument* parser specifies a positional command line argument.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The `argument` builder takes a reader parameter, and creates a
|
|
Packit |
3fa651 |
parser which will return the parsed value every time it is passed
|
|
Packit |
3fa651 |
a command line argument for which the reader succeeds. For example
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
argument str (metavar "FILE")
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
creates an argument accepting any string. To accept an arbitrary
|
|
Packit |
3fa651 |
number of arguments, combine the `argument` builder with either the
|
|
Packit |
3fa651 |
`many` or `some` combinator:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
some (argument str (metavar "FILES..."))
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Note that arguments starting with `-` are considered options by
|
|
Packit |
3fa651 |
default, and will not be considered by an `argument` parser.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
However, parsers always accept a special argument: `--`. When a
|
|
Packit |
3fa651 |
`--` is found on the command line, all the following words are
|
|
Packit |
3fa651 |
considered by `argument` parsers, regardless of whether they start
|
|
Packit |
3fa651 |
with `-` or not.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Arguments use the same *readers* as regular options.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Commands
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
A *command* can be used to specify a sub-parser to be used when a
|
|
Packit |
3fa651 |
certain string is encountered in the command line.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Commands are useful to implement command line programs with multiple
|
|
Packit |
3fa651 |
functions, each with its own set of options, and possibly some
|
|
Packit |
3fa651 |
global options that apply to all of them. Typical examples are
|
|
Packit |
3fa651 |
version control systems like `git`, or build tools like `cabal`.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
A command can be created using the `subparser` builder (or `hsubparser`,
|
|
Packit |
3fa651 |
which is identical but for an additional `--help` option on each
|
|
Packit |
3fa651 |
command), and commands can be added with the `command` modifier.
|
|
Packit |
3fa651 |
For example
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
subparser
|
|
Packit |
3fa651 |
( command "add" (info addOptions ( progDesc "Add a file to the repository" ))
|
|
Packit |
3fa651 |
<> command "commit" (info commitOptions ( progDesc "Record changes to the repository" ))
|
|
Packit |
3fa651 |
)
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Each command takes a full `ParserInfo` structure, which will be
|
|
Packit |
3fa651 |
used to extract a description for this command when generating a
|
|
Packit |
3fa651 |
help text.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Note that all the parsers appearing in a command need to have the
|
|
Packit |
3fa651 |
same type. For this reason, it is often best to use a sum type
|
|
Packit |
3fa651 |
which has the same structure as the command itself. For example,
|
|
Packit |
3fa651 |
for the parser above, you would define a type like:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
data Options = Options
|
|
Packit |
3fa651 |
{ optCommand :: Command
|
|
Packit |
3fa651 |
, ... }
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
data Command
|
|
Packit |
3fa651 |
= Add AddOptions
|
|
Packit |
3fa651 |
| Commit CommitOptions
|
|
Packit |
3fa651 |
...
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Alternatively, you can directly return an `IO` action from a parser,
|
|
Packit |
3fa651 |
and execute it using `join` from `Control.Monad`.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
start :: String -> IO ()
|
|
Packit |
3fa651 |
stop :: IO ()
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
opts :: Parser (IO ())
|
|
Packit |
3fa651 |
opts = subparser
|
|
Packit |
3fa651 |
( command "start" (info (start <$> argument str idm) idm)
|
|
Packit |
3fa651 |
<> command "stop" (info (pure stop) idm) )
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
main :: IO ()
|
|
Packit |
3fa651 |
main = join $ execParser (info opts idm)
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Modifiers
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
*Modifiers* are instances of the `Semigroup` and `Monoid` typeclasses,
|
|
Packit |
3fa651 |
so they can be combined using the composition function `mappend`
|
|
Packit |
3fa651 |
(or simply `(<>)`). Since different builders accept different sets
|
|
Packit |
3fa651 |
of modifiers, modifiers have a type parameter that specifies which
|
|
Packit |
3fa651 |
builders support it.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
For example,
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
command :: String -> ParserInfo a -> Mod CommandFields a
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
can only be used with [commands](#commands), as the `CommandFields`
|
|
Packit |
3fa651 |
type argument of `Mod` will prevent it from being passed to builders
|
|
Packit |
3fa651 |
for other types of options.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Many modifiers are polymorphic in this type argument, which means
|
|
Packit |
3fa651 |
that they can be used with any builder.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
## Custom parsing and error handling
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Parser runners
|
|
Packit |
3fa651 |
Parsers are run with the `execParser` family of functions — from
|
|
Packit |
3fa651 |
easiest to use to most flexible these are:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
execParser :: ParserInfo a -> IO a
|
|
Packit |
3fa651 |
customExecParser :: ParserPrefs -> ParserInfo a -> IO a
|
|
Packit |
3fa651 |
execParserPure :: ParserPrefs -> ParserInfo a -> [String] -> ParserResult a
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
When using the `IO` functions, retrieving command line arguments
|
|
Packit |
3fa651 |
and handling exit codes and failure will be done automatically.
|
|
Packit |
3fa651 |
When using `execParserPure`, the functions
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
handleParseResult :: ParserResult a -> IO a
|
|
Packit |
3fa651 |
overFailure :: (ParserHelp -> ParserHelp) -> ParserResult a -> ParserResult a
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
can be used to correctly set exit codes and display the help message;
|
|
Packit |
3fa651 |
and modify the help message in the event of a failure (adding
|
|
Packit |
3fa651 |
additional information for example).
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Option readers
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Options and Arguments require a way to interpret the string passed
|
|
Packit |
3fa651 |
on the command line to the type desired. The `str` and `auto`
|
|
Packit |
3fa651 |
*readers* are the most common way, but one can also create a custom
|
|
Packit |
3fa651 |
reader that doesn't use the `Read` type class or return a `String`,
|
|
Packit |
3fa651 |
and use it to parse the option. A custom reader is a value in the
|
|
Packit |
3fa651 |
`ReadM` monad.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
We provide the `eitherReader :: (String -> Either String a) -> ReadM a`
|
|
Packit |
3fa651 |
convenience function to help create these values, where a `Left` will
|
|
Packit |
3fa651 |
hold the error message for a parse failure.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
data FluxCapacitor = ...
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
parseFluxCapacitor :: ReadM FluxCapacitor
|
|
Packit |
3fa651 |
parseFluxCapacitor = eitherReader $ \s -> ...
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
option parseFluxCapacitor ( long "flux-capacitor" )
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
One can also use `ReadM` directly, using `readerAsk` to obtain the
|
|
Packit |
3fa651 |
command line string, and `readerAbort` or `readerError` within the
|
|
Packit |
3fa651 |
`ReadM` monad to exit with an error message.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
One nice property of `eitherReader` is how well it composes with
|
|
Packit |
3fa651 |
[attoparsec] parsers with
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
import qualified Data.Attoparsec.Text as A
|
|
Packit |
3fa651 |
attoReadM :: A.Parser a -> ReadM a
|
|
Packit |
3fa651 |
attoReadM p = eitherReader (A.parseOnly p . T.pack)
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Preferences
|
|
Packit |
3fa651 |
`PrefsMod`s can be used to customise the look of the usage text and
|
|
Packit |
3fa651 |
control when it is displayed; turn off backtracking of subparsers;
|
|
Packit |
3fa651 |
and turn on [disambiguation](#disambiguation).
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
To use these modifications, provide them to the `prefs` builder,
|
|
Packit |
3fa651 |
and pass the resulting preferences to one of the parser runners
|
|
Packit |
3fa651 |
that take an `ParserPrefs` parameter, like `customExecParser`.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Disambiguation
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
It is possible to configure optparse-applicative to perform automatic
|
|
Packit |
3fa651 |
disambiguation of prefixes of long options. For example, given a
|
|
Packit |
3fa651 |
program `foo` with options `--filename` and `--filler`, typing
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
$ foo --fil test.txt
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
fails, whereas typing
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
$ foo --file test.txt
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
succeeds, and correctly identifies `"file"` as an unambiguous prefix
|
|
Packit |
3fa651 |
of the `filename` option.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Option disambiguation is *off* by default. To enable it, use the
|
|
Packit |
3fa651 |
`disambiguate` `PrefsMod` modifier as described above.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Here is a minimal example:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
import Options.Applicative
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
sample :: Parser ()
|
|
Packit |
3fa651 |
sample = () <$
|
|
Packit |
3fa651 |
switch (long "filename") <*
|
|
Packit |
3fa651 |
switch (long "filler")
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
main :: IO ()
|
|
Packit |
3fa651 |
main = customExecParser p opts
|
|
Packit |
3fa651 |
where
|
|
Packit |
3fa651 |
opts = info (helper <*> sample) idm
|
|
Packit |
3fa651 |
p = prefs disambiguate
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Customising the help screen
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
optparse-applicative has a number of combinators to help customise
|
|
Packit |
3fa651 |
the usage text, and determine when it should be displayed.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The `progDesc`, `header`, and `footer` functions can be used to
|
|
Packit |
3fa651 |
specify a brief description or tagline for the program, and detailed
|
|
Packit |
3fa651 |
information surrounding the generated option and command descriptions.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Internally we actually use the [ansi-wl-pprint][ansi-wl-pprint]
|
|
Packit |
3fa651 |
library, and one can use the `headerDoc` combinator and friends if
|
|
Packit |
3fa651 |
additional customisation is required.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
To display the usage text, the user may type `--help` if the `helper`
|
|
Packit |
3fa651 |
combinator has been applied to the `Parser`.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Authors can also use the preferences `showHelpOnError` or
|
|
Packit |
3fa651 |
`showHelpOnEmpty` to show the help text on any parser failure or
|
|
Packit |
3fa651 |
when a command is not complete and at the beginning of the parse
|
|
Packit |
3fa651 |
of the main program or one of its subcommands respectively.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Even if the help text is not shown for an error, a specific error
|
|
Packit |
3fa651 |
message will be, indicating what's missing, or what was unable to
|
|
Packit |
3fa651 |
be parsed.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
myParser :: Parser ()
|
|
Packit |
3fa651 |
myParser = ...
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
main :: IO ()
|
|
Packit |
3fa651 |
main = customExecParser p opts
|
|
Packit |
3fa651 |
where
|
|
Packit |
3fa651 |
opts = info (myParser <**> helper) idm
|
|
Packit |
3fa651 |
p = prefs showHelpOnEmpty
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Command groups
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
One experimental feature which may be useful for programs with many
|
|
Packit |
3fa651 |
subcommands is command group separation.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
data Sample
|
|
Packit |
3fa651 |
= Hello [String]
|
|
Packit |
3fa651 |
| Goodbye
|
|
Packit |
3fa651 |
deriving (Eq, Show)
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
hello :: Parser Sample
|
|
Packit |
3fa651 |
hello = Hello <$> many (argument str (metavar "TARGET..."))
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
sample :: Parser Sample
|
|
Packit |
3fa651 |
sample = subparser
|
|
Packit |
3fa651 |
( command "hello" (info hello (progDesc "Print greeting"))
|
|
Packit |
3fa651 |
<> command "goodbye" (info (pure Goodbye) (progDesc "Say goodbye"))
|
|
Packit |
3fa651 |
)
|
|
Packit |
3fa651 |
<|> subparser
|
|
Packit |
3fa651 |
( command "bonjour" (info hello (progDesc "Print greeting"))
|
|
Packit |
3fa651 |
<> command "au-revoir" (info (pure Goodbye) (progDesc "Say goodbye"))
|
|
Packit |
3fa651 |
<> commandGroup "French commands:"
|
|
Packit |
3fa651 |
<> hidden
|
|
Packit |
3fa651 |
)
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
This will logically separate the usage text for the two subparsers
|
|
Packit |
3fa651 |
(these would normally appear together if the `commandGroup` modifier
|
|
Packit |
3fa651 |
was not used). The `hidden` modifier suppresses the metavariable
|
|
Packit |
3fa651 |
for the second subparser being show in the brief usage line, which
|
|
Packit |
3fa651 |
is desirable in some cases.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
In this example we have essentially created synonyms for our parser,
|
|
Packit |
3fa651 |
but one could use this to separate common commands from rare ones,
|
|
Packit |
3fa651 |
or safe from dangerous.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The usage text for the preceding example is:
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
Usage: commands COMMAND
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Available options:
|
|
Packit |
3fa651 |
-h,--help Show this help text
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Available commands:
|
|
Packit |
3fa651 |
hello Print greeting
|
|
Packit |
3fa651 |
goodbye Say goodbye
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
French commands:
|
|
Packit |
3fa651 |
bonjour Print greeting
|
|
Packit |
3fa651 |
au-revoir Say goodbye
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
## Bash completion
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
`optparse-applicative` has built-in support for bash completion of
|
|
Packit |
3fa651 |
command line options and arguments. Any parser, when run using
|
|
Packit |
3fa651 |
`execParser` (and similar functions), is automatically extended
|
|
Packit |
3fa651 |
with a few (hidden) options for bash completion:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
- `--bash-completion-script`: this takes the full path of the program as
|
|
Packit |
3fa651 |
argument, and prints a bash script, which, when sourced into a bash session,
|
|
Packit |
3fa651 |
will install the necessary machinery to make bash completion work. For a
|
|
Packit |
3fa651 |
quick test, you can run something like (for a program called `foo` on the
|
|
Packit |
3fa651 |
`PATH`):
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```console
|
|
Packit |
3fa651 |
$ source <(foo --bash-completion-script `which foo`)
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Normally, the output of `--bash-completion-script` should be shipped with
|
|
Packit |
3fa651 |
the program and copied to the appropriate directory (usually
|
|
Packit |
3fa651 |
`/etc/bash_completion.d/`) during installation.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
- `--bash-completion-index`, `--bash-completion-word`: internal options used
|
|
Packit |
3fa651 |
by the completion script to obtain a list of possible completions for a
|
|
Packit |
3fa651 |
given command line.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Actions and completers
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
By default, options and commands are always completed. So, for example, if the
|
|
Packit |
3fa651 |
program `foo` has an option with a long name `output`, typing
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```console
|
|
Packit |
3fa651 |
$ foo --ou<TAB>
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
will complete `--output` automatically.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Arguments (either of regular options, or top-level) are not completed by
|
|
Packit |
3fa651 |
default. To enable completion for arguments, use one of the following modifiers
|
|
Packit |
3fa651 |
on a regular option or argument:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
- `completeWith`: specifies a list of possible completions to choose from;
|
|
Packit |
3fa651 |
- `action`: specifies a completion "action". An action dynamically determines
|
|
Packit |
3fa651 |
a list of possible completions. A full list of actions can be found in the
|
|
Packit |
3fa651 |
[bash documentation];
|
|
Packit |
3fa651 |
- `completer`: a completer is a function `String -> IO [String]`, returning
|
|
Packit |
3fa651 |
all possible completions for a given string. You can use this modifier to
|
|
Packit |
3fa651 |
specify a custom completion for an argument.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Completion modifiers can be used multiple times: the resulting completions will
|
|
Packit |
3fa651 |
call all of them and join the results.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
### Internals
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
When running a parser with `execParser`, the parser is extended with
|
|
Packit |
3fa651 |
`bashCompletionParser`, which defines the above options.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
When completion is triggered, the completion script calls the executable with
|
|
Packit |
3fa651 |
the special `--bash-completion-index` and `--bash-completion-word` options.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The original parser is therefore run in *completion mode*, i.e. `runParser` is
|
|
Packit |
3fa651 |
called on a different monad, which keeps track of the current state of the
|
|
Packit |
3fa651 |
parser, and exits when all arguments have been processed.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
The completion monad returns, on failure, either the last state of the parser
|
|
Packit |
3fa651 |
(if no option could be matched), or the completer associated to an option (if
|
|
Packit |
3fa651 |
it failed while fetching the argument for that option).
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
From that we generate a list of possible completions, and print them to
|
|
Packit |
3fa651 |
standard output. They are then read by the completion script and put into the
|
|
Packit |
3fa651 |
`COMPREPLY` variable.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
## Arrow interface
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
It is also possible to use the [Arrow syntax][arrows] to combine basic parsers.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
This can be particularly useful when the structure holding parse results is
|
|
Packit |
3fa651 |
deeply nested, or when the order of fields differs from the order in which the
|
|
Packit |
3fa651 |
parsers should be applied.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Using functions from the `Options.Applicative.Arrows` module, one can write,
|
|
Packit |
3fa651 |
for example:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
data Options = Options
|
|
Packit |
3fa651 |
{ optArgs :: [String]
|
|
Packit |
3fa651 |
, optVerbose :: Bool }
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
opts :: Parser Options
|
|
Packit |
3fa651 |
opts = runA $ proc () -> do
|
|
Packit |
3fa651 |
verbosity <- asA (option auto (short 'v' <> value 0)) -< ()
|
|
Packit |
3fa651 |
let verbose = verbosity > 0
|
|
Packit |
3fa651 |
args <- asA (many (argument str idm)) -< ()
|
|
Packit |
3fa651 |
returnA -< Options args verbose
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
where parsers are converted to arrows using `asA`, and the resulting
|
|
Packit |
3fa651 |
composed arrow is converted back to a `Parser` with `runA`.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
See `tests/Examples/Cabal.hs` for a slightly more elaborate example
|
|
Packit |
3fa651 |
using the arrow syntax for defining parsers.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Note that the `Arrow` interface is provided only for convenience. The
|
|
Packit |
3fa651 |
API based on `Applicative` is just as expressive, although it might be
|
|
Packit |
3fa651 |
cumbersome to use in certain cases.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
## Applicative do
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Some may find using optparse-applicative easier using do notation.
|
|
Packit |
3fa651 |
However, as `Parser` is not an instance of `Monad`, this can only
|
|
Packit |
3fa651 |
be done in recent versions of GHC using the *ApplicativeDo* extension.
|
|
Packit |
3fa651 |
For example, a parser specified in this manner might be
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
{-# LANGUAGE RecordWildCards #-}
|
|
Packit |
3fa651 |
{-# LANGUAGE ApplicativeDo #-}
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
data Options = Options
|
|
Packit |
3fa651 |
{ optArgs :: [String]
|
|
Packit |
3fa651 |
, optVerbose :: Bool }
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
opts :: Parser Options
|
|
Packit |
3fa651 |
opts = do
|
|
Packit |
3fa651 |
optVerbose <- switch (short 'v')
|
|
Packit |
3fa651 |
optArgs <- many (argument str idm)
|
|
Packit |
3fa651 |
pure Options {..}
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Here we've also used the *RecordWildCards* extension to make the
|
|
Packit |
3fa651 |
parser specification cleaner. Compilation errors referring to `Monad`
|
|
Packit |
3fa651 |
instances not being found are likely because the `Parser` specified
|
|
Packit |
3fa651 |
can not be implemented entirely with `Applicative` (Note however,
|
|
Packit |
3fa651 |
there were a few desugaring bugs regarding ApplicativeDo in GHC
|
|
Packit |
3fa651 |
8.0.1, function application with `($)` in particular may not work,
|
|
Packit |
3fa651 |
and the `pure` value should instead be wrapped parenthetically).
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
## FAQ
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
* Monadic parsing?
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
If a Monadic style were to be used, there would be no possible
|
|
Packit |
3fa651 |
way to traverse the parser and generate a usage string, or for
|
|
Packit |
3fa651 |
us to allow for options to be parsed in any order. Therefore it
|
|
Packit |
3fa651 |
is intentionally unsupported to write a `Parser` in this manner
|
|
Packit |
3fa651 |
with optparse-applicative, and the `Parser` type does not have
|
|
Packit |
3fa651 |
an instance for `Monad`.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
* Overlapping flags and options / options with optional arguments?
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
This is not supported as it can lead to an ambiguous parse.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
For example, if we supported and had an optional value option
|
|
Packit |
3fa651 |
"--foo" and a flag "--bar", is "--foo --bar" the option with value
|
|
Packit |
3fa651 |
"--bar", or the default value with the flag switched on? What if
|
|
Packit |
3fa651 |
instead of a switch we had many positional string arguments, is
|
|
Packit |
3fa651 |
the first string the option's value or the first positional?
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
It is suggested to instead use the `Alternative` instance of
|
|
Packit |
3fa651 |
`Parser` and create a flag', an option, and a pure value for the
|
|
Packit |
3fa651 |
default (with different names for the flag and option).
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
* Backtracking on `ReadM` errors?
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
Parser structures are predetermined at parse time. This means
|
|
Packit |
3fa651 |
that if a `ReadM` fails, the whole parse must also fail, we can't
|
|
Packit |
3fa651 |
consider any alternatives, as there can be no guarantee that the
|
|
Packit |
3fa651 |
remaining structure will fit. One occasionally confusing side
|
|
Packit |
3fa651 |
effect of this is that two positional arguments for different
|
|
Packit |
3fa651 |
constructors of a sum type can't be composed at the parser level;
|
|
Packit |
3fa651 |
rather, this must be done at the `ReadM` level. For example:
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
```haskell
|
|
Packit |
3fa651 |
import Options.Applicative
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
data S3orFile = S3 BucketKey | File FilsePath
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
s3Read, fileRead :: ReadM S3orFile
|
|
Packit |
3fa651 |
s3Read = S3 <$> ...
|
|
Packit |
3fa651 |
fileRead = File <$> ...
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
correct :: Parser S3orFile
|
|
Packit |
3fa651 |
correct = argument (s3Read <|> fileRead) idm
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
incorrect :: Parser S3orFile
|
|
Packit |
3fa651 |
incorrect = argument s3Read idm <|> argument fileRead idm
|
|
Packit |
3fa651 |
```
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
## How it works
|
|
Packit |
3fa651 |
An applicative `Parser` is essentially a heterogeneous list or tree
|
|
Packit |
3fa651 |
of `Option`s, implemented with existential types.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
All options are therefore known statically (i.e. before parsing,
|
|
Packit |
3fa651 |
not necessarily before runtime), and can, for example, be traversed
|
|
Packit |
3fa651 |
to generate a help text. Indeed, when displaying the usage text for
|
|
Packit |
3fa651 |
a parser, we use an intermediate tree structure.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
When we examine the user's input, each argument is examined to
|
|
Packit |
3fa651 |
determine if it's an option or flag, or a positional argument. The
|
|
Packit |
3fa651 |
parse tree is then searched for a matching term, and if it finds
|
|
Packit |
3fa651 |
one, that leaf of the tree is replaced with the value itself. When
|
|
Packit |
3fa651 |
all input has been processed, we see if we can generate the complete
|
|
Packit |
3fa651 |
value, and if not issue an error.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
See [this blog post][blog] for a more detailed explanation based on a
|
|
Packit |
3fa651 |
simplified implementation.
|
|
Packit |
3fa651 |
|
|
Packit |
3fa651 |
[aeson]: http://hackage.haskell.org/package/aeson
|
|
Packit |
3fa651 |
[applicative]: http://hackage.haskell.org/package/base/docs/Control-Applicative.html
|
|
Packit |
3fa651 |
[arrows]: http://www.haskell.org/arrows/syntax.html
|
|
Packit |
3fa651 |
[attoparsec]: http://hackage.haskell.org/package/attoparsec
|
|
Packit |
3fa651 |
[bash documentation]: http://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html
|
|
Packit |
3fa651 |
[blog]: http://paolocapriotti.com/blog/2012/04/27/applicative-option-parser/
|
|
Packit |
3fa651 |
[hackage]: http://hackage.haskell.org/package/optparse-applicative
|
|
Packit |
3fa651 |
[hackage-png]: http://img.shields.io/hackage/v/optparse-applicative.svg
|
|
Packit |
3fa651 |
[hackage-deps]: http://packdeps.haskellers.com/reverse/optparse-applicative
|
|
Packit |
3fa651 |
[hackage-deps-png]: https://img.shields.io/hackage-deps/v/optparse-applicative.svg
|
|
Packit |
3fa651 |
[monoid]: http://hackage.haskell.org/package/base/docs/Data-Monoid.html
|
|
Packit |
3fa651 |
[semigroup]: http://hackage.haskell.org/package/base/docs/Data-Semigroup.html
|
|
Packit |
3fa651 |
[parsec]: http://hackage.haskell.org/package/parsec
|
|
Packit |
3fa651 |
[status]: http://travis-ci.org/pcapriotti/optparse-applicative?branch=master
|
|
Packit |
3fa651 |
[status-png]: https://api.travis-ci.org/pcapriotti/optparse-applicative.svg?branch=master
|
|
Packit |
3fa651 |
[ansi-wl-pprint]: http://hackage.haskell.org/package/ansi-wl-pprint
|