{"id":13532199,"url":"https://github.com/ndmitchell/cmdargs","last_synced_at":"2025-05-16T06:06:54.270Z","repository":{"id":11132820,"uuid":"13496071","full_name":"ndmitchell/cmdargs","owner":"ndmitchell","description":"Haskell library for command line argument processing","archived":false,"fork":false,"pushed_at":"2025-02-02T22:04:03.000Z","size":1483,"stargazers_count":91,"open_issues_count":46,"forks_count":12,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-05-14T00:12:46.382Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ndmitchell.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.txt","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-10-11T10:20:36.000Z","updated_at":"2025-02-02T22:04:07.000Z","dependencies_parsed_at":"2025-02-16T14:11:17.450Z","dependency_job_id":"002f1d3c-fe9c-496f-b10d-eb68640b513f","html_url":"https://github.com/ndmitchell/cmdargs","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndmitchell%2Fcmdargs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndmitchell%2Fcmdargs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndmitchell%2Fcmdargs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ndmitchell%2Fcmdargs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ndmitchell","download_url":"https://codeload.github.com/ndmitchell/cmdargs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254478190,"owners_count":22077676,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T07:01:09.030Z","updated_at":"2025-05-16T06:06:49.260Z","avatar_url":"https://github.com/ndmitchell.png","language":"Haskell","funding_links":[],"categories":["[Haskell](https://www.haskell.org/)"],"sub_categories":["Useful awesome list for Go cli"],"readme":"# CmdArgs: Easy Command Line Processing [![Hackage version](https://img.shields.io/hackage/v/cmdargs.svg?label=Hackage)](https://hackage.haskell.org/package/cmdargs) [![Stackage version](https://www.stackage.org/package/cmdargs/badge/nightly?label=Stackage)](https://www.stackage.org/package/cmdargs) [![Build status](https://img.shields.io/github/actions/workflow/status/ndmitchell/cmdargs/ci.yml?branch=master)](https://github.com/ndmitchell/cmdargs/actions)\n\nCmdArgs is a Haskell library for defining command line parsers. The two features that make it a better choice than the standard [getopt library](http://haskell.org/ghc/docs/latest/html/libraries/base/System-Console-GetOpt.html) are:\n\n* It's very concise to use. The HLint command line handling is three times shorter with CmdArgs.\n* It supports programs with multiple modes, such as [darcs](http://darcs.net) or [Cabal](http://haskell.org/cabal/).\n\nA very simple example of a command line processor is:\n```haskell\ndata Sample = Sample {hello :: String} deriving (Show, Data, Typeable)\n\nsample = Sample{hello = def \u0026= help \"World argument\" \u0026= opt \"world\"}\n         \u0026= summary \"Sample v1\"\n\nmain = print =\u003c\u003c cmdArgs sample\n```\nDespite being very concise, this processor is already fairly well featured:\n\n    $ runghc Sample.hs --hello=world\n    Sample {hello = \"world\"}\n\n    $ runghc Sample.hs --help\n    Sample v1, (C) Neil Mitchell 2009\n\n    sample [FLAG]\n\n      -? --help[=FORMAT]  Show usage information (optional format)\n      -V --version        Show version information\n      -v --verbose        Higher verbosity\n      -q --quiet          Lower verbosity\n      -h --hello=VALUE    World argument (default=world)\n\n## User Manual\n\nThe 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:\n\n* `hlint` - the [HLint](https://github.com/ndmitchell/hlint#readme) program.\n* `diffy` - a program to compare the differences between directories.\n* `maker` - a make style program.\n\nFor each example you are encouraged to look at it's source (in the [repo](https://github.com/ndmitchell/cmdargs/tree/master/System/Console/CmdArgs/Test/Implicit)) 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](http://haskell.org/ghc/docs/latest/html/libraries/base/System-Console-GetOpt.html) 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.\n\n**Acknowledgements** Thanks to Kevin Quick for substantial patches, and additional code contributions from Sebastian Fischer and Daniel Schoepe.\n\n\n## Hello World Example\n\nThe following code defines a complete command line argument processor:\n```haskell\n{-# LANGUAGE DeriveDataTypeable #-}\n{-# OPTIONS_GHC -fno-cse #-}\nmodule Sample where\nimport System.Console.CmdArgs\n\ndata Sample = Sample {hello :: String}\n              deriving (Show, Data, Typeable)\n\nsample = Sample{hello = def}\n\nmain = print =\u003c\u003c cmdArgs sample\n```\nTo use the CmdArgs library there are three steps:\n\n* Define a record data type (`Sample`) that contains a field for each argument. This type needs to have instances for `Show`, `Data` and `Typeable`.\n* 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.\n* To ensure GHC evalutes attributes the right number of times we disable the CSE optimisation on this module.\n\nNow we have a reasonably functional command line argument processor. Some sample interactions are:\n\n    $ runghc Sample.hs --hello=world\n    Sample {hello = \"world\"}\n\n    $ runghc Sample.hs --version\n    The sample program\n\n    $ runghc Sample.hs --help\n    The sample program\n\n    sample [OPTIONS]\n\n      -? --help        Display help message\n      -V --version     Print version information\n      -h --hello=ITEM\n\nCmdArgs 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.\n\n## Specifying Attributes\n\nIn 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:\n```haskell\nsample = Sample{hello = def \u0026= help \"Who to say hello to\"}\n```\nWe can add additional attributes, for example to specify the type of the value expected by hello:\n```haskell\nsample = Sample {hello = def \u0026= help \"Who to say hello to\" \u0026= typ \"WORLD\"}\n```\nNow when running `--help` the final line is:\n\n      -h --hello=WORLD  Who to say hello to\n\nThere are many more attributes, detailed in the [Haddock documentation](http://hackage.haskell.org/packages/archive/cmdargs/latest/doc/html/System-Console-CmdArgs.html#2).\n\n\n## Multiple Modes\n\nTo specify a program with multiple modes, similar to [darcs](http://darcs.net/), we can supply a data type with multiple constructors, for example:\n```haskell\ndata Sample = Hello {whom :: String}\n            | Goodbye\n              deriving (Show, Data, Typeable)\n\nhello = Hello{whom = def}\ngoodbye = Goodbye\n\nmain = print =\u003c\u003c cmdArgs (modes [hello,goodbye])\n```\nCompared 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:\n\n    $ runghc Sample.hs hello --whom=world\n    Hello {whom = \"world\"}\n\n    $ runghc Sample.hs goodbye\n    Goodbye\n\n    $ runghc Sample.hs --help\n    The sample program\n\n    sample [OPTIONS]\n\n     Common flags\n      -? --help       Display help message\n      -V --version    Print version information\n\n    sample hello [OPTIONS]\n\n      -w --whom=ITEM\n\n    sample goodbye [OPTIONS]\n\nAs before, the behaviour can be customised using attributes.\n\n\n## Larger Examples\n\nFor 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`.\n\n### HLint\n\nThe [HLint](https://github.com/ndmitchell/hlint#readme) 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:\n\n* 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.\n* 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.\n* The `show_` field would clash with `show` if given the expected name, but CmdArgs automatically strips the trailing underscore.\n* The `cpp_define` field has an underscore in it's name, which is transformed into a hyphen for the flag name.\n\nThe code is:\n```haskell\n{-# LANGUAGE DeriveDataTypeable #-}\nmodule HLint where\nimport System.Console.CmdArgs\n\ndata HLint = HLint\n    {report :: [FilePath]\n    ,hint :: [FilePath]\n    ,color :: Bool\n    ,ignore_ :: [String]\n    ,show_ :: Bool\n    ,extension :: [String]\n    ,language :: [String]\n    ,utf8 :: Bool\n    ,encoding :: String\n    ,find :: [FilePath]\n    ,test_ :: Bool\n    ,datadir :: [FilePath]\n    ,cpp_define :: [String]\n    ,cpp_include :: [FilePath]\n    ,files :: [FilePath]\n    }\n    deriving (Data,Typeable,Show,Eq)\n\nhlint = HLint\n    {report = def \u0026= opt \"report.html\" \u0026= typFile \u0026= help \"Generate a report in HTML\"\n    ,hint = def \u0026= typFile \u0026= help \"Hint/ignore file to use\"\n    ,color = def \u0026= name \"c\" \u0026= name \"colour\" \u0026= help \"Color the output (requires ANSI terminal)\"\n    ,ignore_ = def \u0026= typ \"MESSAGE\" \u0026= help \"Ignore a particular hint\"\n    ,show_ = def \u0026= help \"Show all ignored ideas\"\n    ,extension = def \u0026= typ \"EXT\" \u0026= help \"File extensions to search (defaults to hs and lhs)\"\n    ,language = def \u0026= name \"X\" \u0026= typ \"LANG\" \u0026= help \"Language extension (Arrows, NoCPP)\"\n    ,utf8 = def \u0026= help \"Use UTF-8 text encoding\"\n    ,encoding = def \u0026= typ \"ENC\" \u0026= help \"Choose the text encoding\"\n    ,find = def \u0026= typFile \u0026= help \"Find hints in a Haskell file\"\n    ,test_ = def \u0026= help \"Run in test mode\"\n    ,datadir = def \u0026= typDir \u0026= help \"Override the data directory\"\n    ,cpp_define = def \u0026= typ \"NAME[=VALUE]\" \u0026= help \"CPP #define\"\n    ,cpp_include = def \u0026= typDir \u0026= help \"CPP include path\"\n    ,files = def \u0026= args \u0026= typ \"FILES/DIRS\"\n    } \u0026=\n    verbosity \u0026=\n    help \"Suggest improvements to Haskell source code\" \u0026=\n    summary \"HLint v0.0.0, (C) Neil Mitchell\" \u0026=\n    details [\"Hlint gives hints on how to improve Haskell code\",\"\"\n            ,\"To check all Haskell files in 'src' and generate a report type:\",\"  hlint src --report\"]\n\nmode = cmdArgsMode hlint\n```\nProduces the `--help` output:\n\n    HLint v0.0.0, (C) Neil Mitchell\n\n    hlint [OPTIONS] [FILES/DIRS]\n    Suggest improvements to Haskell source code\n\n    Common flags:\n      -r --report[=FILE]            Generate a report in HTML\n      -h --hint=FILE                Hint/ignore file to use\n      -c --colour --color            Color the output (requires ANSI terminal)\n      -i --ignore=MESSAGE            Ignore a particular hint\n      -s --show                     Show all ignored ideas\n         --extension=EXT            File extensions to search (defaults to hs and lhs)\n      -X --language=LANG            Language extension (Arrows, NoCPP)\n      -u --utf8                        Use UTF-8 text encoding\n         --encoding=ENC                Choose the text encoding\n      -f --find=FILE                Find hints in a Haskell file\n      -t --test                        Run in test mode\n      -d --datadir=DIR                Override the data directory\n         --cpp-define=NAME[=VALUE]  CPP #define\n         --cpp-include=DIR            CPP include path\n      -? --help                        Display help message\n      -V --version                    Print version information\n      -v --verbose                    Loud verbosity\n      -q --quiet                    Quiet verbosity\n\n    Hlint gives hints on how to improve Haskell code\n\n    To check all Haskell files in 'src' and generate a report type:\n      hlint src --report\n\n\n### Diffy\n\nThe 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:\n\n* There are multiple modes of execution, creating and diffing.\n* The diff mode takes exactly two arguments, the old file and the new file.\n* Default values are given for the `out` field, which are different in both modes.\n\nThe code is:\n```haskell\n{-# LANGUAGE DeriveDataTypeable #-}\nmodule Diffy where\nimport System.Console.CmdArgs\n\ndata Diffy = Create {src :: Maybe FilePath, out :: FilePath}\n           | Diff {old :: FilePath, new :: FilePath, out :: FilePath}\n             deriving (Data,Typeable,Show,Eq)\n\noutFlags x = x \u0026= help \"Output file\" \u0026= typFile\n\ncreate = Create\n    {src = def \u0026= help \"Source directory\" \u0026= typDir\n    ,out = outFlags \"ls.txt\"\n    } \u0026= help \"Create a fingerprint\"\n\ndiff = Diff\n    {old = def \u0026= typ \"OLDFILE\" \u0026= argPos 0\n    ,new = def \u0026= typ \"NEWFILE\" \u0026= argPos 1\n    ,out = outFlags \"diff.txt\"\n    } \u0026= help \"Perform a diff\"\n\nmode = cmdArgsMode $ modes [create,diff] \u0026= help \"Create and compare differences\" \u0026= program \"diffy\" \u0026= summary \"Diffy v1.0\"\n```\nAnd `--help` produces:\n\n    Diffy v1.0\n\n    diffy [COMMAND] ... [OPTIONS]\n      Create and compare differences\n\n    Common flags:\n      -o --out=FILE     Output file\n      -? --help         Display help message\n      -V --version     Print version information\n\n    diffy create [OPTIONS]\n      Create a fingerprint\n\n      -s  --src=DIR  Source directory\n\n    diffy diff [OPTIONS] OLDFILE NEWFILE\n      Perform a diff\n\n### Maker\n\nThe 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:\n\n* The build mode is the default, so `maker` on it's own will be interpreted as a build command.\n* The build method is an enumeration.\n* 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`.\n\nThe code is:\n```haskell\n{-# LANGUAGE DeriveDataTypeable #-}\nmodule Maker where\nimport System.Console.CmdArgs\n\ndata Method = Debug | Release | Profile\n              deriving (Data,Typeable,Show,Eq)\n\ndata Maker\n    = Wipe\n    | Test {threads :: Int, extra :: [String]}\n    | Build {threads :: Int, method :: Method, files :: [FilePath]}\n      deriving (Data,Typeable,Show,Eq)\n\nthreadsMsg x = x \u0026= help \"Number of threads to use\" \u0026= name \"j\" \u0026= typ \"NUM\"\n\nwipe = Wipe \u0026= help \"Clean all build objects\"\n\ntest_ = Test\n    {threads = threadsMsg def\n    ,extra = def \u0026= typ \"ANY\" \u0026= args\n    } \u0026= help \"Run the test suite\"\n\nbuild = Build\n    {threads = threadsMsg def\n    ,method = enum\n        [Release \u0026= help \"Release build\"\n        ,Debug \u0026= help \"Debug build\"\n        ,Profile \u0026= help \"Profile build\"]\n    ,files = def \u0026= args\n    } \u0026= help \"Build the project\" \u0026= auto\n\nmode = cmdArgsMode $ modes [build,wipe,test_]\n     \u0026= help \"Build helper program\"\n     \u0026= program \"maker\"\n     \u0026= summary \"Maker v1.0\\nMake it\"\n```\nAnd `--help` produces:\n\n    Maker v1.0\n      Make it\n\n    maker [COMMAND] ... [OPTIONS]\n      Build helper program\n\n    Common flags:\n      -? --help     Display help message\n      -V --version  Print version information\n\n    maker [build] [OPTIONS] [ITEM]\n      Build the project\n\n      -j --threads=NUM  Number of threads to use\n      -r --release      Release build\n      -d --debug        Debug build\n      -p --profile      Profile build\n\n    maker wipe [OPTIONS]\n      Clean all build objects\n\n    maker test [OPTIONS] [ANY]\n      Run the test suite\n\n      -j --threads=NUM  Number of threads to use\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fndmitchell%2Fcmdargs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fndmitchell%2Fcmdargs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fndmitchell%2Fcmdargs/lists"}