commander-cli: A command line argument/option parser library

[ cli, library, mit, options, parsing, program, system ] [ Propose Tags ]

A command line argument/option parser library.


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.1.0.0, 0.2.0.0, 0.2.0.1, 0.3.0.0, 0.4.0.0, 0.4.0.1, 0.4.1.1, 0.4.1.2, 0.5.0.0, 0.6.0.0, 0.6.1.0, 0.6.2.0, 0.7.0.0, 0.8.0.0, 0.9.0.0, 0.10.0.0, 0.10.0.1, 0.10.1.0, 0.10.1.1, 0.10.1.2, 0.10.1.3, 0.10.2.0, 0.11.0.0
Change log CHANGELOG.md
Dependencies base (>=4.12 && <5), bytestring (>=0.8 && <1), commander-cli, commandert (>=0.1), containers (>=0.1), directory (>=1.3 && <2), mtl (>=2.2 && <3), process (>=1.6 && <2), text (>=1.2 && <2), unordered-containers (>=0.2 && <1) [details]
License MIT
Copyright 2019 Samuel Schlesinger
Author Samuel Schlesinger
Maintainer sgschlesinger@gmail.com
Category System, CLI, Options, Parsing
Home page https://github.com/SamuelSchlesinger/commander-cli
Bug tracker https://github.com/SamuelSchlesinger/commander-cli/issues
Source repo head: git clone https://github.com/samuelschlesinger/commander-cli
Uploaded by sgschlesinger at 2020-10-06T18:40:54Z
Distributions NixOS:0.11.0.0
Executables task-manager
Downloads 4203 total (52 in the last 30 days)
Rating 2.0 (votes: 1) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2020-10-06 [all 1 reports]

Readme for commander-cli-0.10.0.0

[back to package description]

Commander CLI

Hackage Build Status

This library is meant to allow Haskell programs to quickly and easily construct command line interfaces which are easy to use, especially as a Haskell user. To learn, I suggest viewing/playing with the task-manager application which comes with this repository. Here, we'll display a simpler example:

main = command_ . toplevel @"argument-taker" . arg @"example-argument" $ raw . putStrLn

When you run this program with argument-taker help, you will see:

usage:
name: argument-taker
|
+- subprogram: help
|
`- argument: example-argument :: [Char]

The meaning of this is that every path in the tree is a unique command. The one we've used is the help command. If we run this program with argument-taker hello we will see:

hello

Okay, so we've made a program with hardly any scaffolding that gives us a decent help message, and pipes through our argument correctly. Naturally, we might want to expand on the documentation of this program, as its not quite obvious enough what it does.

main = command_ . toplevel @"argument-taker" . arg @"example-argument" $ (description @"Takes the argument and prints it" . raw . putStrLn)

Printing out the documentation again with argument-taker help, we see:

usage:
name: argument-taker
|
+- subprogram: help
|
`- argument: example-argument :: [Char]
   |
   `- description: Takes the argument and prints it

Okay, so we can expand the documentation. But what if I have an option to pass to the same program? Well, we can pass an option like so:

main = command_ . toplevel @"argument-taker" $
  opt @"m" @"mode" \mode ->
    arg @"example-argument" $ \arg ->
      description @"Takes the argument and prints it or not, depending on the mode" . raw $ do
        if mode == "Print" then putStrLn arg else pure ()

Now, when we run argument-taker help we will see:

usage:
name: argument-taker
|
+- subprogram: help
|
`- option: -m <mode :: [Char]>
   |
   `- argument: example-argument :: [Char]
      |
      `- description: Takes the argument and prints it or not, depending on the mode

Design

The library is based around the following classes:

class Unrender r where
  unrender :: Text -> Maybe r

This class is what you will use to define the parsing of a type from text and can use any parsing library or whatever you want. Next, we have the class

class HasProgram p where
  data ProgramT p m a
  run :: ProgramT p IO a -> CommanderT State IO a
  hoist :: (forall x. m x -> n x) -> ProgramT p m a -> ProgramT p n a
  documentation :: Forest String

Instances of this class will define a syntactic element, a new instance of the data family ProgramT, as well as its semantics in terms of the CommanderT monad, which is something like a free backtracking monad. Users should not have to make instances of this class, as the common CLI elements are already defined as instances. Of course, you can if you want to, and it can be profitable to do so.