{"id":28416676,"url":"https://github.com/hellflame/argparse","last_synced_at":"2025-06-16T21:33:40.573Z","repository":{"id":40587685,"uuid":"363658179","full_name":"hellflame/argparse","owner":"hellflame","description":"argparse for golang","archived":false,"fork":false,"pushed_at":"2023-11-22T10:59:40.000Z","size":1608,"stargazers_count":24,"open_issues_count":2,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-04T06:22:24.686Z","etag":null,"topics":["argparse","go","levenshtein-matcher","positional-arguments"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hellflame.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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":"2021-05-02T13:31:05.000Z","updated_at":"2025-05-02T13:10:00.000Z","dependencies_parsed_at":"2023-11-22T11:41:32.833Z","dependency_job_id":null,"html_url":"https://github.com/hellflame/argparse","commit_stats":null,"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/hellflame/argparse","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellflame%2Fargparse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellflame%2Fargparse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellflame%2Fargparse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellflame%2Fargparse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hellflame","download_url":"https://codeload.github.com/hellflame/argparse/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellflame%2Fargparse/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260245066,"owners_count":22980138,"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":["argparse","go","levenshtein-matcher","positional-arguments"],"created_at":"2025-06-03T23:14:13.921Z","updated_at":"2025-06-16T21:33:40.557Z","avatar_url":"https://github.com/hellflame.png","language":"Go","readme":"# argparse\n\n[![GoDoc](https://godoc.org/github.com/hellflame/argparse?status.svg)](https://godoc.org/github.com/hellflame/argparse) [![Go Report Card](https://goreportcard.com/badge/github.com/hellflame/argparse)](https://goreportcard.com/report/github.com/hellflame/argparse) [![Coverage Status](https://coveralls.io/repos/github/hellflame/argparse/badge.svg?branch=master)](https://coveralls.io/github/hellflame/argparse?branch=master)\n\n[中文文档](docs/cn.md)\n\nArgparser is inspired by [python argparse](https://docs.python.org/3.9/library/argparse.html)\n\nIt's small but Powerful\n\nProviding not only simple parsing args, but :\n\n- [x] Sub Command\n- [x] Argument Groups\n- [x] Positional Arguments\n- [x] Customizable Parse Formatter\n- [x] Customizable Validate Checker\n- [x] Argument Choice Support\n- [x] Argument Action Support (infinite possible)\n- [x] Shell Completion Support\n- [x] Levenshtein Reminder\n- [x] Output Color Schema Support\n- [ ] ......\n\n## Aim\n\nThe aim of the project is to help programers build better command line programs using `golang`.\n\n## Installation\n\n```bash\ngo get -u github.com/hellflame/argparse\n```\n\n\u003e no third-party dependence required\n\n## Usage\n\nJust go:\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"github.com/hellflame/argparse\"\n)\n\nfunc main() {\n    parser := argparse.NewParser(\"basic\", \"this is a basic program\", nil)\n\n    name := parser.String(\"n\", \"name\", nil)\n\n    if e := parser.Parse(nil); e != nil {\n        fmt.Println(e.Error())\n      \treturn\n    }\n    fmt.Printf(\"hello %s\\n\", *name)\n}\n```\n\n[example](examples/basic)\n\nCheck output:\n\n```bash\n=\u003e go run main.go\nusage: basic [-h] [-n NAME]\n\nthis is a basic program\n\noptions:\n  -h, --help            show this help message\n  -n NAME, --name NAME\n\n=\u003e go run main.go -n hellflame\nhello hellflame\n```\n\nA few points:\n\nAbout the object __parser__ :\n\n1. `NewParser`'s first argument is the name of your program, it's ok __to be empty__. When it's an empty string, the program's name will be `path.Base(os.Args[0])` . It can be handy when the release name is not decided yet.\n2. `help` entry is usable by default, you can disable it with `\u0026ParserConfig{DisableHelp: true}` when invoking `NewParser`, then you can define your own `help` .\n3. When *help message* showed up, the program will default __exit with code 1 (version \u003c v1.5)__ or __return error with type BreakAfterHelp (version \u003e= 1.5)__ or the __error equals BreakAfterHelpError (version \u003e= 1.10)__ , this is stoppable by setting `ParserConfig.ContinueOnHelp = true` .\n\nAbout the action __parse__ :\n\n1. The argument `name` is bond to user's input __after__  `parser.Parse` \n2. When give `parser.Parse` a `nil` as the argument, `os.Args[1:]` is used as parse source\n3. The short name of your argument can be __more than one character__\n\n---\n\nBased on those points above, the code can be altered like this:\n\n```go\nfunc main() {\n    parser := argparse.NewParser(\"\", \"this is a basic program\", \u0026argparse.ParserConfig{\n        DisableHelp:true,\n        DisableDefaultShowHelp: true})\n  \n    name := parser.String(\"n\", \"name\", nil)\n    help := parser.Flag(\"help\", \"help-me\", nil)\n  \n    if e := parser.Parse(os.Args[1:]); e != nil {\n        fmt.Println(e.Error())\n        return\n    }\n    if *help {\n        parser.PrintHelp()\n        return\n    }\n    if *name != \"\" {\n        fmt.Printf(\"hello %s\\n\", *name)\n    }\n}\n```\n\n[example](examples/basic-bias)\n\nCheck output:\n\n```bash\n=\u003e go run main.go  # there will be no output\n\n=\u003e go run main.go -h\nunrecognized arguments: -h\ndo you mean?: -n\n\n# the real help entry is -help / --help-me\n=\u003e go run main.go -help\nusage: main [-n NAME] [-help]\n\nthis is a basic program\n\noptions:\n  -n NAME, --name NAME\n  -help, --help-me\n\n=\u003e go run main.go --name hellflame\nhello hellflame\n```\n\nA few more points:\n\n1. `DisableHelp` only prevent  `-h/--help` flag from registering to parser, but the `help` function is still available using `PrintHelp` and `FormatHelp`.\n2. When `DisableDefaultShowHelp` is false, and there is no user input, the `help` message will still show up as Default Action.\n3. Display help message by invoking `parser.PrintHelp()` , `return` will put an end to the `main` function.\n4. Notice the order of usage array, it's mostly the order of creating arguments, I tried to keep them this way. [example](example/change-help)\n\n### Features\n\nSome show cases\n\n#### 1. Levenshtein error correct [ \u003e= v1.2.0 ]\n\nthe `Parser` will try to give most posibile __options__ as recommend when there is no match\n\n```go\nparser := NewParser(\"\", \"\", nil)\nparser.String(\"a\", \"aa\", nil)\nif e := parser.Parse([]string{\"--ax\"}); e != nil {\n  if e.Error() != \"unrecognized arguments: --ax\\ndo you mean?: --aa\" {\n    t.Error(\"failed to guess input\")\n    return\n  }\n}\n// when user input '--ax', Parser will try to find best matches with nearrest levenshtein-distance\n// here for example is --aa\n```\n\nNotice that if there are multiple `Positional Argument` , the `unrecognized arguments` will be regard as `Positional Argument` , and there will be no recommend. \n\n#### 2. Extra special positional arguments [ \u003e= v1.12 ]\n\nWhen the user want to input some special arguments starting with `-` or `--` , normally the parser will warn you with  `unrecognized arguments`. \n\nIf you want to do so, simply input any arguments after a single `--`. \n\nFor example: `./run -- extra1 extra2`.  In the example, `extra1`  and `extra2` can be anything, `./run -- --1 -x`.\n\nIf the last positional argument receives multiple inputs, then the positional inputs before and after `--` will all be its value.\n\n```go\nnames := parser.Strings(\"\", \"names\", \u0026argparse.Option{Positional: true})\nparser.parse([]string{\"a\", \"--\", \"b\", \"c\"})\n// names == [\"a\", \"b\", \"c\"]\n```\n\n### Supported Arguments\n\n#### 1. Flag\n\n```go\nparser.Flag(short, full, *Option)\n```\n\n`Flag` create a flag argument, return a `*bool` pointer to the parse result\n\nPython version is like `add_argument(\"-s\", \"--full\", action=\"store_true\")`\n\nFlag Argument can only be used as an __OptionalArguments__, more restrictions see [restrictions](#restriction-of-flags).\n\n#### 2. String\n\n```go\nparser.String(short, full, *Option)\n```\n\n`String` create a string argument, return a `*string` pointer to the parse result\n\nString Argument can be used as Optional or Positional Argument, default to be Optional. It's like `add_argument(\"-s\", \"--full\")` in python\n\nSet `Option.Positional = true` to use as Positional Argument, it's like `add_argument(\"s\", \"full\")` in python\n\n#### 3. String List\n\n```go\nparser.Strings(short, full, *Option)\n```\n\n`Strings` create a string list argument, return a `*[]string` pointer to the parse result\n\nOptions are mostly like `*Parser.String()`\n\nPython version is like `add_argument(\"-s\", \"--full\", nargs=\"*\")` \n\n#### 4. Int\n\n```go\nparser.Int(short, full, *Option)\n```\n\n`Int` create an int argument, return a `*int` pointer to the parse result\n\nOptions are mostly like `*Parser.String()`, except the return type\n\nPython version is like `add_argument(\"-s\", \"--full\", type=int)`\n\n#### 5. Int List\n\n```go\nparser.Ints(short, full, *Option)\n```\n\n`Ints` create an int list argument, return a `*[]int` pointer to the parse result\n\nOptions are mostly like `*Parser.Int()`\n\nPython version is like `add_argument(\"-s\", \"--full\", type=int, nargs=\"*\")`\n\n#### 6. Float\n\n```go\nparser.Float(short, full, *Option)\n```\n\n`Float` create a float argument, return a `*float64` pointer to the parse result\n\nOptions are mostly like `*Parser.String()`, except the return type\n\nPython version is like `add_argument(\"-s\", \"--full\", type=double)` \n\n#### 7. Float List\n\n```go\nparser.Floats(short, full, *Option)\n```\n\n`Floats` create a float list argument, return a `*[]float64` pointer to the parse result\n\nOptions are mostly like `*Parser.Float()`\n\nPython version is like `add_argument(\"-s\", \"--full\", type=double, nargs=\"*\")` \n\n### Other Types\n\nFor complex types or even customized types, this library do __not directly support__ these feature , but it doesn't mean you can't do anything. Here are some cases:\n\n#### 1. File type\n\nYou can check file's existence before reading it, and tells if it's a valid file, check modify time, etc. [example](examples/customzed-types/main.go)\n\nThough the return type is still a `string` , but it's more garanteed to use them\n\n```go\npath := parser.String(\"f\", \"file\", \u0026argparse.Option{\n  Validate: func(arg string) error {\n    if _, e := os.Stat(arg); e != nil {\n      return fmt.Errorf(\"unable to access '%s'\", arg)\n    }\n    return nil\n  },\n})\n\nif e := parser.Parse(nil); e != nil {\n  fmt.Println(e.Error())\n  return\n}\n\nif *path != \"\" {\n  if read, e := os.ReadFile(*path); e == nil {\n    fmt.Println(string(read))\n  }\n}\n```\n\nThe case above used `Validate` to do the trick, we'll talk about it later in more detail\n\nPython code is like:\n\n```python\ndef valid_type(arg):\n  if not os.path.exist(arg):\n    raise Exception(\"can't access {}\".format(arg))\n  return arg\n\nparser.add_argument(\"-s\", \"--full\", type=valid_type)\n```\n\nThe difference is that, python can return any type from the type function `valid_type` , and you can just return a `file` type in there\n\nThere could arise some problems if a `*File` is returned in go. the `*File` might be used somewhere before, which makes it non-idempotent, and you need to `Close` the file somewhere, or the memory may leak, the resource management can be a problem. Instead of using `*File` with danger, you can manage the resouce in much safer way:\n\n```go\nfunc dealFile(path) {\n  f, e := os.Open(\"\")\n  if e != nil {\n    fmt.Println(e.Error())\n    return\n  }\n  defer f.Close()  // close file\n  io.ReadAll(f)\n}\n```\n\n#### 2. Any Type\n\nCheckout `Action` for example, then you can handle any type when parsing arguments !\n\n### Advanced\n\n#### 1. Argument Group\n\nArgument group is useful to arrange arguments help info in to groups, only affects how the help info displays, use `Group` config to do so. [example](examples/yt-download/main.go)\n\n```go\nparser.Flag(\"\", \"version\", \u0026argparse.Option{\n  Help: \"Print program version and exit\", \n  Group: \"General Options\",\n})\n```\n\n#### 2. Display Meta\n\nWhen the full name of the argument is too long to display, `Meta` can change how it displays in help info. More Control can be optimized by __MaxHeaderLength__. [example](examples/yt-download/main.go)\n\n```go\nparser.Int(\"\", \"playlist-start\", \u0026argparse.Option{\n  Help: \"Playlist video to start at (default is 1)\", \n  Meta: \"NUMBER\",\n})\n```\n\nIt will look like this in help message:\n\n```bash\n  --playlist-start NUMBER  Playlist video to start at (default is 1)\n```\n\n#### 3.Default Value\n\nIf the argument is not specified by user, default value will be applied. [example](examples/yt-download/main.go)\n\n```go\nparser.Int(\"\", \"playlist-start\", \u0026argparse.Option{\n  Help: \"Playlist video to start at (default is 1)\", \n  Default: \"1\",\n})\n```\n\nNote that the Default value is a `String`, the value is used like an argument from `os.Args`, it has to get through `Validate` \u0026 `Formatter` \u0026 `parse` actions (if exist).\n\nAlso, the Default value can only be a `String` , and if you want an Array of arguments, you can only have one element Array as default value. You can apply your default array after *parse*.\n\n#### 4. Required Argument\n\nIf the argument must be specified by the user, set `Required` to be `true`. [example](examples/yt-download/main.go)\n\n```go\nparser.Strings(\"\", \"url\", \u0026argparse.Option{\n  Help: \"youtube links, like 'https://www.youtube.com/watch?v=xxxxxxxx'\", \n  Required: true,\n})\n```\n\nFlag argument can not be `Required` (flag argument has more [restrictions](#restriction-of-flags), you will be noticed while choosing it)\n\n#### 5. Positional Argument\n\nIf you want users to input arguments by position, set `Positional` to be true. [example](examples/yt-download/main.go)\n\n```go\nparser.Strings(\"\", \"url\", \u0026argparse.Option{\n  Help: \"youtube links, like 'https://www.youtube.com/watch?v=xxxxxxxx'\", \n  Positional: true,\n})\n```\n\nThe position of the Positional Argument is quit flex, with not much restrictions, it's ok to be\n\n1. in the middle of other arguments, `--play-list 2 xxxxxxxx --update`. If the argument before it is an Array argument,  `url` will be treated as one of the Array argument: `--user-ids id1 id2 url --update` \n2. after another single value Positional Argument, `--mode login username password` , the last `password` will be regard as another Positional Argument\n\nSo, use it carefully, it may __confuse__ (for the users), which is the same in argparse of Python Version.\n\n#### 6. Argument Validation\n\nProvide `Validate` function to check every one of its argument\n\n```go\nparser.Strings(\"\", \"url\", \u0026argparse.Option{\n  Help: \"youtube links\", \n  Validate: func(arg string) error {\n    if !strings.HasPrefix(arg, \"https://\") {\n      return fmt.Errorf(\"url should be start with 'https://'\")\n    }\n    return nil\n  },\n})\n```\n\n`Validate` function is executed just after when `Default` value is set, which means, the default value has to go through `Validate` check.\n\n\u003e If the argument is an array type (`Ints`, `Strings`, `Floats` ...), every element will be validated by this function.\n\n#### 7. Argument Formatter\n\nRe-format input argument, but remember that, the return type of `Formatter` should be the same as your argument type\n\n```go\nparser.String(\"\", \"b\", \u0026Option{\n  Formatter: func(arg string) (i interface{}, err error) {\n    if arg == \"False\" {\n      err = fmt.Errorf(\"no False\")\n      return\n    }\n    i = fmt.Sprintf(\"=\u003e %s\", arg)\n    return\n  },\n})\n```\n\nIf `Validate` is set, `Formatter` is executed after `Validate`.\n\nIf error is raised in `Formatter`, it acts like `Validate`.\n\nThe return type of `interface{}` should be the same as your Argument Type, or Element Type of your Arguments, here,  is a `string` in the Example.\n\n#### 8. Argument Choices\n\nRestrict inputs to be within the given choices, use `Choices`\n\n```go\nparser.Ints(\"\", \"hours\", \u0026Option{\n  Choices: []interface{}{1, 2, 3, 4},\n})\n```\n\nThe element type of the choice is the same as argument, or the element of the argument.\n\nIf `Formatter` is set, Choice check is right after `Formatter`\n\nWhen it's single value, the value must be one of the `Choices`\n\nWhen it's value array, each value must be one of of `Choices`\n\n#### 9. Sub Commands\n\nCreate new parser scope, arguments won't interrupt other parsers(root parser and other sub parsers)\n\n```go\nfunc main() {\n  parser := argparse.NewParser(\"sub-command\", \"Go is a tool for managing Go source code.\", nil)\n  t := parser.Flag(\"f\", \"flag\", \u0026argparse.Option{Help: \"from main parser\"})\n  testCommand := parser.AddCommand(\"test\", \"start a bug report\", nil)\n  tFlag := testCommand.Flag(\"f\", \"flag\", \u0026argparse.Option{Help: \"from test parser\"})\n  otherFlag := testCommand.Flag(\"o\", \"other\", nil)\n  defaultInt := testCommand.Int(\"i\", \"int\", \u0026argparse.Option{Default: \"1\"})\n  if e := parser.Parse(nil); e != nil {\n    fmt.Println(e.Error())\n    return\n  }\n  println(*tFlag, *otherFlag, *t, *defaultInt)\n}\n```\n\nOutput:\n\n```bash\n=\u003e ./sub-command\nusage: sub-command \u003ccmd\u003e [-h] [-f]\n\nGo is a tool for managing Go source code.\n\ncommands:\n  test        start a bug report\n\noptions:\n  -h, --help  show this help message\n  -f, --flag  from main parser\n\n# when using sub command, it's a total different context\n=\u003e ./sub-command test\nusage: sub-command test [-h] [-f] [-o] [-i INT]\n\nstart a bug report\n\noptions:\n  -h, --help         show this help message\n  -f, --flag         from test parser\n  -o, --other\n  -i INT, --int INT\n```\n\nThe two `--flag` will parse seperately, so you can use `tFlag` \u0026 `t` to reference flag in `test` parser and `main` parser.\n\n1. sub command has different context, so you can have two `--flag`, and different help message output\n2. sub command show help message seperately, it's for user to understand your program *step by step*. While `Group Argument` helps user to understand your program *group by group*\n2. Theoretically, you can create sub parser infinitely. Create a sub parser of a sub parser of a subparser ... Somehow, which would make the program harder to use, and easy to run out of users' patience.\n\n**[v1.7.3]** Fix:\n\n* Invoked Action\n\nif subparser is invoked, the root parser will **NOT** be invoked.\n\n* When Not Invoked\n\nif subparser is **NOT** invoked, no argument's default value will be applied, and required argument will not be checked ... The subparser remains dead. (It's a bug if the subparser gets alive !)\n\n#### 10. Argument Action\n\nArgument Action allows you to do anything with the argument if there is any match, this enables infinite possibility when parsing arguments. [example](examples/any-type-action/main.go)\n\n```go\np := NewParser(\"action\", \"test action\", nil)\n\nsum := 0\np.Strings(\"\", \"number\", \u0026Option{Positional: true, Action: func(args []string) error {\n  // here tries to sum every input number\n  for _, a := range args {\n    if i, e := strconv.Atoi(a); e != nil {\n      return fmt.Errorf(\"I don't know this number: %s\", a)\n    } else {\n      sum += i\n    }\n  }\n  return nil\n}})\n\nif e := p.Parse([]string{\"1\", \"2\", \"3\"}); e != nil {\n  fmt.Println(e.Error())\n  return\n}\n\nfmt.Println(sum)  // 6\n```\n\nA few points:\n\n1. `Action` is a function with `args []string` as input，the `args` has two kinds of input\n   * `nil` : which means it's a `Flag` argument\n   * `[]string{\"a1\", \"a2\"}` : which means you have bond other type of argument, other than `Flag` argument\n2. Errors can be returned if necessary, it can be normally captured in *parse*.\n3. The return type of the argument is not of much importance, using `p.Strings` is the same as `p.Ints` , because `arg.Action` will be executed __before binding value__, which means, `Action` has __top priority__\n4. If `Action` is executed,  `Validate`, `Formatter`, Choice check and value binding will be ignored.\n\n#### 11. Default Parse Action [ \u003e= v0.4 ]\n\nInstead of showing help message as default, you can set your own default action when no user input is given, [example](examples/parse-action/main.go)\n\n```go\nparser := argparse.NewParser(\"basic\", \"this is a basic program\", \u0026argparse.ParserConfig{DefaultAction: func() {\n  fmt.Println(\"hi ~\\ntell me what to do?\")\n}})\nparser.AddCommand(\"test\", \"testing\", \u0026argparse.ParserConfig{DefaultAction: func() {\n  fmt.Println(\"ok, now you know we are testing\")\n}})\nif e := parser.Parse(nil); e != nil {\n  fmt.Println(e.Error())\n  return\n}\n```\n\nWhen `DefaultAction` is set, default action of showing help message will be ignored.\n\n`DefaultAction` is effective on sub command, and if sub parser's `ParserConfig` is `nil`, `DefaultAction` from main parser will be inherited.\n\n#### 12. Shell Completion Support [ \u003e= v0.4 ]\n\nUsers can get terminal hint through tapping [tab]\n\nSet `ParserConfig.AddShellCompletion` to `true` will register `--completion` to the parser. [example](examples/shell-completion/main.go)\n\n```go\np := argparse.NewParser(\"start\", \"this is test\", \u0026argparse.ParserConfig{AddShellCompletion: true})\np.Strings(\"a\", \"aa\", nil)\np.Int(\"\", \"bb\", nil)\np.Float(\"c\", \"cc\", \u0026argparse.Option{Positional: true})\ntest := p.AddCommand(\"test\", \"\", nil)\ntest.String(\"a\", \"aa\", nil)\ntest.Int(\"\", \"bb\", nil)\ninstall := p.AddCommand(\"install\", \"\", nil)\ninstall.Strings(\"i\", \"in\", nil)\nif e := p.Parse(nil); e != nil {\n  fmt.Println(e.Error())\n  return\n}\n```\n\nThough, if you didn't set `ParserConfig.AddShellCompletion` to `true` , shell complete script is still available via `parser.FormatCompletionScript` , which will generate the script.\n\n__Note__: \n\n1. the completion script only support `bash` \u0026 `zsh` for now\n2. and it only generate simple complete code for basic use, it should be better than nothing.\n3. sub command has __no__ completion entry\n3. you will know if the user has triggered this input by checking the error returned from `Parse` function, it's a `BreakAfterShellScriptError`.\n\nSave the output code (using `start --completion`) to `~/.bashrc` or `~/.zshrc` or `~/bash_profile` or some file at `/etc/bash_completion.d/` or `/usr/local/etc/bash_completion.d/` , then restart the shell or `source ~/.bashrc` will enable the completion. Or just save completion by appending this line in `~/.bashrc`:\n\n```bash\neval `start --completion`\n```\n\nCompletion the function is supported by shell, and the shell identify your program by its name, so you `MUST`  give your program a fix name.\n\n#### 13. Hide Entry [ \u003e= 1.3 ]\n\nSometimes, you want to hide en entry from users, because they should not see or are not necessary to know the entry, but you can still use the entry. Situations like:\n\n1. the entry is to help generate completion candidates (which has mess or not much meaningful output)\n2. secret back door that users should not know (you can use `os.Getenv` instead, but `argparse` can do more)\n\nYou only need to set `Option{HideEntry: true}` \n\n```go\nfunc main() {\n  parser := argparse.NewParser(\"basic\", \"this is a basic program\", nil)\n  name := parser.String(\"n\", \"name\", nil)\n  greet := parser.String(\"g\", \"greet\", \u0026argparse.Option{HideEntry: true})\n  if e := parser.Parse(nil); e != nil {\n    fmt.Println(e.Error())\n    return\n  }\n  greetWord := \"hello\"\n  if *greet != \"\" {\n    greetWord = *greet\n  }\n  fmt.Printf(\"%s %s\\n\", greetWord, *name)\n}\n```\n\ncheck ouput:\n\n```bash\nusage: basic [--help] [--name NAME]\n\nthis is a basic program\n\noptions:\n  --help, -h               show this help message\n  --name NAME, -n NAME\n```\n\nWhich will have effect in `Shell Completion Script`\n\n[example](examples/hide-help-entry/main.go)\n\n#### 14. Invoked \u0026 InvokeAction [ \u003e= 1.4 ]\n\nWhen there is valid match for main parser or sub parser,  `Parser.Invoked` will be set true. If `Parser.InvokeAction` is set, it will be executed. \n\n```go\np := NewParser(\"\", \"\", nil)\na := p.String(\"a\", \"\", nil)\nsub := p.AddCommand(\"sub\", \"\", nil)\nb := sub.String(\"b\", \"\", nil)\np.InvokeAction = func(invoked bool) {\n  // do things when main parser has any match\n}\nsub.InvokeAction = func(invoked bool) {\n  // do things when sub parser has any match\n}\nsubNo2 := p.AddCommand(\"sub2\", \"\", nil)\nsubNo2.Int(\"a\", \"\", nil)\nsubNo2.InvokeAction = func(invoked bool) {\n  // do things when sub2 parser has any match\n}\n\nif e := p.Parse(nil); e != nil {\n  t.Error(e.Error())\n  return\n}\n\n// check parser Invoked\n\nfmt.Println(p.Invoked, sub.Invoked, subNo2.Invoked)\n```\n\n#### 15. Help info hint [ \u003e= v1.6 ]\n\nHelp message can be generated with some hint info, like default value, choice range, required mark, or even any hint message. Like:\n\n```bash\nusage: sub-command test [--help] [--flag] [--other] [--float FLOAT] [--int INT] [--string STRING]\n\nstart a bug report\n\noptions:\n  --help, -h                  show this help message\n  --flag, -f                  from test parser\n  --other, -o                 (optional =\u003e ∫)\n  --float FLOAT               (options: [0.100000, 0.200000], required)\n  --int INT, -i INT           this is int (default: 1)\n  --string STRING, -s STRING  no hint message\n```\n\nEnable global hint by setting parser config `\u0026argparse.ParserConfig{WithHint: true}` .\n\nDisable one argument hint with `\u0026argparse.Option{NoHint: true}`\n\nCustomize argument hint with `\u0026argparse.Option{HintInfo: \"customize info\"}`\n\n[example](examples/sub-command)\n\n#### 16. Limit args header length [ \u003e= 1.7 ]\n\nWhen argument is too long, you can set `ParserConfig.MaxHeaderLength` to a reasonable length.\n\nBefore setting `MaxHeaderLength` , the help info may display like (which is default to adjust to the longest argument length):\n\n```bash\nusage: long-args [--help] [--short SHORT] [--medium-size MEDIUM-SIZE] [--this-is-a-very-long-args THIS-IS-A-VERY-LONG-ARGS]\noptions:\n  --help, -h                                                                        show this help message\n  --short SHORT, -s SHORT                                                           this is a short args\n  --medium-size MEDIUM-SIZE, -m MEDIUM-SIZE                                         this is a medium size args\n  --this-is-a-very-long-args THIS-IS-A-VERY-LONG-ARGS, -l THIS-IS-A-VERY-LONG-ARGS  this is a very long args\n\n```\n\nAfter setting `ParserConfig.MaxHeaderLength = 20` (it's recommended to be around 20 ~ 30)，argument's help info will display on new line with 20 space indent, if its header is too long.\n\n```bash\nusage: long-args [--help] [--short SHORT] [--medium-size MEDIUM-SIZE] [--this-is-a-very-long-args THIS-IS-A-VERY-LONG-ARGS]\noptions:\n  --help, -h        show this help message\n  --short SHORT, -s SHORT\n                    this is a short args\n  --medium-size MEDIUM-SIZE, -m MEDIUM-SIZE\n                    this is a medium size args\n  --this-is-a-very-long-args THIS-IS-A-VERY-LONG-ARGS, -l THIS-IS-A-VERY-LONG-ARGS\n                    this is a very long args\n```\n\n[example](examples/long-args/main.go)\n\n#### 17. Inheriable argument [ \u003e= 1.8 ]\n\nWhen some argument represent the same thing among root parser and sub parsers, such as `debug`, `verbose` .... and you don't want to write duplicated arguments code for too many times, you have two recommended ways:\n\nbefore *v1.8*, as all sub parsers are the same type as root parser, use a `for` loop with `Action` would do it.\n\n```go\nparser := argparse.NewParser(\"\", \"\", nil)\nsub := parser.AddCommand(\"sub\", \"\", nil)\nsub2 := parser.AddCommand(\"sub2\", \"\", nil)\n\nurl := \"\"\nfor _, p := range []*argparse.Parser{parser, sub, sub2} {\n    p.String(\"\", \"url\", \u0026argparse.Option{Action: func(args []string) error {\n        url = args[0]\n        return nil\n    }})\n}\n\nif e := parser.Parse(nil); e != nil {\n    return\n}\nprint(url)\n```\n\nThe code above might be less clean, and there comes `Inheritable` , which is an `argument option` . When argument sets __`\u0026argparse.Option{Inheritable: true}`__, sub parsers added __after__ the argument will be able to inherit this argument or override it.\n\n```go\nparser := argparse.NewParser(\"\", \"\", nil)\nverbose := parser.Flag(\"v\", \"\", \u0026argparse.Option{Inheritable: true, Help: \"show verbose info\"}) // inheritable argument\nlocal := parser.AddCommand(\"local\", \"\", nil)\nservice := parser.AddCommand(\"service\", \"\", nil)\nversion := service.Int(\"v\", \"version\", \u0026argparse.Option{Help: \"choose version\"})\n```\n\nAs a result,  sub parser `local` will inhert `verbose` as a `Flag`, when pass user input `program local -v`, `*verbose` will be `true`, which means `*verbose` is shared among root parser and inherited parsers. However, as prefix `v` is also registered as `Int` by sub parser `service`, you can't use `-v` to `show verbose`, but `choose version` , it's `overrided`.\n\n\u003e Note `Inheritable` is valid for `Positional`, if their metaNames are the same, `argparse` will consider them the same.\n\n[example](examples/inherit/main.go)\n\n#### 18. Bind given parsers to an argument [ \u003e= 1.9 ]\n\nThis is a very flexable way to create argument for multiple parsers. Create one argument using the main parser, and provide a series of parsers by setting the option when you create the argument:\n\n __`Option{BindParsers: []*Parser{a, b, ...}}`__.\n\n```go\nparser := argparse.NewParser(\"\", \"\", nil)\na := parser.AddCommand(\"a\", \"\", nil)\nb := parser.AddCommand(\"b\", \"\", nil)\nc := parser.AddCommand(\"c\", \"\", nil)\n\nab := parser.String(\"\", \"ab\", \u0026argparse.Option{\n    BindParsers: []*argparse.Parser{a, b},\n})\nbc := parser.String(\"\", \"bc\", \u0026argparse.Option{\n    BindParsers: []*argparse.Parser{b, c},\n})\n```\n\nAs a result, subparser `a` \u0026 `b` will bind a `String` argument with entry `--ab` and referred to by var `ab` , subparser `b` \u0026 `c` will bind a `String` argument with entry `--bc` and referred to by var `bc`. \n\n__Note__ that both arguments are detached from main `parser`, because you've set the `BindParsers`. If you still want to bind the argument to the main parser, append it to `BindParsers`, like `BindParsers: []*argparse.Parser{b, c, parser}`.\n\nThis is one way to share a single argument among different parsers. Be aware that creating argument like this still need to go through conflict check, if there's already a `--ab` exist in `a` or `b` parser, there will be a panic to notice the programer.\n\n#### 19. Color Schema Support [ \u003e= 1.11 ]\n\nSet `ParserConfig.WithColor = true`, and the help message can be dyed with different colors, if the users' terminal support color.\n\nAlso Set `ParserConfig.EnsureColor = true`, and the help message will surely dye with colors. This is for some rare terminals without the environment variable `TERM`, the programer can check it for your own. Normally this is not necessary.\n\nYou can also set `ParserConfig.ColorSchema` to dye the help message with your own style. Take `DefaultColor` for reference, most part of the help message can be given a `Color` with *Code* and *Property*. A few knowledge of how color is presented in terminal is required. Normally you can try set Color *Code* within 30 and 49 to represent different text color and background color, and set Color *Property* within 10. Do some combinations, and you'll master them, just try!\n\n[example](./examples/colorful/main.go)\n\n![](./docs/images/colorful.png)\n\n##### Argument Process Flow Map\n\n```\n\n                    ┌────►  BindAction？\n                    │            │\n                    │            │  Consume it's Arguments\n                    │            ▼\n                    │    ┌──────┐\n  --date 20210102 --list │ arg1 │ arg2  arg3\n                         └───┬──┘\n                             │\n                             │\n                             ▼\n                        ApplyDefault?\n                             │\n                             │\n                       ┌─────▼──────┐\n                       │  Validate  │\n                       └─────┬──────┘\n                             │\n                       ┌─────▼──────┐\n                       │  Formatter │\n                       └─────┬──────┘\n                             │\n                       ┌─────▼───────┐\n                       │ ChoiceCheck │\n                       └─────────────┘\n```\n\nThe return value of last process will be the input of next process, if shows it in code, it's like\n\n```python\nwith MatchFound:\n  if MatchFound.BindAction:\n    return MatchFound.BindAction(*args)\n  else:\n    for arg in args:\n      if Validate(arg):\n        yield ChoiceCheck(Formatter(arg))\n```\n\n##### Restrictions Of Flag Argument {#restriction-of-flags}\n\n1. Can't be Positional\n2. Can't has Choices\n3. Can't be Required\n4. Can't set Formatter\n5. Can't set Validate function\n\n## Config\n\n### 1. Parser Config\n\nRelative struct: \n\n```go\ntype ParserConfig struct {\n  Usage  string // manual usage display\n  EpiLog string // message after help\n\n  DisableHelp            bool // disable help entry register [-h/--help]\n  ContinueOnHelp         bool // set true to: continue program after default help is printed\n  DisableDefaultShowHelp bool // set false to: default show help when there is no args to parse (default action)\n\n  DefaultAction      func() // set default action to replace default help action\n  AddShellCompletion bool   // set true to register shell completion entry [--completion]\n  WithHint           bool   // argument help message with argument default value hint\n  MaxHeaderLength    int    // max argument header length in help menu, help info will start at new line if argument meta info is too long\n\n  WithColor   bool         // enable colorful help message if the terminal has support for color\n  EnsureColor bool         // use color code for sure, skip terminal env check\n  ColorSchema *ColorSchema // use given color schema to draw help info\n}\n```\n\nexample:\n\n```go\nfunc main() {\n  parser := argparse.NewParser(\"basic\", \"this is a basic program\",\n\t\t\u0026argparse.ParserConfig{\n      Usage:                  \"basic xxx\",\n      EpiLog:                 \"more detail please visit https://github.com/hellflame/argparse\",\n      DisableHelp:            true,\n      ContinueOnHelp:         true,\n      DisableDefaultShowHelp: true,\n    })\n\n  name := parser.String(\"n\", \"name\", nil)\n  help := parser.Flag(\"help\", \"help-me\", nil)\n\n  if e := parser.Parse(nil); e != nil {\n    fmt.Println(e.Error())\n    return\n  }\n  if *help {\n    parser.PrintHelp()\n    return\n  }\n  if *name != \"\" {\n    fmt.Printf(\"hello %s\\n\", *name)\n  }\n}\n```\n\n[example](examples/parser-config)\n\nOutput:\n\n```bash\n=\u003e go run main.go\n# there will be no help message\n# affected by DisableDefaultShowHelp\n\n=\u003e go run main.go --help-me\nusage: basic xxx   # \u003c=== Usage\n\nthis is a basic program\n\noptions: # no [-h/--help] flag is registerd, which is affected by DisableHelp\n  -n NAME, --name NAME\n  -help, --help-me \n\nmore detail please visit https://github.com/hellflame/argparse  # \u003c=== EpiLog\n```\n\nExcept the comment above, `ContinueOnHelp` is only affective on your program process, which gives you possibility to do something when `help` entry is invoked.\n\n### 2. Argument Options\n\nRelated struct:\n\n```go\ntype Option struct {\n  Meta       string // meta value for help/usage generate\n  multi      bool   // take more than one argument\n  Default    string // default argument value if not given\n  isFlag     bool   // use as flag\n  Required   bool   // require to be set\n  Positional bool   // is positional argument\n  HideEntry  bool   // hide usage \u0026 help display\n  Help       string // help message\n  Group      string // argument group info, default to be no group\n  Inheritable bool  // sub parsers after this argument can inherit it\n  Action     func(args []string) error // bind actions when the match is found, 'args' can be nil to be a flag\n  Choices    []interface{}  // input argument must be one/some of the choice\n  Validate   func(arg string) error  // customize function to check argument validation\n  Formatter  func(arg string) (interface{}, error) // format input arguments by the given method\n}\n```\n\n## How it works\n\n```\n  ┌──────────────────────┐ ┌──────────────────────┐\n  │                      │ │                      │\n  │     OptionArgsMap    │ │  PositionalArgsList  │\n  │                      │ │                      │\n  │      -h ───► helpArg │ │                      │\n  │                      │ │[  posArg1  posArg2  ]│\n  │      -n ──┐          │ │                      │\n  │           │► nameArg │ │                      │\n  │  --name ──┘          │ │                      │\n  │                      │ │                      │\n  └──────────────────────┘ └──────────────────────┘\n             ▲ yes                  no ▲\n             │                         │\n             │ match?──────────────────┘\n             │\n             │\n           ┌─┴──┐                   match helpArg:\n    args:  │ -h │-n  hellflame           ▼\n           └────┘                  ┌──isflag?───┐\n                                   ▼            ▼\n                                  done ┌──MultiValue?───┐\n                                       ▼                ▼\n                                   ┌──parse     consume untill\n                                   ▼            NextOptionArgs\n                                 done\n```\n\n## Error \u0026 Panic\n\nThe principle of returning `error` or just panic is that, __no panic for production use__ \n\nCases where `argparse` will panic:\n\n1. failed to add subcommand\n2. failed to add argument entry, `Strings`, `Flag`, etc.\n\nThose failures is not allowed, and you will notice when you test your program. The rest errors will be returned in `Parse`, which you should be able to tell users what to do.\n\n## [Examples](examples)\n\nthere are some useful use cases to help you build your own command line program\n\nfeel free to add different use cases\n\n\n\n1. [more type action](examples/any-type-action)\n2. [parse action(don't help yet)](examples/parse-action)\n3. [shell completion(tabs-able)](examples/shell-completion)\n4. [hide help entry](examples/hide-help-entry)\n5. [customized types(it's all your call)](examples/customzed-types)\n6. [how to add sub command](examples/sub-command)\n7. [deal with long args](examples/long-args)\n8. [multiple parser in one program](examples/multi-parser)\n9. [decide help's position](examples/change-help)\n9. [argument groups](examples/argument-groups)\n9. [batch create arguments](examples/batch-create-arguments)\n9. [argument inherit](examples/inherit)\n9. [color support](examples/colorful)\n9. [extra arguments](examples/extra-arguments)\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhellflame%2Fargparse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhellflame%2Fargparse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhellflame%2Fargparse/lists"}