{"id":20492287,"url":"https://github.com/starriver/charli","last_synced_at":"2025-04-13T17:02:11.637Z","repository":{"id":251040294,"uuid":"835761416","full_name":"starriver/charli","owner":"starriver","description":"Scant CLI toolkit for the summer","archived":false,"fork":false,"pushed_at":"2024-08-17T20:49:44.000Z","size":164,"stargazers_count":5,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2024-08-19T12:41:12.335Z","etag":null,"topics":["cli","command-line","golang","golang-library"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/starriver/charli","language":"Go","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/starriver.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"custom":"https://starriver.run/sponsor"}},"created_at":"2024-07-30T13:33:11.000Z","updated_at":"2024-08-17T20:48:48.000Z","dependencies_parsed_at":"2024-08-17T21:52:08.403Z","dependency_job_id":null,"html_url":"https://github.com/starriver/charli","commit_stats":null,"previous_names":["starriver/charli"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starriver%2Fcharli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starriver%2Fcharli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starriver%2Fcharli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/starriver%2Fcharli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/starriver","download_url":"https://codeload.github.com/starriver/charli/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224819250,"owners_count":17375248,"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":["cli","command-line","golang","golang-library"],"created_at":"2024-11-15T17:28:29.739Z","updated_at":"2024-11-15T17:28:30.439Z","avatar_url":"https://github.com/starriver.png","language":"Go","funding_links":["https://starriver.run/sponsor"],"categories":[],"sub_categories":[],"readme":"# c~~har~~li\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/starriver/charli.svg)](https://pkg.go.dev/github.com/starriver/charli)\n[![Go Report Card](https://goreportcard.com/badge/github.com/starriver/charli)](https://goreportcard.com/report/github.com/starriver/charli)\n[![Fantano Rating](https://img.shields.io/badge/fantano-10-purple\n)](https://youtu.be/bLJ-zfBmChA)\n[![Coverage Status](https://coveralls.io/repos/github/starriver/charli/badge.svg?branch=main)](https://coveralls.io/github/starriver/charli?branch=main)\n\nA small CLI toolkit. It includes a **CLI parser**, **help formatter**, and **completer** for bash \u0026 fish.\n\n![Screenshot](./.images/example.png)\n\n[See the code](./examples/readme/) for the above screenshot.\n\n## Quickstart\n\nTo install:\n\n```sh\ngo get github.com/starriver/charli\n```\n\n- [See the guide](./docs/guide.md) for usage instructions.\n- [Examples](./examples)\n- [Reference](https://pkg.go.dev/github.com/starriver/charli)\n\n## Who's this for?\n\nUse charli if you want to:\n\n- **Configure your CLI with struct data.** It doesn't use the builder pattern, struct tags or reflection.\n- **Have complete control over your app's I/O**. Expect no magic or surprises! None of the core functions have any side-effects.\n- **Bring your own input validation.** The parser outputs a map of options \u0026 positional args according to your config. It aggregates errors caused by unknown args and bad syntax. Nothing else is transformed: values are strings, flags are bools.\n\n## Design\n\nWe made charli because we're very picky about how we want our CLIs to look and behave – in particular, we want to engineer complex, imperative flows for validation. The amount of hacking required on other libraries wasn't worth it for us, so we made this instead.\n\n### Comparisons\n\n- [urfave/cli](https://github.com/urfave/cli) is a great library. Before using charli, try this. It's far more beginner-friendly, yet is probably this library's closest relative. Like charli, it features procedural operation and is configured via struct data – yet provides far more functionality out of the box.\n- [mitchellh/cli](https://github.com/mitchellh/cli) (now archived) also provides a nice degree of control with a procedural style, but instead provides flexibility through its interface types and factories (which you won't find here).\n\n### Parser syntax\n\n#### Options\n\ncharli supports both short and (GNU-style) long options.\n\nOptions normally take a string value. **Flags** are options without a value – ie. they have a boolean output.\n\nProvided that `-o/--option` and `-f/--flag` are configured, all of these are valid:\n\n```sh\nprogram --option value\nprogram --option=value\nprogram -o value\nprogram --flag\nprogram -f\n```\n\nIf a value starts with `-`, usage of the `--option=value` format is required to prevent ambiguity:\n\n```sh\nprogram --option -f    # Error!\nprogram --option=-f    # Valid\n```\n\nAdditionally, combined short flags are supported, but *not* combined short options. If `-j` and `-k` are also configured as flags:\n\n```sh\nprogram -fjk           # Valid\nprogram -fjko value    # Error!\nprogram -fjk -o value  # Valid\n```\n\n#### Positional arguments\n\nAny number of positional arguments can be configured. Args can be mixed in with options, and `--` can be used to stop parsing options.\n\nLet's say 2 args are configured:\n\n```sh\nprogram a b                 # Valid: []string{\"a\", \"b\"}\nprogram a -- -b             # Valid: []string{\"a\", \"-b\"}\nprogram a --option value b  # Valid: []string{\"a\", \"b\"}\nprogram --option a b        # Error! ('a' is the value for --option)\nprogram a b c               # Error! (too many args)\n```\n\nRegarding the last line above, varadic args are also supported. If enabled, it would become valid.\n\n#### Commands\n\nIn all of the above examples, the program has only had a single command. Instead, we can add multiple named commands, which should be supplied as the first argument.\n\nOptions can be global or command-specific. Positional arguments are always command-specific.\n\nWith `pull` and `push` commands configured, all of these are valid:\n\n```sh\nprogram pull\nprogram push\nprogram pull --option value\nprogram push -f\n```\n\nA default command can also be configured, allowing the first argument to be omitted. Note that this introduces some ambiguity should the first argument not be an option (ie. not starting with `-`).\n\n#### Requesting help\n\nBy default, the special `-h/--help` options can be used to request help – either for the whole program or a single command.\n\nThis flag can be supplied anywhere on the command line, but the parser will *suggest* that only certain forms exit with an OK status (it's up to you how to react to this suggestion, though).\n\n```sh\nprogram -h              # OK - display global help\nprogram -h pull         # OK - display help for pull\nprogram pull -h         # OK - display help for pull\nprogram pull --flag -h  # Error - display help for pull anyway\nprogram                 # Error - display global help anyway\n```\n\n`help` can also be optionally enabled as a pseudo-command, which will make all of these valid:\n\n```sh\nprogram help\nprogram help pull\nprogram pull help\n```\n\n### Goals\n\n- **Provide only necessary validation.**\n\t- Syntax checking only.\n\t- No transformation for values – only strings (and bools, in the case of flags).\n\t- This is to provide full control over the validation process downstream.\n- **Produce as many errors as possible.**\n\t- Aggregate errors. Downstream can decide how to deal with them.\n\t- Don't give up after encountering one parse error. Keep going!\n\t- Allow downstream validations to continue even with parse errors.\n\t- However: make downstream validations aware of previous errors, so that expensive operations can be short-circuited.\n- **Render a relatively sane help format.**\n\t- Allow arbitrary highlighting using a set color.\n\t- Prefer using raw strings for long description blocks [(example)](./examples/options/main.go).\n\t- Make color optional. We use [fatih/color](https://github.com/fatih/color), which allows turning them off (and automatically disables them when not in a tty).\n\t- More than anything else, we just made it look the way we wanted it to.\n- **Idiomatic Go.**\n\t- Leverage the flexibility of structs and zero values.\n\t- Aim for a procedural style.\n\t- `io.Writer` galore.\n\n## License\n\n[![ISC](./.images/license.jpg)](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstarriver%2Fcharli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstarriver%2Fcharli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstarriver%2Fcharli/lists"}