mirror of
https://github.com/ilyakooo0/optparse-applicative.git
synced 2024-11-22 22:18:13 +03:00
Replace README with documentation
This commit is contained in:
parent
4e1736a440
commit
5f8a961656
505
README.md
505
README.md
@ -1,62 +1,229 @@
|
||||
# Applicative option parser
|
||||
# optparse-applicative
|
||||
|
||||
This package contains utilities and combinators to define command line option
|
||||
parsers.
|
||||
optparse-applicative is a library for parsing command-line options. It provides
|
||||
a collection of primitive parsers, which can be assembled using an [applicative]
|
||||
interface to build arbitrarily complex command-line option specifications.
|
||||
|
||||
[![Continuous Integration status][status-png]][status]
|
||||
[![Hackage page (downloads and API reference)][hackage-png]][hackage]
|
||||
optparse-applicative takes care of reading and validating the arguments passed
|
||||
to the command line, handling and reporting errors, generating a usage line, a
|
||||
help screen, and enabling context-sensitive bash completions.
|
||||
|
||||
## Getting started
|
||||
**Table of Contents**
|
||||
|
||||
Here is a simple example of an applicative option parser:
|
||||
- [Introduction](#introduction)
|
||||
- [Basic parsers](#basic-parsers)
|
||||
- [Sequencing](#sequencing)
|
||||
- [Choice](#choice)
|
||||
- [Running parsers](#running-parsers)
|
||||
- [Builders](#builders)
|
||||
- [Regular options](#regular-options)
|
||||
- [Flags](#flags)
|
||||
- [Arguments](#arguments)
|
||||
- [Commands](#commands)
|
||||
- [Modifiers](#modifiers)
|
||||
- [Custom parsing and error handling](#custom-parsing-and-error-handling)
|
||||
- [Parser runners](#parser-runners)
|
||||
- [Option readers](#option-readers)
|
||||
- [Preferences](#preferences)
|
||||
- [Disambiguation](#disambiguation)
|
||||
- [Displaying custom error messages](#displaying-custom-error-messages)
|
||||
- [Customising the help screen](#customising-the-help-screen)
|
||||
- [Bash completion](#bash-completion)
|
||||
- [Actions and completers](#actions-and-completers)
|
||||
- [Internals](#internals)
|
||||
- [Arrow interface](#arrow-interface)
|
||||
- [FAQ](#faq)
|
||||
|
||||
## Introduction
|
||||
|
||||
The core type in optparse-applicative is `Parser`:
|
||||
|
||||
```haskell
|
||||
data Sample = Sample
|
||||
{ hello :: String
|
||||
, quiet :: Bool }
|
||||
data Parser a
|
||||
|
||||
sample :: Parser Sample
|
||||
sample = Sample
|
||||
<$> strOption
|
||||
( long "hello"
|
||||
<> metavar "TARGET"
|
||||
<> help "Target for the greeting" )
|
||||
<*> switch
|
||||
( long "quiet"
|
||||
<> help "Whether to be quiet" )
|
||||
instance Functor Parser
|
||||
instance Applicative Parser
|
||||
instance Alternative Parser
|
||||
```
|
||||
|
||||
The parser is built using [applicative style][applicative] starting from a set
|
||||
of basic combinators. In this example, `hello` is defined as an option with a
|
||||
`String` argument, while `quiet` is a boolean flag (called `switch`).
|
||||
A value of type `Parser a` represents a specification for a set of options,
|
||||
which, if parsed correctly, will eventually result in a value of type `a`.
|
||||
|
||||
A parser can be used like this:
|
||||
If you are familiar with parser combinator libraries like [parsec] or
|
||||
[attoparsec], you will feel right at home with optparse-applicative.
|
||||
|
||||
If not, don't worry: all you really need to learn are a few basic parsers, and
|
||||
the two operations of *sequencing* and *choice*, provided by the `Applicative`
|
||||
and `Alternative` type classes respectively.
|
||||
|
||||
### Basic parsers
|
||||
|
||||
optparse-applicative provides a number of primitive parsers, usually
|
||||
corresponding to single options, through its *Builder* interface. Builders are
|
||||
detailed in their [own section](#builder) of the manual, but for now, let's
|
||||
just look at a few examples to get a feel for how parsers can be defined.
|
||||
|
||||
Here is a parser for a mandatory option with an argument:
|
||||
|
||||
```haskell
|
||||
greet :: Sample -> IO ()
|
||||
greet (Sample h False) = putStrLn $ "Hello, " ++ h
|
||||
greet _ = return ()
|
||||
|
||||
main :: IO ()
|
||||
main = execParser opts >>= greet
|
||||
where
|
||||
opts = info (helper <*> sample)
|
||||
( fullDesc
|
||||
<> progDesc "Print a greeting for TARGET"
|
||||
<> header "hello - a test for optparse-applicative" )
|
||||
target :: Parser String
|
||||
target = strOption
|
||||
( long "hello"
|
||||
<> metavar "TARGET"
|
||||
<> help "Target for the greeting" )
|
||||
```
|
||||
|
||||
The `greet` function is the entry point of the program, while `opts` is a
|
||||
complete description of the program, used when generating a help text. The
|
||||
`helper` combinator takes any parser, and adds a `help` option to it.
|
||||
You can see that we are defining an option parser for a string argument, with
|
||||
*long* option name "hello", *metavariable* "TARGET", and the given help text.
|
||||
This means that the `target` parser defined above will require an option like
|
||||
|
||||
The `hello` option in this example is mandatory (since it doesn't have a
|
||||
default value), so running the program without any argument will display a
|
||||
short option summary:
|
||||
--target world
|
||||
|
||||
Usage: hello --hello TARGET [--quiet]
|
||||
on the command line. The metavariable and the help text will appear in the
|
||||
generated help text, but don't otherwise affect the behaviour of the parser.
|
||||
|
||||
Running the program with the `--help` option will display the full help text:
|
||||
The attributes passed to the option are called *modifiers*, and are composed
|
||||
using the [monoid] operation `(<>)`.
|
||||
|
||||
Options with an argument such as `target` are referred to as *regular options*,
|
||||
and are by far the most common. Another example of option is a boolean
|
||||
*switch*:
|
||||
|
||||
```haskell
|
||||
quiet :: Parser Bool
|
||||
quiet = switch
|
||||
( long "quiet"
|
||||
<> short 'q'
|
||||
<> help "Whether to be quiet" )
|
||||
```
|
||||
|
||||
Here we used a `short` modifier to specify a one-letter name for the option.
|
||||
This means that this switch can be set either with `--quiet` or `-q`.
|
||||
|
||||
Switches, unlike regular options, have no arguments. They simply return `True`
|
||||
when found on the command line, and `False` otherwise.
|
||||
|
||||
Switches are special cases of *flags*, which can be created using `flag` (or
|
||||
`flag'` for flags without a default value), and can be used to choose between
|
||||
any two values of any type, rather than just `True` and `False`.
|
||||
|
||||
There are other kinds of basic parsers, and several ways to configure them. We
|
||||
will cover all of them in [Builders](#builders).
|
||||
|
||||
### Sequencing
|
||||
|
||||
We now want to combine `target` and `quiet` into a single parser that accepts
|
||||
both options and returns a combined value. So let's begin by defining the type
|
||||
of the result:
|
||||
|
||||
```haskell
|
||||
data Options = Options
|
||||
{ optTarget :: String
|
||||
, optQuiet :: Bool }
|
||||
```
|
||||
|
||||
and now it's just a matter of using `Applicative`'s sequencing operator `(<*>)`
|
||||
to combine the two previously defined parsers:
|
||||
|
||||
```haskell
|
||||
opts :: Parser Options
|
||||
opts = Options <$> target <*> quiet
|
||||
```
|
||||
|
||||
No matter which parsers appear first in the sequence, options will still be
|
||||
parsed in whatever order they appear in the command line. A parser with such a
|
||||
property is sometimes called a *permutation parser*.
|
||||
|
||||
In our example, a command line like:
|
||||
|
||||
--target world -q
|
||||
|
||||
will give the same result as
|
||||
|
||||
-q --target world
|
||||
|
||||
Note, however, that the order of sequencing is still somewhat significant, in
|
||||
that it affects the generated help text.
|
||||
|
||||
### Choice
|
||||
|
||||
It is quite common to find programs that can be configured in different ways
|
||||
through the command line. A typical example is a program that can be given a
|
||||
text file as input, or alternatively read it directly from the standard input.
|
||||
|
||||
We can model this easily and effectively in Haskell using *sum types*:
|
||||
|
||||
```haskell
|
||||
data Input
|
||||
= FileInput FilePath
|
||||
| StdInput
|
||||
|
||||
run :: Input -> IO ()
|
||||
run = ...
|
||||
```
|
||||
|
||||
However, we can't build a command line parser for the type `Input` using only
|
||||
the primitive blocks introduced so far, plus sequencing. We can certainly
|
||||
define the two basic parsers involved:
|
||||
|
||||
```haskell
|
||||
fileInput :: Parser Input
|
||||
fileInput = FileInput <$> strOption
|
||||
( long "file"
|
||||
<> short 'f'
|
||||
<> metavar "FILENAME"
|
||||
<> help "Input file" )
|
||||
|
||||
stdInput :: Parser Input
|
||||
stdInput = flag' StdInput
|
||||
( long "stdin"
|
||||
<> help "Read from stdin" )
|
||||
```
|
||||
|
||||
but we want to combine them in such a way that only one of them is ever
|
||||
parsed, and never both; alas, the sequencing operator of `Applicative` doesn't
|
||||
allow us to specify this kind of behaviour.
|
||||
|
||||
Fortunately, the `Parser` type constructor is also an instance of `Alternative`,
|
||||
which provides a *choice* operator `(<|>)` for exactly this purpose:
|
||||
|
||||
```haskell
|
||||
opts2 :: Parser Input
|
||||
opts2 = fileInput <|> stdInput
|
||||
```
|
||||
|
||||
Now `--file "foo.txt"` will be parsed as `FileInput "foo.txt"`, `--stdin` will
|
||||
be parsed as `StdInput`, but a command line containing both options, like
|
||||
|
||||
--file "foo.txt" --stdin
|
||||
|
||||
will be rejected.
|
||||
|
||||
### Running parsers
|
||||
|
||||
We have been discussing what parsers do, but so far, we haven't seen how to
|
||||
actually have them process the command line and return a result, or report a
|
||||
failure.
|
||||
|
||||
Before we can run a `Parser`, we need to wrap it into a `ParserInfo` structure,
|
||||
that specifies a number of properties that only apply to top level parsers, such
|
||||
as a header describing what the program does, to be displayed in the help
|
||||
screen.
|
||||
|
||||
The function `info` will help with this step. For the parser `opts` defined
|
||||
above the corresponding `ParserInfo` could look something like:
|
||||
|
||||
```haskell
|
||||
pinfo :: ParserInfo Options
|
||||
pinfo = info (opts <**> helper)
|
||||
( progDesc "Print a greeting for TARGET"
|
||||
<> header "hello - a demo of optparse-applicative" )
|
||||
```
|
||||
|
||||
The `helper` parser that we added after `opts` just creates a dummy `--helper`
|
||||
option that displays the help text. Besides that, we just set some of the
|
||||
fields of the `ParserInfo` structure with meaningful values. They will be
|
||||
displayed in the help text like so:
|
||||
|
||||
hello - a test for optparse-applicative
|
||||
|
||||
@ -68,30 +235,45 @@ Running the program with the `--help` option will display the full help text:
|
||||
--hello TARGET Target for the greeting
|
||||
--quiet Whether to be quiet
|
||||
|
||||
containing a detailed list of options with descriptions.
|
||||
|
||||
The specified metavars are used as placeholders for the option arguments, and
|
||||
can be referred to in the program description. This makes it possible to
|
||||
explicitly describe the connection between the options and the behaviour of the
|
||||
program.
|
||||
|
||||
Parsers are instances of both `Applicative` and `Alternative`, and work with
|
||||
any generic combinator, like `many` and `some`. For example, to make a option
|
||||
return `Nothing` instead of failing when it's not supplied, you can use the
|
||||
`optional` combinator in `Control.Applicative`:
|
||||
Now that we have a `ParserInfo`, we can finally run the parser. The simplest
|
||||
way to do so is to simply call the `execParser` function in your `main`:
|
||||
|
||||
```haskell
|
||||
optional $ strOption
|
||||
( long "output"
|
||||
<> metavar "DIRECTORY" )
|
||||
main :: IO ()
|
||||
main = do
|
||||
options <- execParser pinfo
|
||||
...
|
||||
```
|
||||
|
||||
[applicative]: http://www.soi.city.ac.uk/~ross/papers/Applicative.html
|
||||
The `execParser` function takes care of everything, including getting the
|
||||
arguments from the command line, and displaying errors and help screens to the
|
||||
user.
|
||||
|
||||
## Supported options
|
||||
There are other ways to run a `ParserInfo`, in situations where you need finer
|
||||
control over the behavior of your parser, or if you want to use it in pure
|
||||
code. They will be covered in
|
||||
[Custom parsing and error handling](#custom-parsing-and-error-handling).
|
||||
|
||||
`optparse-applicative` supports four kinds of options: regular options, flags,
|
||||
arguments and commands.
|
||||
## Builders
|
||||
|
||||
Builders allow you to define parsers using a convenient combinator-based
|
||||
syntax. We have already seen examples of builders in action, like `strOption`
|
||||
and `switch`, which we used to define the `opts` parser for our "hello" example.
|
||||
|
||||
Builders always take a [modifier](#modifier) argument, which is essentially a
|
||||
composition of functions acting on the option, setting values for properties or
|
||||
adding features.
|
||||
|
||||
Builders work by building the option from scratch, and eventually lifting it to
|
||||
a single-option parser, ready to be combined with other parsers using normal
|
||||
`Applicative` and `Alternative` combinators.
|
||||
|
||||
See the [haddock documentation][builder-documentation] for
|
||||
`Options.Applicative.Builder` for a full list of builders and modifiers.
|
||||
|
||||
There are four different kinds of options in `optparse-applicative`: regular
|
||||
options, flags, arguments and commands. In the following, we will go over each
|
||||
one of these and describe the builders that can be used to create them.
|
||||
|
||||
### Regular options
|
||||
|
||||
@ -138,7 +320,7 @@ strOption
|
||||
|
||||
creates a regular option with a string argument (which can be referred to as
|
||||
`FILE` in the help text and documentation), a long name "output" and a short
|
||||
name "o". See below for more information on the builder syntax and modifiers.
|
||||
name "o".
|
||||
|
||||
A regular option can return an object of any type, and takes a *reader*
|
||||
parameter which specifies how the argument should be parsed. A common reader is
|
||||
@ -294,50 +476,185 @@ opts = subparser
|
||||
<> command "stop" (info (pure stop) idm) )
|
||||
|
||||
main :: IO ()
|
||||
main = join $ execParser (info opts idm)
|
||||
main = join $ execParser pinfo(info opts idm)
|
||||
```
|
||||
|
||||
## Option builders
|
||||
### Modifiers
|
||||
|
||||
Builders allow you to define parsers using a convenient combinator-based
|
||||
syntax. Each builder takes a **modifier** as parameter, and returns a parser.
|
||||
**Modifiers** are instances of the `Monoid` typeclass, so they can be combined using
|
||||
the composition function `mappend` (or simply `(<>)`). Since different builders
|
||||
accept different sets of modifiers, modifiers have a type parameter that
|
||||
specifies which builders support it.
|
||||
|
||||
A modifier is a composition of functions which act on the option, setting
|
||||
values for properties or adding features, and is used to build the option from
|
||||
scratch and finally lift it to a single-option parser, which can then be
|
||||
combined with other parsers using normal `Applicative` combinators.
|
||||
For example,
|
||||
|
||||
Modifiers are instances of the `Monoid` typeclass, so they can be combined
|
||||
using the composition function `mappend` (or simply `(<>)`).
|
||||
```haskell
|
||||
command :: String -> ParserInfo a -> Mod CommandFields a
|
||||
```
|
||||
|
||||
See the [haddock documentation][builder-documentation] for `Options.Applicative.Builder`
|
||||
for a full list of builders and modifiers.
|
||||
can only be used with [commands](#commands), as the `CommandFields` type
|
||||
argument of `Mod` will prevent it from being passed to builders for other types
|
||||
of options.
|
||||
|
||||
## Advanced features
|
||||
Many modifiers are polymorphic in this type argument, which means that they can
|
||||
be used with any builder.
|
||||
|
||||
* [Bash completion]
|
||||
* [Arrow interface]
|
||||
* [Disambiguation]
|
||||
## Custom parsing and error handling
|
||||
|
||||
[Bash completion]: https://github.com/pcapriotti/optparse-applicative/wiki/Bash-Completion
|
||||
[Arrow interface]: https://github.com/pcapriotti/optparse-applicative/wiki/Arrows
|
||||
[Disambiguation]: https://github.com/pcapriotti/optparse-applicative/wiki/Disambiguation
|
||||
### Parser runners
|
||||
### Option readers
|
||||
### Preferences
|
||||
### Disambiguation
|
||||
|
||||
## How it works
|
||||
It is possible to configure optparse-applicative to perform automatic
|
||||
disambiguation of prefixes of long options. For example, given a program `foo`
|
||||
with options `--filename` and `--filler`, typing
|
||||
|
||||
A `Parser a` is essentially a heterogeneous list of `Option`s, implemented with
|
||||
existential types.
|
||||
$ foo --fil test.txt
|
||||
|
||||
All options are therefore known statically (i.e. before parsing, not
|
||||
necessarily before runtime), and can, for example, be traversed to generate a
|
||||
help text.
|
||||
fails, whereas typing
|
||||
|
||||
See [this blog post][blog] for a more detailed explanation based on a
|
||||
simplified implementation.
|
||||
$ foo --file test.txt
|
||||
|
||||
[status-png]: https://api.travis-ci.org/pcapriotti/optparse-applicative.svg
|
||||
[status]: http://travis-ci.org/pcapriotti/optparse-applicative?branch=master
|
||||
[blog]: http://paolocapriotti.com/blog/2012/04/27/applicative-option-parser/
|
||||
[builder-documentation]: http://hackage.haskell.org/package/optparse-applicative/docs/Options-Applicative-Builder.html
|
||||
[hackage-png]: http://img.shields.io/hackage/v/optparse-applicative.svg
|
||||
[hackage]: http://hackage.haskell.org/package/optparse-applicative
|
||||
succeeds, and correctly identifies `"file"` as an unambiguous prefix of the
|
||||
`filename` option.
|
||||
|
||||
Option disambiguation is *off* by default. To enable it, provide the
|
||||
`disambiguate` modifier to the `prefs` builder, and pass the resulting
|
||||
preferences to one of the parser runners that take an `ParserPrefs` parameter,
|
||||
like `customExecParser`.
|
||||
|
||||
Here is a minimal example:
|
||||
|
||||
```haskell
|
||||
import Options.Applicative
|
||||
|
||||
sample :: Parser ()
|
||||
sample = () <$
|
||||
switch (long "filename") <*
|
||||
switch (long "filler")
|
||||
|
||||
main :: IO ()
|
||||
main = customExecParser p opts
|
||||
where
|
||||
opts = info (helper <*> sample) idm
|
||||
p = prefs disambiguate
|
||||
|
||||
```
|
||||
|
||||
### Displaying custom error messages
|
||||
### Customising the help screen
|
||||
|
||||
## Bash completion
|
||||
|
||||
`optparse-applicative` has built-in support for bash completion of command line
|
||||
options and arguments. Any parser, when run using `execParser` (and similar
|
||||
functions), is automatically extended with a few (hidden) options for bash
|
||||
completion:
|
||||
|
||||
- `--bash-completion-script`: this takes the full path of the program as
|
||||
argument, and prints a bash script, which, when sourced into a bash session,
|
||||
will install the necessary machinery to make bash completion work. For a
|
||||
quick test, you can run something like (for a program called `foo` on the
|
||||
`PATH`):
|
||||
|
||||
```console
|
||||
$ source <(foo --bash-completion-script `which foo`)
|
||||
```
|
||||
|
||||
Normally, the output of `--bash-completion-script` should be shipped with
|
||||
the program and copied to the appropriate directory (usually
|
||||
`/etc/bash_completion.d/`) during installation.
|
||||
|
||||
- `--bash-completion-index`, `--bash-completion-word`: internal options used
|
||||
by the completion script to obtain a list of possible completions for a
|
||||
given command line.
|
||||
|
||||
### Actions and completers
|
||||
|
||||
By default, options and commands are always completed. So, for example, if the
|
||||
program `foo` has an option with a long name `output`, typing
|
||||
|
||||
```console
|
||||
$ foo --ou<TAB>
|
||||
```
|
||||
|
||||
will complete `--output` automatically.
|
||||
|
||||
Arguments (either of regular options, or top-level) are not completed by
|
||||
default. To enable completion for arguments, use one of the following modifiers
|
||||
on a regular option or argument:
|
||||
|
||||
- `completeWith`: specifies a list of possible completions to choose from;
|
||||
- `action`: specifies a completion "action". An action dynamically determines
|
||||
a list of possible completions. A full list of actions can be found in the
|
||||
[bash documentation];
|
||||
- `completer`: a completer is a function `String -> IO [String]`, returning
|
||||
all possible completions for a given string. You can use this modifier to
|
||||
specify a custom completion for an argument.
|
||||
|
||||
Completion modifiers can be used multiple times: the resulting completions will
|
||||
call all of them and join the results.
|
||||
|
||||
### Internals
|
||||
|
||||
When running a parser with `execParser`, the parser is extended with
|
||||
`bashCompletionParser`, which defines the above options.
|
||||
|
||||
When completion is triggered, the completion script calls the executable with
|
||||
the special `--bash-completion-index` and `--bash-completion-word` options.
|
||||
|
||||
The original parser is therefore run in *completion mode*, i.e. `runParser` is
|
||||
called on a different monad, which keeps track of the current state of the
|
||||
parser, and exits when all arguments have been processed.
|
||||
|
||||
The completion monad returns, on failure, either the last state of the parser
|
||||
(if no option could be matched), or the completer associated to an option (if
|
||||
it failed while fetching the argument for that option).
|
||||
|
||||
From that we generate a list of possible completions, and print them to
|
||||
standard output. They are then read by the completion script and put into the
|
||||
`COMPREPLY` variable.
|
||||
|
||||
## Arrow interface
|
||||
|
||||
It is also possible to use the [Arrow syntax][arrows] to combine basic parsers.
|
||||
|
||||
This can be particularly useful when the structure holding parse results is
|
||||
deeply nested, or when the order of fields differs from the order in which the
|
||||
parsers should be applied.
|
||||
|
||||
Using functions from the `Options.Applicative.Arrows` module, one can write,
|
||||
for example:
|
||||
|
||||
```haskell
|
||||
data Options = Options
|
||||
{ optArgs :: [String]
|
||||
, optVerbose :: Bool }
|
||||
|
||||
opts :: Parser Options
|
||||
opts = runA $ proc () -> do
|
||||
verbosity <- asA (option (short 'v' <> value 0)) -< ()
|
||||
let verbose = verbosity > 0
|
||||
args <- asA (many (argument str idm)) -< ()
|
||||
returnA -< Options args verbose
|
||||
```
|
||||
|
||||
where parsers are converted to arrows using `asA`, and the resulting composed
|
||||
arrow is converted back to a `Parser` with `runA`.
|
||||
|
||||
See `tests/Examples/Cabal.hs` for a slightly more elaborate example using the
|
||||
arrow syntax for defining parsers.
|
||||
|
||||
Note that the `Arrow` interface is provided only for convenience. The API based
|
||||
on `Applicative` is just as expressive, although it might be cumbersome to use
|
||||
in certain cases.
|
||||
|
||||
## FAQ
|
||||
|
||||
[applicative]: http://hackage.haskell.org/package/base/docs/Control-Applicative.html
|
||||
[arrows]: http://www.haskell.org/arrows/syntax.html
|
||||
[attoparsec]: http://hackage.haskell.org/package/attoparsec
|
||||
[bash documentation]: http://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html
|
||||
[monoid]: http://hackage.haskell.org/package/base/docs/Data-Monoid.html
|
||||
[parsec]: http://hackage.haskell.org/package/parsec
|
||||
|
660
docs/index.md
660
docs/index.md
@ -1,660 +0,0 @@
|
||||
# optparse-applicative
|
||||
|
||||
optparse-applicative is a library for parsing command-line options. It provides
|
||||
a collection of primitive parsers, which can be assembled using an [applicative]
|
||||
interface to build arbitrarily complex command-line option specifications.
|
||||
|
||||
optparse-applicative takes care of reading and validating the arguments passed
|
||||
to the command line, handling and reporting errors, generating a usage line, a
|
||||
help screen, and enabling context-sensitive bash completions.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Basic parsers](#basic-parsers)
|
||||
- [Sequencing](#sequencing)
|
||||
- [Choice](#choice)
|
||||
- [Running parsers](#running-parsers)
|
||||
- [Builders](#builders)
|
||||
- [Regular options](#regular-options)
|
||||
- [Flags](#flags)
|
||||
- [Arguments](#arguments)
|
||||
- [Commands](#commands)
|
||||
- [Modifiers](#modifiers)
|
||||
- [Custom parsing and error handling](#custom-parsing-and-error-handling)
|
||||
- [Parser runners](#parser-runners)
|
||||
- [Option readers](#option-readers)
|
||||
- [Preferences](#preferences)
|
||||
- [Disambiguation](#disambiguation)
|
||||
- [Displaying custom error messages](#displaying-custom-error-messages)
|
||||
- [Customising the help screen](#customising-the-help-screen)
|
||||
- [Bash completion](#bash-completion)
|
||||
- [Actions and completers](#actions-and-completers)
|
||||
- [Internals](#internals)
|
||||
- [Arrow interface](#arrow-interface)
|
||||
- [FAQ](#faq)
|
||||
|
||||
## Introduction
|
||||
|
||||
The core type in optparse-applicative is `Parser`:
|
||||
|
||||
```haskell
|
||||
data Parser a
|
||||
|
||||
instance Functor Parser
|
||||
instance Applicative Parser
|
||||
instance Alternative Parser
|
||||
```
|
||||
|
||||
A value of type `Parser a` represents a specification for a set of options,
|
||||
which, if parsed correctly, will eventually result in a value of type `a`.
|
||||
|
||||
If you are familiar with parser combinator libraries like [parsec] or
|
||||
[attoparsec], you will feel right at home with optparse-applicative.
|
||||
|
||||
If not, don't worry: all you really need to learn are a few basic parsers, and
|
||||
the two operations of *sequencing* and *choice*, provided by the `Applicative`
|
||||
and `Alternative` type classes respectively.
|
||||
|
||||
### Basic parsers
|
||||
|
||||
optparse-applicative provides a number of primitive parsers, usually
|
||||
corresponding to single options, through its *Builder* interface. Builders are
|
||||
detailed in their [own section](#builder) of the manual, but for now, let's
|
||||
just look at a few examples to get a feel for how parsers can be defined.
|
||||
|
||||
Here is a parser for a mandatory option with an argument:
|
||||
|
||||
```haskell
|
||||
target :: Parser String
|
||||
target = strOption
|
||||
( long "hello"
|
||||
<> metavar "TARGET"
|
||||
<> help "Target for the greeting" )
|
||||
```
|
||||
|
||||
You can see that we are defining an option parser for a string argument, with
|
||||
*long* option name "hello", *metavariable* "TARGET", and the given help text.
|
||||
This means that the `target` parser defined above will require an option like
|
||||
|
||||
--target world
|
||||
|
||||
on the command line. The metavariable and the help text will appear in the
|
||||
generated help text, but don't otherwise affect the behaviour of the parser.
|
||||
|
||||
The attributes passed to the option are called *modifiers*, and are composed
|
||||
using the [monoid] operation `(<>)`.
|
||||
|
||||
Options with an argument such as `target` are referred to as *regular options*,
|
||||
and are by far the most common. Another example of option is a boolean
|
||||
*switch*:
|
||||
|
||||
```haskell
|
||||
quiet :: Parser Bool
|
||||
quiet = switch
|
||||
( long "quiet"
|
||||
<> short 'q'
|
||||
<> help "Whether to be quiet" )
|
||||
```
|
||||
|
||||
Here we used a `short` modifier to specify a one-letter name for the option.
|
||||
This means that this switch can be set either with `--quiet` or `-q`.
|
||||
|
||||
Switches, unlike regular options, have no arguments. They simply return `True`
|
||||
when found on the command line, and `False` otherwise.
|
||||
|
||||
Switches are special cases of *flags*, which can be created using `flag` (or
|
||||
`flag'` for flags without a default value), and can be used to choose between
|
||||
any two values of any type, rather than just `True` and `False`.
|
||||
|
||||
There are other kinds of basic parsers, and several ways to configure them. We
|
||||
will cover all of them in [Builders](#builders).
|
||||
|
||||
### Sequencing
|
||||
|
||||
We now want to combine `target` and `quiet` into a single parser that accepts
|
||||
both options and returns a combined value. So let's begin by defining the type
|
||||
of the result:
|
||||
|
||||
```haskell
|
||||
data Options = Options
|
||||
{ optTarget :: String
|
||||
, optQuiet :: Bool }
|
||||
```
|
||||
|
||||
and now it's just a matter of using `Applicative`'s sequencing operator `(<*>)`
|
||||
to combine the two previously defined parsers:
|
||||
|
||||
```haskell
|
||||
opts :: Parser Options
|
||||
opts = Options <$> target <*> quiet
|
||||
```
|
||||
|
||||
No matter which parsers appear first in the sequence, options will still be
|
||||
parsed in whatever order they appear in the command line. A parser with such a
|
||||
property is sometimes called a *permutation parser*.
|
||||
|
||||
In our example, a command line like:
|
||||
|
||||
--target world -q
|
||||
|
||||
will give the same result as
|
||||
|
||||
-q --target world
|
||||
|
||||
Note, however, that the order of sequencing is still somewhat significant, in
|
||||
that it affects the generated help text.
|
||||
|
||||
### Choice
|
||||
|
||||
It is quite common to find programs that can be configured in different ways
|
||||
through the command line. A typical example is a program that can be given a
|
||||
text file as input, or alternatively read it directly from the standard input.
|
||||
|
||||
We can model this easily and effectively in Haskell using *sum types*:
|
||||
|
||||
```haskell
|
||||
data Input
|
||||
= FileInput FilePath
|
||||
| StdInput
|
||||
|
||||
run :: Input -> IO ()
|
||||
run = ...
|
||||
```
|
||||
|
||||
However, we can't build a command line parser for the type `Input` using only
|
||||
the primitive blocks introduced so far, plus sequencing. We can certainly
|
||||
define the two basic parsers involved:
|
||||
|
||||
```haskell
|
||||
fileInput :: Parser Input
|
||||
fileInput = FileInput <$> strOption
|
||||
( long "file"
|
||||
<> short 'f'
|
||||
<> metavar "FILENAME"
|
||||
<> help "Input file" )
|
||||
|
||||
stdInput :: Parser Input
|
||||
stdInput = flag' StdInput
|
||||
( long "stdin"
|
||||
<> help "Read from stdin" )
|
||||
```
|
||||
|
||||
but we want to combine them in such a way that only one of them is ever
|
||||
parsed, and never both; alas, the sequencing operator of `Applicative` doesn't
|
||||
allow us to specify this kind of behaviour.
|
||||
|
||||
Fortunately, the `Parser` type constructor is also an instance of `Alternative`,
|
||||
which provides a *choice* operator `(<|>)` for exactly this purpose:
|
||||
|
||||
```haskell
|
||||
opts2 :: Parser Input
|
||||
opts2 = fileInput <|> stdInput
|
||||
```
|
||||
|
||||
Now `--file "foo.txt"` will be parsed as `FileInput "foo.txt"`, `--stdin` will
|
||||
be parsed as `StdInput`, but a command line containing both options, like
|
||||
|
||||
--file "foo.txt" --stdin
|
||||
|
||||
will be rejected.
|
||||
|
||||
### Running parsers
|
||||
|
||||
We have been discussing what parsers do, but so far, we haven't seen how to
|
||||
actually have them process the command line and return a result, or report a
|
||||
failure.
|
||||
|
||||
Before we can run a `Parser`, we need to wrap it into a `ParserInfo` structure,
|
||||
that specifies a number of properties that only apply to top level parsers, such
|
||||
as a header describing what the program does, to be displayed in the help
|
||||
screen.
|
||||
|
||||
The function `info` will help with this step. For the parser `opts` defined
|
||||
above the corresponding `ParserInfo` could look something like:
|
||||
|
||||
```haskell
|
||||
pinfo :: ParserInfo Options
|
||||
pinfo = info (opts <**> helper)
|
||||
( progDesc "Print a greeting for TARGET"
|
||||
<> header "hello - a demo of optparse-applicative" )
|
||||
```
|
||||
|
||||
The `helper` parser that we added after `opts` just creates a dummy `--helper`
|
||||
option that displays the help text. Besides that, we just set some of the
|
||||
fields of the `ParserInfo` structure with meaningful values. They will be
|
||||
displayed in the help text like so:
|
||||
|
||||
hello - a test for optparse-applicative
|
||||
|
||||
Usage: hello --hello TARGET [--quiet]
|
||||
Print a greeting for TARGET
|
||||
|
||||
Available options:
|
||||
-h,--help Show this help text
|
||||
--hello TARGET Target for the greeting
|
||||
--quiet Whether to be quiet
|
||||
|
||||
Now that we have a `ParserInfo`, we can finally run the parser. The simplest
|
||||
way to do so is to simply call the `execParser` function in your `main`:
|
||||
|
||||
```haskell
|
||||
main :: IO ()
|
||||
main = do
|
||||
options <- execParser pinfo
|
||||
...
|
||||
```
|
||||
|
||||
The `execParser` function takes care of everything, including getting the
|
||||
arguments from the command line, and displaying errors and help screens to the
|
||||
user.
|
||||
|
||||
There are other ways to run a `ParserInfo`, in situations where you need finer
|
||||
control over the behavior of your parser, or if you want to use it in pure
|
||||
code. They will be covered in
|
||||
[Custom parsing and error handling](#custom-parsing-and-error-handling).
|
||||
|
||||
## Builders
|
||||
|
||||
Builders allow you to define parsers using a convenient combinator-based
|
||||
syntax. We have already seen examples of builders in action, like `strOption`
|
||||
and `switch`, which we used to define the `opts` parser for our "hello" example.
|
||||
|
||||
Builders always take a [modifier](#modifier) argument, which is essentially a
|
||||
composition of functions acting on the option, setting values for properties or
|
||||
adding features.
|
||||
|
||||
Builders work by building the option from scratch, and eventually lifting it to
|
||||
a single-option parser, ready to be combined with other parsers using normal
|
||||
`Applicative` and `Alternative` combinators.
|
||||
|
||||
See the [haddock documentation][builder-documentation] for
|
||||
`Options.Applicative.Builder` for a full list of builders and modifiers.
|
||||
|
||||
There are four different kinds of options in `optparse-applicative`: regular
|
||||
options, flags, arguments and commands. In the following, we will go over each
|
||||
one of these and describe the builders that can be used to create them.
|
||||
|
||||
### Regular options
|
||||
|
||||
A **regular option** is an option which takes a single argument, parses it, and
|
||||
returns a value.
|
||||
|
||||
A regular option can have a default value, which is used as the result if the
|
||||
option is not found in the command line. An option without a default value is
|
||||
considered mandatory, and produces an error when not found.
|
||||
|
||||
Regular options can have **long** names, or **short** (one-character) names,
|
||||
which determine when the option matches and how the argument is extracted.
|
||||
|
||||
An option with a long name (say "output") is specified on the command line as
|
||||
|
||||
--output filename.txt
|
||||
|
||||
or
|
||||
|
||||
--output=filename.txt
|
||||
|
||||
while a short name option (say "o") can be specified with
|
||||
|
||||
-o filename.txt
|
||||
|
||||
or
|
||||
|
||||
-ofilename.txt
|
||||
|
||||
Options can have more than one name, usually one long and one short, although
|
||||
you are free to create options with an arbitrary combination of long and short
|
||||
names.
|
||||
|
||||
Regular options returning strings are the most common, and they can be created
|
||||
using the `strOption` builder. For example,
|
||||
|
||||
```haskell
|
||||
strOption
|
||||
( long "output"
|
||||
<> short 'o'
|
||||
<> metavar "FILE"
|
||||
<> help "Write output to FILE" )
|
||||
```
|
||||
|
||||
creates a regular option with a string argument (which can be referred to as
|
||||
`FILE` in the help text and documentation), a long name "output" and a short
|
||||
name "o".
|
||||
|
||||
A regular option can return an object of any type, and takes a *reader*
|
||||
parameter which specifies how the argument should be parsed. A common reader is
|
||||
`auto`, which assumes a `Read` instance for the return type and uses it to parse
|
||||
its argument. For example:
|
||||
|
||||
```haskell
|
||||
lineCount :: Parser Int
|
||||
lineCount = option auto
|
||||
( long "lines"
|
||||
<> short 'n'
|
||||
<> metavar "K"
|
||||
<> help "Output the last K lines" )
|
||||
```
|
||||
|
||||
specifies a regular option with an `Int` argument. We added an explicit type
|
||||
annotation here, since without it the parser would have been polymorphic in the
|
||||
output type. There's usually no need to add type annotations, however, because
|
||||
the type will be normally inferred from the context in which the parser is
|
||||
used.
|
||||
|
||||
You can also create a custom reader that doesn't use the `Read` typeclass, and
|
||||
use it to parse option arguments:
|
||||
|
||||
```haskell
|
||||
data FluxCapacitor = ...
|
||||
|
||||
parseFluxCapacitor :: Monad m => String -> m FluxCapacitor
|
||||
|
||||
option parseFluxCapacitor
|
||||
( long "flux-capacitor" )
|
||||
```
|
||||
|
||||
### Flags
|
||||
|
||||
A **flag** is just like a regular option, but it doesn't take any arguments: it is
|
||||
either present in the command line or not.
|
||||
|
||||
A flag has a default value and an **active value**. If the flag is found on the
|
||||
command line, the active value is returned, otherwise the default value is
|
||||
used. For example:
|
||||
|
||||
```haskell
|
||||
data Verbosity = Normal | Verbose
|
||||
|
||||
flag Normal Verbose
|
||||
( long "verbose"
|
||||
<> short 'v'
|
||||
<> help "Enable verbose mode" )
|
||||
```
|
||||
|
||||
is a flag parser returning a `Verbosity` value.
|
||||
|
||||
Simple boolean flags can be specified using the `switch` builder, like so:
|
||||
|
||||
```haskell
|
||||
switch
|
||||
( long "keep-tmp-files"
|
||||
<> help "Retain all intermediate temporary files" )
|
||||
```
|
||||
|
||||
There is also a `flag'` builder, which has no default value. For example, to
|
||||
add a `--version` switch to a program, you could write:
|
||||
|
||||
```haskell
|
||||
flag' Nothing (long "version" <> hidden) <|> (Just <$> normal_options)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
An **argument** parser specifies a positional command line argument.
|
||||
|
||||
The `argument` builder takes a reader parameter, and creates a parser which
|
||||
will return the parsed value every time it is passed a command line argument
|
||||
for which the reader succeeds. For example
|
||||
|
||||
```haskell
|
||||
argument str (metavar "FILE")
|
||||
```
|
||||
|
||||
creates an argument accepting any string. To accept an arbitrary number of
|
||||
arguments, combine the `argument` builder with either the `many` or `some`
|
||||
combinator:
|
||||
|
||||
```haskell
|
||||
some (argument str (metavar "FILES..."))
|
||||
```
|
||||
|
||||
Arguments are only displayed in the brief help text, so there's no need to
|
||||
attach a description to them. They should be manually documented in the program
|
||||
description.
|
||||
|
||||
Note that arguments starting with `-` are considered options by default, and
|
||||
will not be considered by an `argument` parser.
|
||||
|
||||
However, parsers always accept a special argument: `--`. When a `--` is found on
|
||||
the command line, all the following words are considered by `argument` parsers,
|
||||
regardless of whether they start with `-` or not.
|
||||
|
||||
### Commands
|
||||
|
||||
A **command** can be used to specify a sub-parser to be used when a certain
|
||||
string is encountered in the command line.
|
||||
|
||||
Commands are useful to implement command line programs with multiple functions,
|
||||
each with its own set of options, and possibly some global options that apply
|
||||
to all of them. Typical examples are version control systems like `git`, or
|
||||
build tools like `cabal`.
|
||||
|
||||
A command can be created using the `subparser` builder, and commands can be
|
||||
added with the `command` modifier. For example
|
||||
|
||||
```haskell
|
||||
subparser
|
||||
( command "add" (info addOptions
|
||||
( progDesc "Add a file to the repository" ))
|
||||
<> command "commit" (info commitOptions
|
||||
( progDesc "Record changes to the repository" ))
|
||||
)
|
||||
```
|
||||
|
||||
Each command takes a full `ParserInfo` structure, which will be used to extract
|
||||
a description for this command when generating a help text.
|
||||
|
||||
Note that all the parsers appearing in a command need to have the same type.
|
||||
For this reason, it is often best to use a sum type which has the same
|
||||
structure as the command itself. For example, for the parser above, you would
|
||||
define a type like:
|
||||
|
||||
```haskell
|
||||
data Options = Options
|
||||
{ optGlobalOpt :: String
|
||||
, optGlobalFlag :: Bool
|
||||
...
|
||||
, optCommand :: Command }
|
||||
|
||||
data Command
|
||||
= Add AddOptions
|
||||
| Commit CommitOptions
|
||||
...
|
||||
```
|
||||
|
||||
Alternatively, you can directly return an `IO` action from a parser, and
|
||||
execute it using `join` from `Control.Monad`.
|
||||
|
||||
```haskell
|
||||
start :: String -> IO ()
|
||||
stop :: IO ()
|
||||
|
||||
opts :: Parser (IO ())
|
||||
opts = subparser
|
||||
( command "start" (info (start <$> argument str idm) idm)
|
||||
<> command "stop" (info (pure stop) idm) )
|
||||
|
||||
main :: IO ()
|
||||
main = join $ execParser pinfo(info opts idm)
|
||||
```
|
||||
|
||||
### Modifiers
|
||||
|
||||
**Modifiers** are instances of the `Monoid` typeclass, so they can be combined using
|
||||
the composition function `mappend` (or simply `(<>)`). Since different builders
|
||||
accept different sets of modifiers, modifiers have a type parameter that
|
||||
specifies which builders support it.
|
||||
|
||||
For example,
|
||||
|
||||
```haskell
|
||||
command :: String -> ParserInfo a -> Mod CommandFields a
|
||||
```
|
||||
|
||||
can only be used with [commands](#commands), as the `CommandFields` type
|
||||
argument of `Mod` will prevent it from being passed to builders for other types
|
||||
of options.
|
||||
|
||||
Many modifiers are polymorphic in this type argument, which means that they can
|
||||
be used with any builder.
|
||||
|
||||
## Custom parsing and error handling
|
||||
|
||||
### Parser runners
|
||||
### Option readers
|
||||
### Preferences
|
||||
### Disambiguation
|
||||
|
||||
It is possible to configure optparse-applicative to perform automatic
|
||||
disambiguation of prefixes of long options. For example, given a program `foo`
|
||||
with options `--filename` and `--filler`, typing
|
||||
|
||||
$ foo --fil test.txt
|
||||
|
||||
fails, whereas typing
|
||||
|
||||
$ foo --file test.txt
|
||||
|
||||
succeeds, and correctly identifies `"file"` as an unambiguous prefix of the
|
||||
`filename` option.
|
||||
|
||||
Option disambiguation is *off* by default. To enable it, provide the
|
||||
`disambiguate` modifier to the `prefs` builder, and pass the resulting
|
||||
preferences to one of the parser runners that take an `ParserPrefs` parameter,
|
||||
like `customExecParser`.
|
||||
|
||||
Here is a minimal example:
|
||||
|
||||
```haskell
|
||||
import Options.Applicative
|
||||
|
||||
sample :: Parser ()
|
||||
sample = () <$
|
||||
switch (long "filename") <*
|
||||
switch (long "filler")
|
||||
|
||||
main :: IO ()
|
||||
main = customExecParser p opts
|
||||
where
|
||||
opts = info (helper <*> sample) idm
|
||||
p = prefs disambiguate
|
||||
|
||||
```
|
||||
|
||||
### Displaying custom error messages
|
||||
### Customising the help screen
|
||||
|
||||
## Bash completion
|
||||
|
||||
`optparse-applicative` has built-in support for bash completion of command line
|
||||
options and arguments. Any parser, when run using `execParser` (and similar
|
||||
functions), is automatically extended with a few (hidden) options for bash
|
||||
completion:
|
||||
|
||||
- `--bash-completion-script`: this takes the full path of the program as
|
||||
argument, and prints a bash script, which, when sourced into a bash session,
|
||||
will install the necessary machinery to make bash completion work. For a
|
||||
quick test, you can run something like (for a program called `foo` on the
|
||||
`PATH`):
|
||||
|
||||
```console
|
||||
$ source <(foo --bash-completion-script `which foo`)
|
||||
```
|
||||
|
||||
Normally, the output of `--bash-completion-script` should be shipped with
|
||||
the program and copied to the appropriate directory (usually
|
||||
`/etc/bash_completion.d/`) during installation.
|
||||
|
||||
- `--bash-completion-index`, `--bash-completion-word`: internal options used
|
||||
by the completion script to obtain a list of possible completions for a
|
||||
given command line.
|
||||
|
||||
### Actions and completers
|
||||
|
||||
By default, options and commands are always completed. So, for example, if the
|
||||
program `foo` has an option with a long name `output`, typing
|
||||
|
||||
```console
|
||||
$ foo --ou<TAB>
|
||||
```
|
||||
|
||||
will complete `--output` automatically.
|
||||
|
||||
Arguments (either of regular options, or top-level) are not completed by
|
||||
default. To enable completion for arguments, use one of the following modifiers
|
||||
on a regular option or argument:
|
||||
|
||||
- `completeWith`: specifies a list of possible completions to choose from;
|
||||
- `action`: specifies a completion "action". An action dynamically determines
|
||||
a list of possible completions. A full list of actions can be found in the
|
||||
[bash documentation];
|
||||
- `completer`: a completer is a function `String -> IO [String]`, returning
|
||||
all possible completions for a given string. You can use this modifier to
|
||||
specify a custom completion for an argument.
|
||||
|
||||
Completion modifiers can be used multiple times: the resulting completions will
|
||||
call all of them and join the results.
|
||||
|
||||
### Internals
|
||||
|
||||
When running a parser with `execParser`, the parser is extended with
|
||||
`bashCompletionParser`, which defines the above options.
|
||||
|
||||
When completion is triggered, the completion script calls the executable with
|
||||
the special `--bash-completion-index` and `--bash-completion-word` options.
|
||||
|
||||
The original parser is therefore run in *completion mode*, i.e. `runParser` is
|
||||
called on a different monad, which keeps track of the current state of the
|
||||
parser, and exits when all arguments have been processed.
|
||||
|
||||
The completion monad returns, on failure, either the last state of the parser
|
||||
(if no option could be matched), or the completer associated to an option (if
|
||||
it failed while fetching the argument for that option).
|
||||
|
||||
From that we generate a list of possible completions, and print them to
|
||||
standard output. They are then read by the completion script and put into the
|
||||
`COMPREPLY` variable.
|
||||
|
||||
## Arrow interface
|
||||
|
||||
It is also possible to use the [Arrow syntax][arrows] to combine basic parsers.
|
||||
|
||||
This can be particularly useful when the structure holding parse results is
|
||||
deeply nested, or when the order of fields differs from the order in which the
|
||||
parsers should be applied.
|
||||
|
||||
Using functions from the `Options.Applicative.Arrows` module, one can write,
|
||||
for example:
|
||||
|
||||
```haskell
|
||||
data Options = Options
|
||||
{ optArgs :: [String]
|
||||
, optVerbose :: Bool }
|
||||
|
||||
opts :: Parser Options
|
||||
opts = runA $ proc () -> do
|
||||
verbosity <- asA (option (short 'v' <> value 0)) -< ()
|
||||
let verbose = verbosity > 0
|
||||
args <- asA (many (argument str idm)) -< ()
|
||||
returnA -< Options args verbose
|
||||
```
|
||||
|
||||
where parsers are converted to arrows using `asA`, and the resulting composed
|
||||
arrow is converted back to a `Parser` with `runA`.
|
||||
|
||||
See `tests/Examples/Cabal.hs` for a slightly more elaborate example using the
|
||||
arrow syntax for defining parsers.
|
||||
|
||||
Note that the `Arrow` interface is provided only for convenience. The API based
|
||||
on `Applicative` is just as expressive, although it might be cumbersome to use
|
||||
in certain cases.
|
||||
|
||||
## FAQ
|
||||
|
||||
[applicative]: http://hackage.haskell.org/package/base/docs/Control-Applicative.html
|
||||
[arrows]: http://www.haskell.org/arrows/syntax.html
|
||||
[attoparsec]: http://hackage.haskell.org/package/attoparsec
|
||||
[bash documentation]: http://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html
|
||||
[monoid]: http://hackage.haskell.org/package/base/docs/Data-Monoid.html
|
||||
[parsec]: http://hackage.haskell.org/package/parsec
|
Loading…
Reference in New Issue
Block a user