The butcher package

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain]

Warnings:

See the README.


[Skip to ReadMe]

Properties

Versions1.1.0.0, 1.1.0.0, 1.1.0.1, 1.1.0.2, 1.1.1.0, 1.2.0.0
Change logChangeLog.md
Dependenciesbase (>=4.8 && <4.10), bifunctors, containers, deque, either, extra, free, microlens, microlens-th, mtl, multistate, pretty, transformers, unsafe, void [details]
LicenseBSD3
CopyrightCopyright (C) 2016-2017 Lennart Spitzner
AuthorLennart Spitzner
Maintainerlsp@informatik.uni-kiel.de
CategoryUI
Home pagehttps://github.com/lspitzner/butcher/
Bug trackerhttps://github.com/lspitzner/butcher/issues
Source repositoryhead: git clone https://github.com/lspitzner/butcher.git
UploadedTue May 16 22:01:39 UTC 2017 by lspitzner

Modules

[Index]

Flags

NameDescriptionDefaultType
butcher-dev

dev options

DisabledManual

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainers' corner

For package maintainers and hackage trustees


Readme for butcher-1.1.0.0

[back to package description]

butcher

Chops a command or program invocation into digestable pieces.

Similar to the optparse-applicative package, but less features, more flexibility and more evil.

The main differences are:

Examples

The minimal example is

main = mainFromCmdParser $ addCmdImpl $ putStrLn "Hello, World!"

But lets look at a more feature-complete example:

main = mainFromCmdParserWithHelpDesc $ \helpDesc -> do

  addCmdSynopsis "a simple butcher example program"
  addCmdHelpStr "a very long help document"

  addCmd "version" $ do
    porcelain <- addSimpleBoolFlag "" ["porcelain"]
      (flagHelpStr "print nothing but the numeric version")
    addCmdHelpStr "prints the version of this program"
    addCmdImpl $ putStrLn $ if porcelain
      then "0.0.0.999"
      else "example, version 0.0.0.999"

  addCmd "help" $ addCmdImpl $ print $ ppHelpShallow helpDesc

  short <- addSimpleBoolFlag "" ["short"]
    (flagHelpStr "make the greeting short")
  name <- addStringParam "NAME"
    (paramHelpStr "your name, so you can be greeted properly")

  addCmdImpl $ do
    if short
      then putStrLn $ "hi, " ++ name ++ "!"
      else putStrLn $ "hello, " ++ name ++ ", welcome from butcher!"

Further:

The evil monadic interface

As long as you only use Applicative or (Kleisli) Arrow, you can use the interface freely. When you use Monad, there is one rule: Whenever you read any command-parts like in

f <- addFlag ...
p <- addParam ...

you are only allowed to use bindings bound thusly in any command's implemenation, i.e. inside the parameter to addCmdImpl. You are not allowed to force/inspect/patternmatch on them before that. good usage is:

addCmdImpl $ do
  print x
  print y

while bad would be

f <- addFlag
when f $ do
  p <- addParam
  -- evil: the existence of the param `p`
  -- depends on parse result for the flag `f`.

That means that checking if a combination of flags is allowed must be done after parsing. (But different commands and their subcommands (can) have separate sets of flags.)

(abstract) Package intentions

Consider a commandline invocation like "ghc -O -i src -Main.hs -o Main". This package provides a way for the programmer to simultaneously define the semantics of your program based on its arguments and retrieve documentation for the user. More specifically, i had three goals in mind:

  1. Straight-forward description of (sub)command and flag-specific behaviour
  2. Extract understandable usage/help commandline documents/texts from that descriptions, think of ghc --help or stack init --help.
  3. Extract necessary information to compute commandline completion results from any partial input. (This is not implemented to any serious degree.)

Semantics

Basic elements of a command are flags, parameters and subcommands. These can be composed in certain ways, i.e. flags can have a (or possibly multiple?) parameters; parameters can be grouped into sequences, and commands can have subcommands.

Commands are essentially String -> Either ParseError out where out can be chosen by the user. It could for example be IO ().

To allow more flexible composition, the parts of a command have the "classic" parser's type: String -> Maybe (p, String) where p depends on the part. Parse a prefix of the input and return something and the remaining input, or fail with Nothing.

A command-parser contains a sequence of parts and then a number of subcommands and/or some implementation.

Commands and Child-Commands

Flags

Params

TODO