Code Monkey home page Code Monkey logo

cmdargs's Introduction

CmdArgs: Easy Command Line Processing Hackage version Stackage version Build status

CmdArgs is a Haskell library for defining command line parsers. The two features that make it a better choice than the standard getopt library are:

  • It's very concise to use. The HLint command line handling is three times shorter with CmdArgs.
  • It supports programs with multiple modes, such as darcs or Cabal.

A very simple example of a command line processor is:

data Sample = Sample {hello :: String} deriving (Show, Data, Typeable)

sample = Sample{hello = def &= help "World argument" &= opt "world"}
         &= summary "Sample v1"

main = print =<< cmdArgs sample

Despite being very concise, this processor is already fairly well featured:

$ runghc Sample.hs --hello=world
Sample {hello = "world"}

$ runghc Sample.hs --help
Sample v1, (C) Neil Mitchell 2009

sample [FLAG]

  -? --help[=FORMAT]  Show usage information (optional format)
  -V --version        Show version information
  -v --verbose        Higher verbosity
  -q --quiet          Lower verbosity
  -h --hello=VALUE    World argument (default=world)

User Manual

The rest of this document explains how to write the "hello world" of command line processors, then how to extend it with features into a complex command line processor. Finally this document gives three samples, which the cmdargs program can run. The three samples are:

  • hlint - the HLint program.
  • diffy - a program to compare the differences between directories.
  • maker - a make style program.

For each example you are encouraged to look at it's source (in the repo) and run it (try cmdargs hlint --help). The HLint program is fairly standard in terms of it's argument processing, and previously used the System.Console.GetOpt library. Using GetOpt required 90 lines and a reasonable amount of duplication. Using CmdArgs the code requires 30 lines, and the logic is much simpler.

Acknowledgements Thanks to Kevin Quick for substantial patches, and additional code contributions from Sebastian Fischer and Daniel Schoepe.

Hello World Example

The following code defines a complete command line argument processor:

{-# LANGUAGE DeriveDataTypeable #-}
{-# OPTIONS_GHC -fno-cse #-}
module Sample where
import System.Console.CmdArgs

data Sample = Sample {hello :: String}
              deriving (Show, Data, Typeable)

sample = Sample{hello = def}

main = print =<< cmdArgs sample

To use the CmdArgs library there are three steps:

  • Define a record data type (Sample) that contains a field for each argument. This type needs to have instances for Show, Data and Typeable.
  • Give a value of that type (sample) with default values (def is a default value of any type, but I could also have written ""). This value is turned into a command line by calling the cmdArgs function.
  • To ensure GHC evalutes attributes the right number of times we disable the CSE optimisation on this module.

Now we have a reasonably functional command line argument processor. Some sample interactions are:

$ runghc Sample.hs --hello=world
Sample {hello = "world"}

$ runghc Sample.hs --version
The sample program

$ runghc Sample.hs --help
The sample program

sample [OPTIONS]

  -? --help        Display help message
  -V --version     Print version information
  -h --hello=ITEM

CmdArgs uses defaults to automatically infer a command line parser for a value, and provides annotations to override any of the the defaults. CmdArgs automatically supports --help and --version flags, and optionally supports verbosity flags.

Specifying Attributes

In order to control the behaviour we can add attributes. For example to add an attribute specifying the help text for the --hello argument we can write:

sample = Sample{hello = def &= help "Who to say hello to"}

We can add additional attributes, for example to specify the type of the value expected by hello:

sample = Sample {hello = def &= help "Who to say hello to" &= typ "WORLD"}

Now when running --help the final line is:

  -h --hello=WORLD  Who to say hello to

There are many more attributes, detailed in the Haddock documentation.

Multiple Modes

To specify a program with multiple modes, similar to darcs, we can supply a data type with multiple constructors, for example:

data Sample = Hello {whom :: String}
            | Goodbye
              deriving (Show, Data, Typeable)

hello = Hello{whom = def}
goodbye = Goodbye

main = print =<< cmdArgs (modes [hello,goodbye])

Compared to the first example, we now have multiple constructors, and a sample value for each constructor is passed to cmdArgs. Some sample interactions with this command line are:

$ runghc Sample.hs hello --whom=world
Hello {whom = "world"}

$ runghc Sample.hs goodbye
Goodbye

$ runghc Sample.hs --help
The sample program

sample [OPTIONS]

 Common flags
  -? --help       Display help message
  -V --version    Print version information

sample hello [OPTIONS]

  -w --whom=ITEM

sample goodbye [OPTIONS]

As before, the behaviour can be customised using attributes.

Larger Examples

For each of the following examples we first explain the purpose of the program, then give the source code, and finally the output of --help. The programs are intended to show sample uses of CmdArgs, and are available to experiment with through cmdargs progname.

HLint

The HLint program analyses a list of files, using various options to control the analysis. The command line processing is simple, but a few interesting points are:

  • The --report flag can be used to output a report in a standard location, but giving the flag a value changes where the file is output.
  • The color field is assigned two flag aliases, --colour and -c. Assigning the -c short flag explicitly stops either of the CPP fields using it.
  • The show_ field would clash with show if given the expected name, but CmdArgs automatically strips the trailing underscore.
  • The cpp_define field has an underscore in it's name, which is transformed into a hyphen for the flag name.

The code is:

{-# LANGUAGE DeriveDataTypeable #-}
module HLint where
import System.Console.CmdArgs

data HLint = HLint
    {report :: [FilePath]
    ,hint :: [FilePath]
    ,color :: Bool
    ,ignore_ :: [String]
    ,show_ :: Bool
    ,extension :: [String]
    ,language :: [String]
    ,utf8 :: Bool
    ,encoding :: String
    ,find :: [FilePath]
    ,test_ :: Bool
    ,datadir :: [FilePath]
    ,cpp_define :: [String]
    ,cpp_include :: [FilePath]
    ,files :: [FilePath]
    }
    deriving (Data,Typeable,Show,Eq)

hlint = HLint
    {report = def &= opt "report.html" &= typFile &= help "Generate a report in HTML"
    ,hint = def &= typFile &= help "Hint/ignore file to use"
    ,color = def &= name "c" &= name "colour" &= help "Color the output (requires ANSI terminal)"
    ,ignore_ = def &= typ "MESSAGE" &= help "Ignore a particular hint"
    ,show_ = def &= help "Show all ignored ideas"
    ,extension = def &= typ "EXT" &= help "File extensions to search (defaults to hs and lhs)"
    ,language = def &= name "X" &= typ "LANG" &= help "Language extension (Arrows, NoCPP)"
    ,utf8 = def &= help "Use UTF-8 text encoding"
    ,encoding = def &= typ "ENC" &= help "Choose the text encoding"
    ,find = def &= typFile &= help "Find hints in a Haskell file"
    ,test_ = def &= help "Run in test mode"
    ,datadir = def &= typDir &= help "Override the data directory"
    ,cpp_define = def &= typ "NAME[=VALUE]" &= help "CPP #define"
    ,cpp_include = def &= typDir &= help "CPP include path"
    ,files = def &= args &= typ "FILES/DIRS"
    } &=
    verbosity &=
    help "Suggest improvements to Haskell source code" &=
    summary "HLint v0.0.0, (C) Neil Mitchell" &=
    details ["Hlint gives hints on how to improve Haskell code",""
            ,"To check all Haskell files in 'src' and generate a report type:","  hlint src --report"]

mode = cmdArgsMode hlint

Produces the --help output:

HLint v0.0.0, (C) Neil Mitchell

hlint [OPTIONS] [FILES/DIRS]
Suggest improvements to Haskell source code

Common flags:
  -r --report[=FILE]            Generate a report in HTML
  -h --hint=FILE                Hint/ignore file to use
  -c --colour --color            Color the output (requires ANSI terminal)
  -i --ignore=MESSAGE            Ignore a particular hint
  -s --show                     Show all ignored ideas
     --extension=EXT            File extensions to search (defaults to hs and lhs)
  -X --language=LANG            Language extension (Arrows, NoCPP)
  -u --utf8                        Use UTF-8 text encoding
     --encoding=ENC                Choose the text encoding
  -f --find=FILE                Find hints in a Haskell file
  -t --test                        Run in test mode
  -d --datadir=DIR                Override the data directory
     --cpp-define=NAME[=VALUE]  CPP #define
     --cpp-include=DIR            CPP include path
  -? --help                        Display help message
  -V --version                    Print version information
  -v --verbose                    Loud verbosity
  -q --quiet                    Quiet verbosity

Hlint gives hints on how to improve Haskell code

To check all Haskell files in 'src' and generate a report type:
  hlint src --report

Diffy

The Diffy sample is a based on the idea of creating directory listings and comparing them. The tool can operate in two separate modes, create or diff. This sample is fictional, but the ideas are drawn from a real program. A few notable features:

  • There are multiple modes of execution, creating and diffing.
  • The diff mode takes exactly two arguments, the old file and the new file.
  • Default values are given for the out field, which are different in both modes.

The code is:

{-# LANGUAGE DeriveDataTypeable #-}
module Diffy where
import System.Console.CmdArgs

data Diffy = Create {src :: Maybe FilePath, out :: FilePath}
           | Diff {old :: FilePath, new :: FilePath, out :: FilePath}
             deriving (Data,Typeable,Show,Eq)

outFlags x = x &= help "Output file" &= typFile

create = Create
    {src = def &= help "Source directory" &= typDir
    ,out = outFlags "ls.txt"
    } &= help "Create a fingerprint"

diff = Diff
    {old = def &= typ "OLDFILE" &= argPos 0
    ,new = def &= typ "NEWFILE" &= argPos 1
    ,out = outFlags "diff.txt"
    } &= help "Perform a diff"

mode = cmdArgsMode $ modes [create,diff] &= help "Create and compare differences" &= program "diffy" &= summary "Diffy v1.0"

And --help produces:

Diffy v1.0

diffy [COMMAND] ... [OPTIONS]
  Create and compare differences

Common flags:
  -o --out=FILE     Output file
  -? --help         Display help message
  -V --version     Print version information

diffy create [OPTIONS]
  Create a fingerprint

  -s  --src=DIR  Source directory

diffy diff [OPTIONS] OLDFILE NEWFILE
  Perform a diff

Maker

The Maker sample is based around a build system, where we can either build a project, clean the temporary files, or run a test. Some interesting features are:

  • The build mode is the default, so maker on it's own will be interpreted as a build command.
  • The build method is an enumeration.
  • The threads field is in two of the constructors, but not all three. It is given the short flag -j, rather than the default -t.

The code is:

{-# LANGUAGE DeriveDataTypeable #-}
module Maker where
import System.Console.CmdArgs

data Method = Debug | Release | Profile
              deriving (Data,Typeable,Show,Eq)

data Maker
    = Wipe
    | Test {threads :: Int, extra :: [String]}
    | Build {threads :: Int, method :: Method, files :: [FilePath]}
      deriving (Data,Typeable,Show,Eq)

threadsMsg x = x &= help "Number of threads to use" &= name "j" &= typ "NUM"

wipe = Wipe &= help "Clean all build objects"

test_ = Test
    {threads = threadsMsg def
    ,extra = def &= typ "ANY" &= args
    } &= help "Run the test suite"

build = Build
    {threads = threadsMsg def
    ,method = enum
        [Release &= help "Release build"
        ,Debug &= help "Debug build"
        ,Profile &= help "Profile build"]
    ,files = def &= args
    } &= help "Build the project" &= auto

mode = cmdArgsMode $ modes [build,wipe,test_]
     &= help "Build helper program"
     &= program "maker"
     &= summary "Maker v1.0\nMake it"

And --help produces:

Maker v1.0
  Make it

maker [COMMAND] ... [OPTIONS]
  Build helper program

Common flags:
  -? --help     Display help message
  -V --version  Print version information

maker [build] [OPTIONS] [ITEM]
  Build the project

  -j --threads=NUM  Number of threads to use
  -r --release      Release build
  -d --debug        Debug build
  -p --profile      Profile build

maker wipe [OPTIONS]
  Clean all build objects

maker test [OPTIONS] [ANY]
  Run the test suite

  -j --threads=NUM  Number of threads to use

cmdargs's People

Contributors

aavogt avatar dschoepe avatar elvishjerricco avatar kquick avatar mklca avatar ndmitchell avatar ozgurakgun avatar ryanglscott avatar sapek avatar sol avatar thisiswhereitype avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

cmdargs's Issues

Add union flags

Sometimes it is useful for one field to be controlled by two flags, for example --encoding=ENC or --utf8 as an alias for --encoding=utf8. I should support that somehow.

Switch to js-jquery

The cmdargs-browser mode should switch to js-jquery. I should also write a blog post about it, since I don't think anyone knows it exists.

Comments in args file

Please note that I am not too familiar with cmdargs but am a user of hledger, which uses cmdargs for parsing arguments stored in text files.
As specified in an issue there, I find that it would be very convenient to have comments in the argument files.
In case the functionality of reading the argument files is indeed part of cmdargs, would you consider ignoring lines that start with ";" (or other delimiters), for example, and leave them as comments.
This might be really useful for cases when there are multiple or confusing arguments, or just temporarily removing some of them.
Thanks!

Unable to make args mandatory

Hello! Great library, thank you. I'm struggling though, and i feel like i'm doing what the docs say i should do. I'm using version cmdargs-0.10.12.

So i have this bit of code:

data DiaspecCompiler = Pretty { inFile :: FilePath
                              , outFile :: Maybe FilePath}
                     | Racket { inFile :: FilePath
                              , outFile :: Maybe FilePath}
                     | Java   { inFile :: FilePath }
                     deriving (Show, Data, Typeable)

pretty = Pretty { inFile = def &= args &= typFile
                , outFile = Nothing &= typFile} 

java   = Java   { inFile = def &= args &= typFile }

racket = Racket { inFile = def &= args &= typFile
                , outFile = Nothing &= typFile} 

mode = cmdArgsMode $ modes [racket, java, pretty]

main :: IO ()
main = do
  opt <- cmdArgsRun mode

When i run ./mything --help i get the following output, though:

The diaspeccompiler program

diaspeccompiler [COMMAND] ... [OPTIONS]

Common flags:
  -? --help          Display help message
  -V --version       Print version information

diaspeccompiler racket [OPTIONS] [FILE]

  -o --outfile=FILE

diaspeccompiler java [OPTIONS]

  -i --infile=ITEM 

diaspeccompiler pretty [OPTIONS]

  -i --infile=ITEM 
  -o --outfile=ITEM

Which looks like nonsense to me. I expect each mode to have a mandatory FILE argument at the end, since all modes must operate on an input file. Where is the -i option coming from? Am i doing something brain-dead?

'&= help' incorrectly works with 'newtype'

I tested cmdargs-0.10.12.

data Foo = Foo { arg :: Bool } deriving (Show, Data, Typeable)

foo :: Foo
foo = Foo { arg = False &= help "arg help" }

main :: IO ()
main =
  print =<< cmdArgs foo

returns

The foo program

foo [OPTIONS]

Common flags:
  -a --arg      arg help
  -? --help     Display help message
  -V --version  Print version information

If I change 'data' to 'newtype':

The foo program

foo [OPTIONS]
  arg help

Common flags:
  -a --arg    
  -? --help     Display help message
  -V --version  Print version information

The pure version works as expected:

newtype Foo = Foo { arg :: Bool } deriving (Show, Data, Typeable)

foo = record Foo {} [ arg := False += help "arg help" ]

main :: IO ()
main =
  print =<< (cmdArgs_ foo :: IO Foo)

System.Console.CmdArgs.Explicit.helpText: required arguments are rendered as optional and vice versa

The help text rendering (System.Console.CmdArgs.Explicit.helpText) renders required arguments as optional (with square brackets) and optional arguments as required (without square brackets).

Example

module CmdArgsExplicit where

import System.Console.CmdArgs.Explicit
import System.Console.CmdArgs.Text


argMode :: Mode ()
argMode = (modeEmpty ())
  { modeNames = ["Main"]
  , modeArgs = ([argReq, argOpt], Nothing)
  }
  where
    argReq = (flagArg (\ _ _ -> Right ()) "REQ"){argRequire = True}
    argOpt =  flagArg (\ _ _ -> Right ()) "OPT"


main :: IO ()
main
  = putStr
  $ showText defaultWrap
  $ helpText [] HelpFormatAll argMode

Expected output: Main REQ [OPT]

Actual output: Main [REQ] OPT

PS

The function flagArg creates optional arguments. I would prefer, if it created required arguments.

Nevertheless, CmdArgs is really awesome!

Support nested records

From http://code.google.com/p/ndmitchell/issues/detail?id=291:

@aavogt says: cmdargs should support nested records:

> data A = A { optA :: X, optB :: Y }
> data Y = Y { xopt :: X, optionY :: Bool }
> data X = X { path :: String, optionX :: Bool }

It should be possible to use:

> mode (A (X "here" True) (Y (X "there" False) True)

Which would infer flags including:

 --opta-optionx, --optb-xopt-path

It would be nice not to have to expand the redundancy in the arguments in
the usage description, but I'm not sure when or how that should be done.

@ndmitchell replied:It's possible it should just infer --optionx and --path, so the nesting is for the
author of CmdArgs, not the user. Anyway, something should be done.

sudo-like cli: a way to instruct `cmdargs` to not look for flags in the remaining arguments

I am working on a program that has sudo-like interface:

sudo ls
sudo ls -l
sudo -u joe ls -l /

Here's my current code:

#!/usr/bin/env stack
-- stack --resolver lts-9.20 script --package cmdargs

{-# LANGUAGE DeriveDataTypeable #-}
{-# OPTIONS_GHC -fno-cse #-}

module Main where

import           System.Console.CmdArgs as Args
import           System.IO

data Sudo = Sudo { user        :: Maybe String
                 , group       :: Maybe String
                 , command     :: [String] }
              deriving (Data, Show)

main :: IO ()
main = do
  m <- cmdArgs Sudo { user    = def
                    , group   = def
                    , command = def &= typ "COMMAND" &= args  }

  print m

It works fine for commands without flags or when -- is used to mark the end of flags.

$ ./cmdargs.hs ls 1 2 3
Sudo {user = Nothing, group = Nothing, command = ["ls","1","2","3"]}

$ ./cmdargs.hs -- ls -l
Sudo {user = Nothing, group = Nothing, command = ["ls","-l"]}

$ ./cmdargs.hs -u joe -- ls -l
Sudo {user = Just "joe", group = Nothing, command = ["ls","-l"]}

However, it doesn't work when a sub-command has flags and when -- is not used:

$ ./cmdargs.hs ls -l
Unknown flag: -l

$ ./cmdargs.hs -u joe ls -l
Unknown flag: -l

Q: How to instruct cmdargs to not look for flags in the remaining arguments?

Generate help text if no default mode was specified

Hi thank you for this awesome helper.
I am struggling trying to get the help text as default command if no options were specified for example:

$ mycli

should generate the same output as

$ mycli --help

Do you have any hint to lead me to a possible solution?
Thank you

Using `&= help` with `&= argPos` throws an error

I can use argPos just fine, but if I add a help param, I get

CallStack (from HasCallStack):
  error, called at ./System/Console/CmdArgs/Implicit/Local.hs:106:11 in cmdargs-0.10.20-F07nW8QLYyL7Sb2sj6I5zi:System.Console.CmdArgs.Implicit.Local

Is there another way I'm supposed to be documenting positional arguments? If so, a better error message and docs to show this would be helpful, ideally it shouldn't type check.

I'm using stack with ghc 8.4.3, if it matters

modeHelp eats blank lines

I have a mode-building helper that wants to show multiple blank-line-separated paragraphs of help text, above the cmdargs-generated flags/subcommands help. This means using modeHelp, not modeHelpSuffix, but it seems blank lines in modeHelp are always removed. How about a PR to change that ?

Allow flags with newlines for their description

Split out from #17 by @ozgurakgun:

About the help-text, here is what I mean. (I probably should have created a separate issue for this, sorry.)

{-# LANGUAGE DeriveDataTypeable #-}
{-# OPTIONS_GHC -fno-cse #-}

module Main where

-- cmdargs-0.10.12
import System.Console.CmdArgs

data Program = Program { someFile :: FilePath }
    deriving (Eq, Ord, Show, Data, Typeable)

ui :: Program
ui = Program
    { someFile = def &= help "Help line 1\n\
                             \Help line 2."
    } &= help "Some more\ntext."

main :: IO ()
main = cmdArgs ui >>= print

The output I get is the following.

$ ghc -O2 repro.hs && ./repro --help
[1 of 1] Compiling Main             ( repro.hs, repro.o )
Linking repro ...
The program program

program [OPTIONS]
  Some more text.

Common flags:
  -s --somefile=ITEM  Help line 1 Help line 2.
  -? --help           Display help message
  -V --version        Print version information

man and info generation

It would be nice to generate basic man pages and info manuals out of the information that is already provided for help messages, but currently help2man (versions 1.41.1 and 1.47.4) fails to process cmdargs output well, particularly when modes are used: synopsis doesn't get extracted, different modes fall into the "common flags" section, etc.

One way to solve this is to aim help2man compatibility: though the multi-mode programs are not explicitly covered in its recommendations, it's still possible to rearrange the output so that all the different forms get synopsis lines, and per-mode sections elaborate on those, listing mode-specific options. A nice side effect of such an approach is that users would also get more conventional --help output.

Another approach is to generate those out of cmdArgs annotations, from cmdargs itself (--help=man, --help=info) or an additional library based on it. This could be used simultaneously with the previous one as well.

Generating bash completion

Wondering if you've given any thought to this. It seems like there's room for something awesome. I assume it would go in a separate package. I can see about tackling it myself (and will, when it rises sufficiently high on my list of projects) but 1) I don't want to step on your toes if you have plans there, and 2) I'm happy for any thoughts or guidance you might have if I do sit down to it.

Thanks for the great package!

Does not print help message for all options with the same help message in multiple modes

I found that if in different modes there are options with the same help message then all options lacks this message except the first one.
It is my test case program:

{-# LANGUAGE DeriveDataTypeable #-}
module Main where

import System.Console.CmdArgs

data Flags = Mode1 { opt1 :: Bool }
           | Mode2 { opt2 :: Bool }
           | Mode3 { opt3 :: Bool }
             deriving (Data, Typeable, Show)

commonHelpMessage = "Common help message"

mode1 = Mode1 { opt1 = def &= help commonHelpMessage }
mode2 = Mode2 { opt2 = def &= help commonHelpMessage }
mode3 = Mode3 { opt3 = def &= help commonHelpMessage }

main :: IO ()
main = do
  cmdArgs $ modes [mode1, mode2, mode3]
  return ()

and when running with a single option of --help the program prints to STDOUT:

The flags program

flags [COMMAND] ... [OPTIONS]

Common flags:
  -? --help     Display help message
  -V --version  Print version information

flags mode1 [OPTIONS]

  -o --opt1     Common help message

flags mode2 [OPTIONS]

  -o --opt2   

flags mode3 [OPTIONS]

  -o --opt3 

This error is reproduced with cmdargs=0.10.17 on Ubuntu 16.04. Just in case I created this repo for reproduction of the error.

Default Lists?

Say I have command line arguments, and one of the things that I want to accept is a list of arguments. Let's just use the example from here:

https://zuttobenkyou.wordpress.com/2011/04/19/haskell-using-cmdargs-single-and-multi-mode/

So, I have a list of formats, and I might want to specify several of them.

data Format     = Text
                | TeX
                | HTML
                | FNone
    deriving (Data, Typeable, Show, Eq)

data MyOptions = MyOptions
    { ...
    , format :: [Format]
    , ...
    } deriving (Data, Typeable, Show, Eq)

myProgOpts = MyOptions
    { ...
    , format = [] &= help "format of output"
    , ...
    }

This seems to work well, but when format is, say [TeX] by default (instead of the empty list) I would expect the behavior to be [TeX] when no argument is passed in, but if I do something like... -f Text -f HTML I would expect to get [Text, HTML]. Instead you get a list with [Tex, Text, HTML].

Is this the expected behaviour? Is there any way to get my desired behaviour of [Text, HTML]?

Thanks in advance!

Add command aliases

From http://code.google.com/p/ndmitchell/issues/detail?id=444:

Often programs need command line aliases, for example in HLint --utf8 == --encoding=UTF8, and for Hoogle --all == --count=1000000. These should be supported properly, for example, I could add:

alias "--encoding=UTF8" &= name "utf" etc.

Should these be specified at the bottom of the flags? How do I control where the flags appear in the help list? Should you be allowed alias "--opt-foo --opt-bar" "-O1" ? There's something scope for something there.

Using enum to set mupltiple flags in a field causes runtime failure.

Attempting to run the following minimal example given in the documentation for enum:

{-#LANGUAGE DeriveDataTypeable#-}

import System.Console.CmdArgs

data State = On | Off deriving (Data, Show)
data Mode = Mode {state :: [State]} deriving (Show, Data)
main = print =<< cmdArgs Mode{state = enum [[] &= ignore, [On] &= help "Turn on", [Off] &= help "Turn off"]}

results in the error message:
System.Console.CmdArgs.Implicit, unexpected no available name: ? regardless of the flags passed to the executable.

I've only tested this with GHC 7.10.1

expandArgsAt doesn't understand ~

expandArgsAt and @ARGSFILE seems a great feature, which I've enabled in hledger 1.4.

I notice that @~/some/file doesn't work though, you have to write @$HOME/some/file instead. Perhaps there is some extra level of file path expansion that would be appropriate for it to do.

cmdArgsRun on an invalid flag should say how to get help

From http://code.google.com/p/ndmitchell/issues/detail?id=418

Compare ghc (not cmdargs) with Hoogle (cmdargs):

$ ghc -h
ghc: unrecognised flags: -h

Usage: For basic information, try the `--help' option.

$ hoogle -h
Unknown flag: -h

Using cmdArgsRun, it should always output try the --help option (assuming the help option hasn't been renamed). Suggested by Nick Wu.

And an additional possible idea from bug #425 :

An alternative would be to define a variant of cmdArgsRun which interprets null getArgs to mean that it should print the help message (perhaps with a Bool argument to turn this on and off). Ideally, this variant would also allow other configurations like where to direct the printed output, etc, which could all be bundled together into a CmdArgsRunConfig argument.

@jfeltz remarked: This may be totally out of context, but with 0.10.2 I've gotten around this by calling Explicit.process directly:

import qualified System.Console.CmdArgs.Explicit as Exp                                                  

mode :: Mode (CmdArgs ProgramName)
mode = ...

main :: IO ()
main =
    env_args <- getArgs

    case (Exp.process mode env_args) of
      Right res ->
        case (cmdArgsHelp res) of
          Just h -> putStr h
          Nothing -> myHandleResultFunction $ cmdArgsValue res
      Left err  -> putStr $ err ++ "\n " ++ "(--help for assistance)\n"

This seems to work. Though I'm not sure what the full consequences/implications here are, I've just started using the library.

(Thanks @jfeltz for the suggestion, I had missed it on the Google bug tracker, but I've got it written down now for when I go through the GitHub tracker.)

Different (non-working) output with ghc -O (ghc 7.8.3)

Hi,

When I compile a modal application with optimizations on (such as is done by default with cabal), the command line parsing doesn't work as expected. Here's a small example program:

{-# LANGUAGE DeriveDataTypeable #-}

module Main
where
import System.Console.CmdArgs

data ProgramMode = Mode1 {
                common :: String,
                private1 :: String
            }
            | Mode2 {
                common :: String,
                private2 :: String
            } deriving (Show, Data, Typeable)

mode1 :: ProgramMode
mode1 = Mode1
    {
        private1 = def,
        common = def &= argPos 0
    }

mode2 :: ProgramMode
mode2 = Mode2
    {
        private2 = def,
        common = def &= argPos 0
    }

main :: IO ()
main = do
    let m = modes [mode1, mode2]
    parsedArgs <- cmdArgs m
    print parsedArgs

This is what should happen, compiled with ghc --make Main.hs:

[ipuustin@ipuustin-mobl1 cmdargs]$ ./Main -?
The programmode program

programmode [COMMAND] ... [OPTIONS]

Common flags:
  -? --help           Display help message
  -V --version        Print version information

programmode mode1 [OPTIONS] ITEM

  -p --private1=ITEM

programmode mode2 [OPTIONS] ITEM

  -p --private2=ITEM

This is the error case when the second mode doesn't work, compiled with ghc --make -O Main.hs:

[ipuustin@ipuustin-mobl1 cmdargs]$ ./Main -?
The programmode program

 programmode [COMMAND] ... [OPTIONS]

Common flags:
  -? --help           Display help message
  -V --version        Print version information

programmode mode1 [OPTIONS] ITEM

  -p --private1=ITEM

programmode mode2 [OPTIONS]

  -c --common=ITEM  
  -p --private2=ITEM

I'm using GHC 7.8.3:

[ipuustin@ipuustin-mobl1 cmdargs]$ ghc -V
The Glorious Glasgow Haskell Compilation System, version 7.8.3

Ability to change the value of defaultWrap

As the title says, I'd like to be able to change the value of defaultWrap in my program. I know I can pass, for example, --help=120 if I wanted to but I want to change the default, which is currently 80.

I am not sure how portable or worth the effort this is, but the terminal-size library or something similar could also be nice.

This becomes particularly important when a program has a lot of command line flags and long descriptions for each of them.

As a side issue/question, line-breaks seem to be dropped from the help text. What's the reason for that?

Thanks for the great library!

Store unknown flags

From https://code.google.com/p/ndmitchell/issues/detail?id=470:

Some programs want to accumulate "unknown" flags, i.e. those which aren't otherwise recognised by the program. I'm in two minds about this, since it brings a number of disadvantages:

  1. There will be no --help output for these commands, so they are undiscoverable.
  2. Given a known flag --bar, then --ba will automatically resolve to --bar, unless there is also a --baa in which case it will be an ambiguous error. The existence or otherwise of commands changes the parser, so having unknown flags can be problematic.

On the other hand, it's something that hledger already does with the -- option, so supporting it more explicitly might give a better experience for them. See this thread for details: http://www.mail-archive.com/[email protected]/msg92770.html

@simonmichael says:

Yes, without this (optional) feature it seems hard to pass extra flags through to be handled by a sub-executable. Here's an example: hledger wants to pass some web-specific options through to hledger-web as in https://code.google.com/p/hledger/issues/detail?id=64 .

Not quite so hard as all that: http://joyful.com/darcsden/simon/hledger/patch/20110923141027-3c3f9 . But it would still be nice not to have to type --.

use errorWithoutStackTrace with GHC 8+

To avoid console output like:

$ hledger -f t.j print -V
hledger: Unknown flag: -V
CallStack (from HasCallStack):
  error, called at ./System/Console/CmdArgs/Explicit.hs:143:15 in cmdargs-0.10.14-8WOlFWoK1XlCebTZE2edgd:System.Console.CmdArgs.Explicit

I think cmdargs should use errorWithoutStackTrace with GHC 8 and above. Eg something like:

error' =
#if __GLASGOW_HASKELL__ < 800
  error
#else
  errorWithoutStackTrace
#endif

Support Data.Text[.Lazy].Text and Filesystem.Path.FilePath

From http://code.google.com/p/ndmitchell/issues/detail?id=580

These types are now very commonly used in Haskell and it would be very helpful to be able to use them directly in the arguments record. I'd think that adding the dependency on the text package probably isn't too big a deal since it's part of Haskell Platform. Not sure if you're OK the dependency on system-filepath, which is not part of HP.

@ndmitchell replied:

bytestring should probably also go on that list as String-like things that should be supported. I'd much rather avoid the dependency on text/filepath though, since I have deliberately tried to keep the dependencies of cmdargs very light, since it is such a small piece of most applications.

I wonder if there is some scope for going via IsString instances (which is probably what we really want), although can't immediately thing how that should be done...

runtime error with newtype declarations

Here is a minimal showcase of the error I am facing:

If I declare a newtype datatype - then flags produce runtime errors.
For data-declarations everything seems to work just fine.

{-# LANGUAGE DeriveDataTypeable #-}
module Main where

import System.Console.CmdArgs
---------------------------------------------------------------------------------
--                 Newtypes seem to make problems with CMDARGS                 --
---------------------------------------------------------------------------------

newtype NewtypeSample = NewtypeSample {helloNT :: FilePath } deriving (Show, Data, Typeable)

worksNT = NewtypeSample{helloNT = def &= help "World argument" }
         &= summary "NewtypeSample v1"

doesn'tWorkNT1 = NewtypeSample{helloNT = def &= help "World argument" &= opt "world" &= typFile}
         &= summary "NewtypeSample v1"

doesn'tWorkNT2 = NewtypeSample{helloNT = def &= help "World argument" &= opt "world"}
         &= summary "NewtypeSample v1"

---------------------------------------------------------------------------------
--                  Data declarations seem to work just fine                   --
---------------------------------------------------------------------------------

data DataSample = DataSample {helloD :: FilePath } deriving (Show, Data, Typeable)

worksD1 = DataSample{helloD = def &= help "World argument" &= opt "world"}
         &= summary "DataSample v1"

worksD2= DataSample{helloD = def &= help "World argument" &= opt "world" &= typFile}
         &= summary "DataSample v1"

main :: IO ()
main = do 
  print =<< cmdArgs doesn'tWorkNT1
  print =<< cmdArgs doesn'tWorkNT2
  print =<< cmdArgs worksNT
  print =<< cmdArgs worksD1
  print =<< cmdArgs worksD2
  return ()

Here are the errors I get:

  • doesn'tWorkNT1
stack build && stack exec -- cmdargsbug
cmdargsbug-0.1.0.0: build (exe)
Preprocessing executable 'cmdargsbug' for cmdargsbug-0.1.0.0...
[1 of 1] Compiling Main             ( src/Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/cmdargsbug/cmdargsbug-tmp/Main.o )
Linking .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/cmdargsbug/cmdargsbug ...
cmdargsbug-0.1.0.0: copy/register
Installing executable(s) in
..../cmdargsbug/.stack-work/install/x86_64-linux/lts-8.17/8.0.2/bin
cmdargsbug: System.Console.CmdArgs.Implicit, unexpected mode: FlagType "FILE"
CallStack (from HasCallStack):
  error, called at ./System/Console/CmdArgs/Implicit/Local.hs:106:11 in cmdargs-0.10.17-IWa8ygdJhnJBShkQXN8V9I:System.Console.CmdArgs.Implicit.Local

commenting out the doesn'tWorkNT1 line produces

  • doesn'tWorkNT2
stack build && stack exec -- cmdargsbug
cmdargsbug-0.1.0.0: build (exe)
Preprocessing executable 'cmdargsbug' for cmdargsbug-0.1.0.0...
[1 of 1] Compiling Main             ( src/Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/cmdargsbug/cmdargsbug-tmp/Main.o )
Linking .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/cmdargsbug/cmdargsbug ...
cmdargsbug-0.1.0.0: copy/register
Installing executable(s) in
..../cmdargsbug/.stack-work/install/x86_64-linux/lts-8.17/8.0.2/bin
cmdargsbug: System.Console.CmdArgs.Implicit, unexpected mode: FlagOptional "world"
CallStack (from HasCallStack):
  error, called at ./System/Console/CmdArgs/Implicit/Local.hs:106:11 in cmdargs-0.10.17-IWa8ygdJhnJBShkQXN8V9I:System.Console.CmdArgs.Implicit.Local

the built-in help flag is hard to customise

I'd like to make -h a synonym for --help, and suppress -?. But "h" is automatically assigned to another flag (--hide-successes). If I add the "explicit" annotation to that one, cmdargs complains at runtime about a missing ? name. The example in helpArg's haddock (helpArg [explicit, name "h"]) complains about a repeated h name.

Have --help list the options available for --help

For an end-user, it's not at all obvious that "--help" will accept arguments, since this doesn't seem to be especially typical of command-line programs.
   I'm therefore adding my own explanation, since so far as I can see, there is no way of automatically producing it. Also, a number of options ( "def", "bash", "zsh") aren't actually explained in the documentation for System.Console.CmdArgs.Explicit.flagHelpFormat, one has to look at various other bits of documentation and the source code.
   Would it be possible to have "--help" (either by default, or as an option) display to the user the options available for "--help"?

Add --numeric-version as default

HLint is my use case for this feature request, but I think the feature is general enough to sit in command line parsing libraries.

Cabal supports the flag --numeric-version which is convenient for version detection/comparison in scripts/tools. I looked around in the source but I don't see any obvious ways of adding this flag without breaking the current API.

Can you either sketch how to cause the least breakage and I can prepare a patch, or add support for the flag?

Running multiple sub-commands

I'm wondering if it is possible at all to be able to run like ./myprog cmd1 cmd2 ... using this library? The modes things returns a single command, so maybe not ?

Better error messages for invalid annotations

From http://code.google.com/p/ndmitchell/issues/detail?id=345

in_files   = [] &= help "CVS files with data to visualise"
                &= args
                &= typ "FILES"

This is invalid because args and help don't mix, but you get the error:

System.Console.CmdArgs.Implicit, unexpected flag (args/argPos):
     Flag_ {flagField = "in_files",
            flagFlag  = CVS files with data to visualise,
            flagExplicit = False,
            flagGroup = Nothing,
            flagEnum = Nothing}

That's horrible, and misses the essential parts.

As another example, if you make the help field an unknown type, for example Text, you get the error message:

System.Console.CmdArgs.Implicit, unexpected flag (help): Data.Text.Internal.Text

It doesn't say that its an unexpected type, or that the flag is expected but the type is not.

A problem with common flags and multiple typFile resulting in "ITEM"

I am trying to get a help page that looks like:

$ ./cmdargs.hs --help
The tape program

tape [COMMAND] ... [OPTIONS]
  Records and replays stdout/stder produced by a command

Common flags:
  -? --help       Display help message
  -V --version    Print version information
  -f --file=FILE  Use file instead of stdin/stdout

tape record [OPTIONS] COMMAND [ARGS]

tape replay [OPTIONS]
  -d --delays     Reproduce delays in stdout/stderr (off by default)

tape inspect [OPTIONS]

I made it to this point:

#!/usr/bin/env stack
-- stack --resolver lts-9.20 script --package cmdargs

{-# LANGUAGE DeriveDataTypeable #-}

module Main where

import           System.Console.CmdArgs as Args
import           System.IO

data Tape = Record  {file :: Maybe String, command :: String, commandArgs :: [String]}
          | Replay  {file :: Maybe String, delays :: Bool}
          | Inspect {file :: Maybe String}
            deriving (Data, Typeable, Show, Eq)
main :: IO ()
main = do
  let fileSpec = def &= typFile &= help "Use file instead of stdin/stdout"
  _ <- cmdArgs $ modes
         [ Record  { file        = fileSpec
                   , command     = def &= typ "COMMAND" &= argPos 0
                   , commandArgs = def &= typ "ARGS"    &= args     }
         , Replay  { file        = fileSpec
                   , delays      = def &= help "Reproduce delays in stdout/stderr (off by default)"}
         , Inspect { file        = fileSpec }
         ]
         &= help    "Records and replays stdout/stder produced by a command"
  return ()

...that results in:

$ ./cmdargs.hs --help
The tape program

tape [COMMAND] ... [OPTIONS]
  Records and replays stdout/stder produced by a command

Common flags:
  -? --help       Display help message
  -V --version    Print version information

tape record [OPTIONS] COMMAND [ARGS]

  -f --file=FILE  Use file instead of stdin/stdout

tape replay [OPTIONS]

  -f --file=ITEM
  -d --delays     Reproduce delays in stdout/stderr (off by default)

tape inspect [OPTIONS]

  -f --file=ITEM

I am trying to find a workaround to these problems:

  • "record" mode shows the correct "--file=FILE" and a help message, however consequent modes show "--file=ITEM" and no help message
  • "--file" flag is present in all modes, however it is not moved to common flags

What would be your recommendations in fixing these two things?

P.S. Thank you for your beautifully designed library.

Data.Generics.Any: Undefined field inside compose0, :% :: Ratio Int

Getting a runtime error on:

{-# LANGUAGE DeriveDataTypeable -}
module Main where

import Data.Ratio
import System.Console.CmdArgs

data Options = Options { r :: Ratio Int
                                      } deriving (Show, Data, Typeable)

defaultOptions = Options { r = 4 % 7 }

main = print =<< cmdArgs defaultOptions

The error message is:
Data.Generics.Any: Undefined field inside compose0, :% :: Ratio Int

Some arguments aren't grouped under 'Common Flags' (cmdargs 0.10.7)

Hi Neil,

some arguments seem to be considered, others not, here -e, -l, -t and -b aren't considered:

dan@machine ~> cabal-bounds --help
cabal-bounds [COMMAND] ... [OPTIONS]
  A command line program for managing the bounds/versions of the dependencies
  in a cabal file.

Common flags:
  -O --only=ITEM             Only the bounds of the dependency are modified.
  -I --ignore=ITEM           This dependency is ignored, not modified in any
                             way.
  -o --outputCabalFile=ITEM  Save modified cabal file to file, if empty, the
                             cabal file is modified inplace.
  -h --help                  Display help message
  -v --version               Print version information

cabal-bounds drop [OPTIONS] CABAL-FILE

  -U --upper                 Only the upper bound is dropped, otherwise both
                             - the lower and upper - bounds are dropped.
  -l --library               Only the bounds of the library are dropped.
  -e --executable=ITEM       Only the bounds of the executable are dropped.
  -t --testsuite=ITEM        Only the bounds of the test suite are dropped.
  -b --benchmark=ITEM        Only the bounds of the benchmark are dropped.

cabal-bounds update [OPTIONS] CABAL-FILE SETUP-CONFIG-FILE

  -L --lower                 Only the lower bound is updated.
  -U --upper                 Only the upper bound is updated.
  -l --library               Only the bounds of the library are updated.
  -e --executable=ITEM       Only the bounds of the executable are updated.
  -t --testsuite=ITEM        Only the bounds of the test suite are updated.
  -b --benchmark=ITEM        Only the bounds of the benchmark are updated.

The data structure for the arguments is:

data Args = Drop { upper           :: Bool
             , library         :: Bool
             , executable      :: [String]
             , testSuite       :: [String]
             , benchmark       :: [String]
             , only            :: [String]
             , ignore          :: [String]
             , outputCabalFile :: String
             , cabalFile       :: String
             }
      | Update { lower           :: Bool
               , upper           :: Bool
               , library         :: Bool
               , executable      :: [String]
               , testSuite       :: [String]
               , benchmark       :: [String]
               , only            :: [String]
               , ignore          :: [String]
               , outputCabalFile :: String
               , cabalFile       :: String
               , setupConfigFile :: String
               } 
      deriving (Data, Typeable, Show, Eq)

And the initialization of the arguments:

get :: IO Args
get = cmdArgsRun . cmdArgsMode $ modes [dropArgs, updateArgs]
   &= program "cabal-bounds"
   &= summary summaryInfo
   &= help "A command line program for managing the bounds/versions of the dependencies in a cabal file."
   &= helpArg [explicit, name "help", name "h"]
   &= versionArg [explicit, name "version", name "v", summary versionInfo]
   where
      summaryInfo = ""

dropArgs :: Args
dropArgs = Drop
   { upper           = def &= explicit &= name "upper" &= name "U" &= help "Only the upper bound is dropped, otherwise both - the lower and upper - bounds are dropped."
   , library         = def &= explicit &= name "library" &= name "l" &= help "Only the bounds of the library are dropped."
   , executable      = def &= help "Only the bounds of the executable are dropped."
   , testSuite       = def &= help "Only the bounds of the test suite are dropped."
   , benchmark       = def &= help "Only the bounds of the benchmark are dropped."
   , only            = def &= explicit &= name "only" &= name "O" &= help "Only the bounds of the dependency are modified."
   , ignore          = def &= explicit &= name "ignore" &= name "I" &= help "This dependency is ignored, not modified in any way."
   , outputCabalFile = def &= explicit &= name "outputCabalFile" &= name "o" &= help "Save modified cabal file to file, if empty, the cabal file is modified inplace."
   , cabalFile       = def &= argPos 0 &= typ "CABAL-FILE"
   }


updateArgs :: Args
updateArgs = Update
   { lower           = def &= explicit &= name "lower" &= name "L" &= help "Only the lower bound is updated."
   , upper           = def &= explicit &= name "upper" &= name "U" &= help "Only the upper bound is updated."
   , library         = def &= explicit &= name "library" &= name "l" &= help "Only the bounds of the library are updated."
   , executable      = def &= help "Only the bounds of the executable are updated."
   , testSuite       = def &= help "Only the bounds of the test suite are updated."
   , benchmark       = def &= help "Only the bounds of the benchmark are updated."
   , only            = def &= explicit &= name "only" &= name "O" &= help "Only the bounds of the dependency are modified."
   , ignore          = def &= explicit &= name "ignore" &= name "I" &= help "This dependency is ignored, not modified in any way."
   , outputCabalFile = def &= explicit &= name "outputCabalFile" &= name "o" &= help "Save modified cabal file to file, if empty, the cabal file is modified inplace."
   , cabalFile       = def &= argPos 0 &= typ "CABAL-FILE"
   , setupConfigFile = def &= argPos 1 &= typ "SETUP-CONFIG-FILE"
   }

That's the case for cmdargs 0.10.7. Any ideas? Thanks!

Greetings,
Daniel

Version 0.10.8 breaks elm-server

When I compile elm-server (0.11.0.1) with cmdargs-0.10.8 it ends up completely broken due to what seems like an internal error in CmdArgs:

elm-server: System.Console.CmdArgs.Implicit, unexpected repeated names: v version

Downgrading to cmdargs-0.10.7 fixes it. I haven't looked into what exactly is causing this; perhaps it'll be clear for you based on the error message.

Modes/Flags/Args ordering should be customizable

From http://code.google.com/p/ndmitchell/issues/detail?id=457 by @simonmichael:

This works, assuming mainflag is defined for both the main mode and command's mode:

program command --mainflag --commandflag

I'd like this to work too:

program --mainflag command --commandflag

but it doesn't recognise --commandflag, I think because it has not selected the command's mode.
Aug 19, 2011 Delete comment Project Member #1 ndmitchell
In the first case, whether --mainflag is defined for the main mode is totally irrelevant. The current rule is:

program [modes] [flags/args]

This picks exactly one mode, then accumulates flags/args into it. In the first case you do not end up with:

main-mode{--mainflag} and command-mode{--commandflag}

You just end up with:

command-mode{--mainflag,--commandflag}

The restriction to only have modes before flags is just a choice of the command line processor, and could be lifted - is that what you are asking for? However, the restriction to only producing one "mode" value is much more fundamental.
Labels: Proj-Catch
Aug 19, 2011 Delete comment Project Member #2 ndmitchell
(No comment was entered for this change.)
Labels: -Proj-Catch Proj-CmdArgs
Aug 19, 2011 Delete comment Project Member #3 ndmitchell
Issue 458 has been merged into this issue.
Aug 19, 2011 Delete comment #4 [email protected]
Ok, it sounds like I don't have the right mental model for cmdargs yet, but yes I think that's what I'm asking for. I'd like flags to work either before or after the mode (command); I think I'm used to that from other (good) programs.
Sep 3, 2011 Delete comment Project Member #5 ndmitchell
Currently CmdArgs allows you to enter: modes_(flags|args)_

You are asking for: (modes|flags|args)*

Separately, Lennart has asked for: modes_flags_args*

Certainly the mode Lennart asks for is essential to support something like runhaskell, where "runhaskell -O Module --args" should be treated as --args being an argument that is passed on directly, and then interpreted by the Module.

It seems like this should be a preference set per application, something available in Explicit, and then exposed through Implicit.
Summary: Modes/Flags/Args ordering should be customizable
Status: Accepted
Sep 6, 2011 Delete comment #6 [email protected]
Hi Neil, following up on this and your email: I'm not asking that flags be handled or passed through based on their position in the command line, at least not in this issue. I'm just asking for a more forgiving parser that allows flags to appear either before or after the mode argument, so users don't have to think much about ordering. I think this is what the most usable programs out there, do, and of course I'd like cmdargs to support that. I actually didn't realise it wasn't supported until you pointed it out.
Sep 6, 2011 Delete comment #7 [email protected]
PS but since you bring it up, that pass-through-based on position rule feels a bit to clever/unfamiliar to me. I like the explicit "after --" convention. But I'd like an alternate mode where unrecognised flags are passed through without complaint. That would make hledger's commands more usable, users wouldn't have to use -- and ordering would be more flexible.
Sep 11, 2011 Delete comment Project Member #8 ndmitchell
I added this bug to track the addition of an unknown flag: https://code.google.com/p/ndmitchell/issues/list?id=470
Sep 11, 2011 Delete comment Project Member #9 ndmitchell
I raised a separate bug for the unknown flags bit: https://code.google.com/p/ndmitchell/issues/detail?id=470
Oct 16, 2012 Delete comment Project Member #10 ndmitchell
Asked on StackOverflow: http://stackoverflow.com/questions/12881204/can-cmdargs-have-flags-outside-of-sub-modes/
Labels: Downstream
Jan 27, 2014 Delete comment #11 rpglover64
I assume no progress has been made on this. Could some of the parsing difficulties be ameliorated by requiring explicit specification of common flags that can be present before the mode?

Add an applicative mode

People seem to like writing their parsers in applicative format. I'm not a fan (you don't write the label next to the value, which makes it fragile) but I should at least provide some applicative parser inside cmdargs.

Add a way of regenerating the getArgs input, with changes

From http://code.google.com/p/ndmitchell/issues/detail?id=404:

It would be useful to add the function:

cmdArgsReform :: Mode (CmdArgs a) -> CmdArgs a -> [String]

Given a mode, and a value (presumably returned by cmdArgs or similar, perhaps tweaked slightly) it will give a set of arguments, which when parsed with the given mode, will regenerate the value.

Use case: For servers, it's useful to run them in a mode that continually respawns them if they die. This can usually be done by passing --restart, then running the same program with all but the --restart argument. With cmdArgsReform you parse with CmdArgs, and on seeing the restart just set it to false, and manufacture a new set of equivalent arguments.

Implementation notes: I probably need to add modeReform :: Maybe (a -> [String]) to the mode constructor. During construction we have to manufacture this function, then cmdArgsReform just calls it.

Testing: Testing is rather easy, I just add to the test case driver a test, so it will always get tested that if you run this you get back what you started with.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.