{"id":13532573,"url":"https://github.com/c-blake/cligen","last_synced_at":"2026-01-19T12:05:25.071Z","repository":{"id":40745105,"uuid":"48857927","full_name":"c-blake/cligen","owner":"c-blake","description":"Nim library to infer/generate command-line-interfaces / option / argument parsing; Docs at","archived":false,"fork":false,"pushed_at":"2024-10-29T08:12:43.000Z","size":5056,"stargazers_count":510,"open_issues_count":0,"forks_count":25,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-10-29T09:23:20.959Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://c-blake.github.io/cligen/","language":"Nim","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/c-blake.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2015-12-31T18:01:08.000Z","updated_at":"2024-10-29T08:05:37.000Z","dependencies_parsed_at":"2023-02-19T01:31:04.629Z","dependency_job_id":"55252581-2cdb-4108-b3dc-ef865ed60708","html_url":"https://github.com/c-blake/cligen","commit_stats":null,"previous_names":[],"tags_count":122,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-blake%2Fcligen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-blake%2Fcligen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-blake%2Fcligen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-blake%2Fcligen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c-blake","download_url":"https://codeload.github.com/c-blake/cligen/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246712915,"owners_count":20821817,"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:11.979Z","updated_at":"2025-04-01T21:30:40.750Z","avatar_url":"https://github.com/c-blake.png","language":"Nim","funding_links":[],"categories":["Nim","Command-Line Interface Automation","Development Tools","[Nim](https://nim-lang.org/)"],"sub_categories":["Generating HTML","Command-Line Interface Automation","Useful awesome list for Go cli"],"readme":"# cligen: A Native API-Inferred Command-Line Interface Generator For Nim\n\nThis approach to CLIs was inspired by Andrey Mikhaylenko's Python\n[argh](https://pythonhosted.org/argh/)\n([Click](https://github.com/pallets/click/) became more popular).\nThe key observation is that proc signatures already encode what you need to\ngenerate CLIs - names, types, and default values.  Reflection then suffices to\ngenerate parser-dispatchers translating `seq[string]` command input into calls\nto a wrapped proc.  In Nim, adding a CLI can be 1-line of code:\n```nim\nproc fun(foo=1,bar=2.0,baz=\"x\",verb=false,args: seq[string]): int=\n  ## An API call doc comment\n  result = 1      # Of course, real code would have real work here\nimport cligen; dispatch fun # Whoa..Just 1 line??\n```\nCompile it to `fun` (e.g., `nim c fun.nim`) and then run `./fun --help`\nto get a minimal (but not so useless!) help message:\n```\nUsage:\n  fun [optional-params] [args: string...]\nAn API call doc comment\nOptions:\n  -h, --help                    print this cligen-erated help\n  --help-syntax                 advanced: prepend,plurals,..\n  -f=, --foo=    int     1      set foo\n  -b=, --bar=    float   2.0    set bar\n  --baz=         string  \"x\"    set baz\n  -v, --verb     bool    false  set verb\n```\nThat's it!  No specification language/complex arg parsing API/Nim pragma tags\nto learn.  Installing can be as simple as `nimble install cligen` or even just\n`git clone \u003cthisRepo\u003e` and `nim c --path:whereYouClonedTo myProgram.nim`.  If\nyou aren't sold already, here is more\n[MOTIVATION](https://github.com/c-blake/cligen/tree/master/MOTIVATION.md).\n\nThe `help` column is filled with generic `set foo` placeholders by default.\nYou can override that using parameter-keyed association-list literals:\n```nim\ndispatch fun, help={\"foo\": \"the beginning\", \"bar\": \"the rate\"}\n```\nThe same goes for `short` versions of the CLI arguments.  More on that\n[below](#common-overrides-program-exit-config-fileenvironment-vars).\n\nOther invocations (`./fun --foo 2 -b=2.7 --baz:\"ho\"...`) work as expected.\n\nDefault help tables work with automated \"help to X\" tools such as `complete -F\n_longopt` in bash, `compdef _gnu_generic` in Zsh, or the GNU `help2man` (e.g.\n`help2man -N ./fun|man /dev/stdin`).\n\nNim CLI authors who have read this far can mostly use `cligen` already.  Enter\n`--help`, `--help-syntax`/`--helps`, or illegal commands to get help messages,\nsyntax, exhibit mappings, etc.  Out of the box, `cligen` supports conversion for\nmost basic Nim types (`int`s, `float`s, `enum`s, `seq`s, `set`s, `HashSet`s of\nthem, ranges, etc.) [but can be extended](#custom-parameter-types-or-parsing).\n\n### CLusage: Param Match/Help Render, Trailing \u0026 Required Args\n\n`cligen`-erated parsers accept **any unambiguous prefix** for long options.\nIn other words, long options can be as short as possible.  In yet other words,\nhitting the TAB key to complete is unnecessary **if** the completion is unique.\nThis is patterned after, e.g. gnuplot, gdb, Vim ex-commands, etc.  Long options\ncan also be **spelled flexibly**, e.g. `--dry-run`|`--dryRun`, like Nim's\nstyle-insensitive identifiers, but with extra \"kebab-case-insensitivity\".\nThe exact spelling of the key in `help` controls the look of printed help.\n\nLayout details like column spacing and help colorization are controlled [by a\nCL user config file](https://github.com/c-blake/cligen/tree/master/configs).\nHere are screenshots of example\n[night](https://raw.githubusercontent.com/c-blake/cligen/master/screenshots/dirqHelpNight.png)\nand\n[day](https://raw.githubusercontent.com/c-blake/cligen/master/screenshots/dupsHelpDay.png)\nthemes.)\n\n---\n\nMost commands have some trailing variable length sequence of arguments like\n`args` in the first example.  `cligen` automatically treats the first\nnon-defaulted `seq[T]` proc parameter as such an optional sequence.  `cligen`\napplies the same basic string-to-native type converters/parsers used for option\nvalues to such parameters.\n\n---\n\nIf a proc parameter has no **explicit** default value (via `=`) then it becomes\nrequired.  The input syntax is the same as for optional values.  So, in\n```nim\nproc fun(myRequired: float, mynums: seq[int], foo=1) = discard\nwhen isMainModule: # Preserve ability to `import api`/call from Nim\n  import cligen; dispatch fun\n```\nthe command-line user must give `--myRequired=something` somewhere.  Non-option\narguments must be parsable as `int` with whitespace stripped, e.g. `./fun\n--myRequired=2.0 1 2 \" -3\" -- -4`.\n\nMore general user semantics for argument validation (required-ness, length,\n\"sub-parsing\", etc.) can be done like\n[UserError.nim](https://github.com/c-blake/cligen/blob/master/test/UserError.nim).\n\n### Custom Parameter Types, Parsing, Or Default Renders\n\nWhile `cligen/argcvt` supports basic Nim types, the parsing/printing system is\n*extensible* via in-`dispatch` scope `argParse` \u0026 `argHelp` overloads for types.\nA simple example:\n```nim\nimport std/times\nproc foo(i = 42, d = now()): void = echo d\n\nwhen isMainModule:\n  import cligen/argcvt, cligen\n  proc argParse(dst: var DateTime, dfl: DateTime,\n                a: var ArgcvtParams): bool =\n    try: dst = times.parse(a.val, \"yyyyMMdd\")\n    except TimeParseError:\n      echo \"bad DateTime: \", a.val; return false\n    return true\n\n  proc argHelp(dfl: DateTime, a: var ArgcvtParams): seq[string]=\n    @[a.argKeys, \"DateTime\", getDateStr(dfl)]\n\n  dispatch foo, help={\"i\": \"favorite number\", \"d\": \"birthday\"}\n```\nThese two \"argument IO\" procs take a shared coordination parameter for argument\nmetadata (more fully documented in `cligen/argcvt.nim`).  As just a simple e.g.,\n`a.parNm` is the name of the parameter being parsed.  While not usually useful,\nthis can be used to parse the same Nim type differently (based on the name),\ndetect when CLusers alter parameters from defaults, count uses, etc.\n\nThis same mechanism can ***override existing*** `cligen/argcvt` parser/helpers\nif the built-ins are not what you want.  Consulting `cligen/argcvt` for examples\nis a good idea.  E.g., [test/FancyRepeats.nim](test/FancyRepeats.nim) shows how\nto change `argParse` and/or `argHelp` for `int`.  *All* conversions can be\noverridden to taste this way (or even the whole `cligen/argcvt.nim` module).\n\n### Subcommands, dispatch to object init\n\n`dispatchMulti` lets you expose two or more procs with subcommands a la `git` or\n`nimble`. Each `[]` list in `dispatchMulti` is the argument list for each\nsub-`dispatch`.  Tune command syntax and help strings in the same way as\n`dispatch` as in:\n```nim\nproc foo(myRequired: int, mynums: seq[int], foo=1) = discard\n  ## Some API call\nproc bar(yippee: int, myFlts: seq[float], verb=false) = discard\n  ## Some other API call\nwhen isMainModule:\n  import cligen\n  dispatchMulti([foo, help={\"myRequired\": \"Need it!\"}], [bar])\n```\nWith the above in `cmd.nim`, CLI users can run `./cmd foo -m1` or\n`./cmd bar -y10 1.0 2.0`.  `./cmd` or `./cmd --help` print brief help messages\nwhile `./cmd help` prints a comprehensive message, and `./cmd SUBCMD --help`\nor `./cmd help SUBCMD` print a message for just `SUBCMD` (e.g. `foo`|`bar`).\n\nLike long option keys or `enum` value names, subcommand names can also be ***any\nunambiguous prefix and are case-kebab-insensitive***.  So, `./cmd f-O -m1` would\nalso work above.\n\n---\n\nRather than dispatching to a proc and exiting, you can also initialize the\n***fields of an object/tuple*** from the command-line with `initFromCL` which\nhas the same keyword parameters as the most salient features of `dispatch`:\n```nim\ntype App* = object\n  srcFile*: string\n  show*: bool\nconst dfl* = App(srcFile: \"junk\") # set defaults!=default for type\n\nproc logic*(a: var App) = echo \"app is: \", a\n\nwhen isMainModule:\n  import cligen\n  var app = initFromCL(dfl, help = { \"srcFile\": \"yadda yadda\" })\n  app.logic # Only --help/--version/parse errors cause early exit\n```\n\n### Common Overrides, Program Exit, Config File/Environment Vars\n\nYou can manually control the short option for any parameter via `short`:\n```nim\ndispatch fun, short={\"bar\" : 'r'}\n```\nIf you'd like to define `short` or `help` parameters outside of a `dispatch`\ncall, you need an explicit conversion to a `Table` symbol:\n```nim\nimport cligen; clCfg.longPfxOk = false  # {.define(cgCfgNone).}..\nfrom std/tables import toTable          #..blocks syntax config\nconst\n  Help  = { \"foo\": \"the beginning\", \"bar\": \"the rate\" }.toTable()\n  Short = { \"foo\": 'f', \"bar\": 'r'}.toTable()\nproc fun(foo = 1, bar = 2, baz = \"hi\") = discard\ndispatch(fun, help = Help, short = Short)\n```\nWith that `\"bar\"` gets `'r'` while `\"baz\"` gets `'b'` as short options.  To\nsuppress a long option getting *any* short option, specify a short key `'\\0'`.\nTo suppress _all_ short options, give `short` a key of `\"\"`.  Making `longPfxOk`\nfalse instead of the default `true` means CLusers must say `--foo`, not `--fo`.\n\nTo suppress API parameters in the CLI, pass `suppress = @[\"apiParam\", ...]`.\n(For object init, \"ALL AFTER field\" stops fieldPairs iteration.)  To suppress\npresence only in help messages use `help={\"apiParam\": \"CLIGEN-NOHELP\"}`.  Pass\n`implicitDefault = @[\"apiParam\",...]` to let the CLI wrapper default API\nparameter values with no explicit initialization to the Nim default for a type.\n\n---\n\nThe default exit protocol is (with boolean short-circuiting) `quit(int(result))\nor (echo $result or discard; quit(0))`.  If `echoResult==true`, it's just\n`echo $result; quit(0)`, while if `noAutoEcho==true` it's `quit(int(result)) or\n(discard; quit(0))`.  The `or`s above are based on whether the wrapped proc has\na return type or `$` defined on the type.  So,\n```nim\nimport editdistance, cligen # gen CLI for a Nim stdlib API\ndispatch(editDistanceASCII, echoResult=true)\n```\nmakes a program to print edit distance between two required parameters while\nwithout `echoResult` it would be in the shell `$?` variable.\n\nIf these exit protocols are inadequate then you may need to call `dispatchGen()`\nand later call `try: dispatchFoo(someSeqString) except: discard` yourself.\nThis is all `dispatch` itself does.  ***Return*** _types and values_ of the\ngenerated dispatcher match the wrapped proc. { Other parameters to generated\ndispatchers are for internal use in `dispatchMulti` and probably don't matter to\nyou. }  A dispatcher raises 3 exception types: `HelpOnly`, `VersionOnly`,\n`ParseError`.  These are hopefully self-explanatory.\n\n---\n\nIf you want `cligen` to merge parameters from other sources, like a per-program\nconfig file and/or `$CMD` environment variable, then you can redefine\n`mergeParams()` after `import cligen` but before `dispatch`/`dispatchMulti`:\n```nim\nimport cligen, os, strutils # multi foo/multi bar are like subcommand example\nproc mergeParams(cmdNames: seq[string], cmdLine =\n                 commandLineParams()): seq[string] =\n  let e = cmdNames.join(\"_\").toUpperAscii.getEnv # $MULTI_(FOO|BAR)\n  if e.len\u003e0: e.parseCmdLine \u0026 cmdLine else: cmdLine # os.parseCmdLine\ndispatchMulti([foo, short={\"verb\": 'v'}], [bar])\n```\nYou can `include cligen/mergeCfgEnv` between `import cligen` \u0026 `dispatch` to\nmerge `${CMD_CONFIG:-${XDG_CONFIG_HOME:-$HOME/.config}}/CMD` (with Nim stdlib's\n`parsecfg` module) and then `$CMD` with `parseCmdLine` as above.\n\nUnless `cgCfgNone` is defined, `cligen` programs look for\n`${XDG_CONFIG_HOME:-$HOME/.config}/cligen`, e.g.\n[~/.config/cligen/config](https://github.com/c-blake/cligen/wiki/Example-Config-File)\nwhich allows command-line end users to tweak colors, layout, syntax, and usage\nhelp templates and generally set things that command authors can also [alter\ndefaults for](https://github.com/c-blake/cligen#common-overrides-program-exit-config-fileenvironment-vars)\nin the global [`cligen.clCfg`](cligen.nim#L28C1-L56C1).\n\n### Restrictions\n\n 1. Can only wrap basic funcs/procs -- no `auto|var` types, generics, etc.\n   \n 2. Param types used must have argParse, argHelp in scope (including generic\n    parameters like the `T` in `seq[T]`).\n\n 3. No param of a wrapped proc can be named \"help\".  (Name collision!)\n\n## Even More Controls and Details\n\n`cligen` grew many features upon request \u0026 usage.  The [test\nsuite](https://github.com/c-blake/cligen/tree/master/test/) has suggestively\nnamed examples.  There's also [a Wiki](https://github.com/c-blake/cligen/wiki),\n[generated docs for various modules](https://c-blake.github.io/cligen/) (which\ninclude various system interfaces useful in writing CLIs) and a [set of fully\nworked utilities](https://github.com/c-blake/bu) which may be useful to you in\ntheir own right.  I also try to mention breaking changes \u0026 new features in\n[RELEASE-NOTES](https://github.com/c-blake/cligen/tree/master/RELEASE-NOTES.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-blake%2Fcligen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc-blake%2Fcligen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-blake%2Fcligen/lists"}