{"id":21477111,"url":"https://github.com/devedbox/commander","last_synced_at":"2025-07-25T17:41:03.472Z","repository":{"id":63908299,"uuid":"139727068","full_name":"devedbox/Commander","owner":"devedbox","description":"🚀The framework to write type-safe and structured command line program easily in Swift. ","archived":false,"fork":false,"pushed_at":"2020-11-21T05:05:42.000Z","size":764,"stargazers_count":168,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-28T17:39:44.095Z","etag":null,"topics":["cli","command-line","command-line-interface","command-line-parser","commandant","commander","commands","coverage-graph","swift","swift-cli","swift-framework","swift-library"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/devedbox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-04T13:38:17.000Z","updated_at":"2024-04-19T01:59:52.000Z","dependencies_parsed_at":"2022-11-28T20:15:53.300Z","dependency_job_id":null,"html_url":"https://github.com/devedbox/Commander","commit_stats":null,"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devedbox%2FCommander","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devedbox%2FCommander/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devedbox%2FCommander/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devedbox%2FCommander/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devedbox","download_url":"https://codeload.github.com/devedbox/Commander/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226033257,"owners_count":17563126,"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","command-line-interface","command-line-parser","commandant","commander","commands","coverage-graph","swift","swift-cli","swift-framework","swift-library"],"created_at":"2024-11-23T11:12:18.790Z","updated_at":"2024-11-23T11:12:19.407Z","avatar_url":"https://github.com/devedbox.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"Resources/logo.svg\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://travis-ci.com/devedbox/Commander.svg?branch=master\"\u003e\n  \u003ca href=\"https://codecov.io/gh/devedbox/Commander\"\u003e\n    \u003cimg src=\"https://codecov.io/gh/devedbox/Commander/branch/master/graph/badge.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codeclimate.com/github/devedbox/Commander/maintainability\"\u003e\n    \u003cimg src=\"https://api.codeclimate.com/v1/badges/83ff78d95f31412070e1/maintainability\"\u003e\n  \u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/language-swift-orange.svg\"\u003e\n  \u003cimg src=\"https://img.shields.io/github/tag-date/devedbox/Commander.svg?label=spm-ver\u0026colorB=lightgray\"\u003e\n  \u003ca href=\"https://gitter.im/commander-swift/Lobby?utm_source=share-link\u0026utm_medium=link\u0026utm_campaign=share-link\"\u003e\n    \u003cimg src=\"https://badges.gitter.im/devedbox/Commander.svg\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander/watchers\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/watchers/devedbox/Commander.svg?style=social\u0026label=Watch\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander/stargazers\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/stars/devedbox/Commander.svg?style=social\u0026label=Star\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander/fork\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/forks/devedbox/Commander.svg?style=social\u0026label=Fork\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://twitter.com/intent/follow?screen_name=devedbox\"\u003e\n    \u003cimg src=\"https://img.shields.io/twitter/follow/devedbox.svg?style=social\u0026label=Follow%20%40devedbox\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://twitter.com/intent/tweet?text=Commander+makes+it+easy+to+build+type-safe+and+structured+command-line+interface+program+in+Swift!\u0026url=https%3a%2f%2fgithub.com%2fdevedbox%2fCommander\u0026hashtags=github,swiftlang,commandline,iosdev,commander\u0026original_referer=http%3A%2F%2Fgithub.com%2F\u0026tw_p=tweetbutton\"\u003e\n    \u003cimg src=\"https://img.shields.io/twitter/url/http/shields.io.svg?style=social\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align='center'\u003e\n  \u003ca href=\"https://996.icu\"\u003e\u003cimg src=\"https://img.shields.io/badge/link-996.icu-red.svg\" alt=\"996.icu\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nCommander is a Swift framework for decoding command-line arguments by integrating with Swift standard library protocols Decodable \u0026 Decoder. Commander can help you to write **structured cli** program by declaring the structure of `command` and `options` of that command without writing any codes to parse the cli arguments. With Commander, you just need to focus on writing `options` structure of commands, the rest works will be handled by Commander automatically.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"Resources/sample.png\"\u003e\u003c/p\u003e\n\n# Table Of Contents\n\n- [Features](#features)\n- [Example](#example)\n- [Requirements](#requirements)\n- [Test Coverage Graph](#test-coverage-graph)\n- [Installation](#installation)\n  - [Swift Package Manager](#with-spm)\n- [Patterns](#patterns)\n  - [Key-Value Pairs](#key-value-pairs)\n    - [Single Value](#single-value)\n    - [Multiple Values](#multiple-values)\n  - [Argument](#argument)\n- [Value Types](#value-types)\n- [Usage](#usage)\n  - [Command](#command)\n    - [Creating A Command](#creating-a-command)\n    - [Dispatching A Command](#dispatching-a-command)\n    - [Adding Subcommands](#adding-subcommands)\n  - [Options](#options)\n    - [Declaring An Options](#declaring-an-options)\n    - [Changing Option Symbol](#changing-option-symbol)\n    - [Providing A Short Key](#providing-a-short-key)\n    - [Providing A Default Value](#providing-a-default-value)\n  - [Help Menu](#help-menu)\n  - [Arguments](#arguments)\n  - [Completions](#completions)\n    - [Installing Completion Scripts](#installing-completion-scripts)\n      - [Bash](#bash)\n      - [Zsh](#zsh)\n    - [Write Your Own Completion](#write-your-own-completion)\n- [License](#license)\n\n----\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander#features\"\u003e\u003cb\u003eFeatures\u003c/b\u003e\u003c/a\u003e\n  \u003cbody\u003e  -  \u003c/body\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander#example\"\u003e\u003cb\u003eExample\u003c/b\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Features\n\n- [x] Structured-CLI, commands and options are all structured by declaration of `struct` or `class`.\n- [x] Options types are type-safe by implementing `Decodable` protocol.\n- [x] Automatically generate help message for the `commander` or `command`.\n- [x] Shell `\u003cTab\u003e` completion supported. **Bash/Zsh** `\u003cTab\u003e` auto-complete scripts supported.\n- [x] Swift 4.x compatibility.\n- [x] Zero dependency and pure Swift.\n- [x] Supports Linux with `swift build`.\n  \n# Example\n\nWith Commander, a command and its associated options could be defined as follows:\n\n```swift\nimport Commander\n\npublic struct SampleCommand: CommandRepresentable {\n  public struct Options: OptionsRepresentable {\n    public typealias ArgumentsResolver = AnyArgumentsResolver\u003cString\u003e\n    public enum CodingKeys: String, CodingKeysRepresentable {\n      case verbose = \"verbose\"\n      case stringValue = \"string-value\"\n    }\n\n    public static let keys: [Options.CodingKeys : Character] = [\n      .verbose: \"v\",\n      .stringValue: \"s\"\n    ]\n\n    public static let descriptions: [Options.CodingKeys : OptionDescription] = [\n      .verbose: .usage(\"Prints the logs of the command\"),\n      .stringValue: .usage(\"Pass a value of String to the command\")\n    ]\n\n    public var verbose: Bool = false\n    public var stringValue: String = \"\"\n  }\n\n  public static let symbol: String = \"sample\"\n  public static let usage: String = \"Show sample usage of commander\"\n\n  public static func main(_ options: Options) throws {\n    print(options)\n    print(\"arguments: \\(options.arguments)\")\n    print(\"\\n\\n\\(Options.CodingKeys.stringValue.stringValue)\")\n  }\n}\n```\n\nThen, configuring the available commands would like this: \n\n```swift\nimport Commander\n\nCommander.commands = [\n  SampleCommand.self,\n  NoArgsCommand.self\n]\nCommander.usage = \"The sample usage command of 'Commander'\"\nCommander().dispatch() // Call this to dispatch and run the command\n```\n\nAfter which, arguments can be resolved by declaration of `ArgumentsResolver`:\n\n```swift\npublic typealias ArgumentsResolver = AnyArgumentsResolver\u003cT\u003e // T must be Decodable\n```\n\nAnd you can fetch the arguments by:\n```swift\npublic static func main(_ options: Options) throws {\n  print(\"arguments: \\(options.arguments)\") // 'arguments' is being declared in OptionsRepresentable \n}\n```\n\nAt last, run from shell:\n\n```bash\ncommander-sample sample --verbose --string-value String arg1 arg2\n# \n# Options(verbose: true, stringValue: \"String\")\n# arguments: [\"arg1\", \"arg2\"]\n#\n#\n# string-value\n```\n\nIt's easy and fun!!!\n\n----\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander#requirements\"\u003e\u003cb\u003eRequirements\u003c/b\u003e\u003c/a\u003e\n  \u003cbody\u003e  -  \u003c/body\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander#test-coverage-graph\"\u003e\u003cb\u003eTest Coverage Graph\u003c/b\u003e\u003c/a\u003e\n  \u003cbody\u003e  -  \u003c/body\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander#installation\"\u003e\u003cb\u003eInstallation\u003c/b\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Requirements\n\n- Mac OS X 10.10+ / Ubuntu 14.10\n- Xcode 10\n- Swift 4.2\n\n# Test Coverage Graph\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://codecov.io/gh/devedbox/Commander/commit/1a15f7be4db03125027641205529e0e5d5050b21/graphs/sunburst.svg\"\u003e\n\u003c/p\u003e\n\n# Installation\n\n## With [SPM](https://github.com/apple/swift-package-manager)\n\n```swift\n// swift-tools-version:4.2\ndependencies: [\n  .package(url: \"https://github.com/devedbox/Commander.git\", \"0.5.6..\u003c100.0.0\")\n]\n```\n\n----\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander#features\"\u003e\u003cb\u003ePatterns\u003c/b\u003e\u003c/a\u003e\n  \u003cbody\u003e  -  \u003c/body\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander#value-types\"\u003e\u003cb\u003eValue Types\u003c/b\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Patterns\n\n## Key-Value Pairs\n\n### Single Value\n\n```bash\ncommander command --key value --key1=value1\ncommander command --bool\ncommander command -k value -K=value1\ncommander command -z=value # {\"z\": \"value\"}\ncommander command -z # {\"z\": true}\ncommander command -zop # {\"z\": true, \"o\": true, \"p\": true}\n```\n\n### Multiple Values\n\n```bash\ncommander command --array val1,val2,val3\ncommander command -a val1,val2,val3\ncommander command --dict key1=val1,key2=val2,key3=val3\ncommander command -d key1=val1,key2=val2,key3=val3\ncommander command --array val1 --array val2 --array val3\ncommander command -a val1 -a val2 -a val3\ncommander command --dict key1=val1 --dict key2=val2 --dict key3=val3\ncommander command -d key1=val1 -d key2=val2 -d key3=val3\n```\n\n## Argument\n\nIn Commander，The position of arguments is not settled, they can be arywhere but the arguments must be continuous:\n\n```bash\ncommander command args... --options                   # before options\ncommander command --options args...                   # after options\ncommander command --options args... --options         # between options\ncommander command arg0... --options arg1... --options # Error\n```\n\nUse `--` to mark the ends of options and begins of arguments, but, this is normally optional in Commander:\n\n`commander command --options -- args...`\n\n# Value Types\n\nAs we all know, all the arguments from `CommandLine.arguments` is `String` type, in Commander, the available value types are:\n\n- Bool: `commander command --verbose`\n- Int(8, 16, 32, 64...): `commander command --int 100`\n- String: `commander command --string \"this is a string value\"`\n- Array: `commander command --array val1,val2,val3`\n- Dictionary: `commander command --dict key1=val1,key2=val2,key3=val3`\n\nArray object is delimited by character `,` and Dict object is delimited by character `=` and `,`.\n\n----\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander#usage\"\u003e\u003cb\u003eAdvanced Usage\u003c/b\u003e\u003c/a\u003e\n  \u003cbody\u003e  -  \u003c/body\u003e\n  \u003ca href=\"https://github.com/devedbox/Commander#license\"\u003e\u003cb\u003eLicense\u003c/b\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Usage\n\nCommander supports a main commander alongwith the commands of that commander, and each command has its own subcommands and options.\n\nUsing a Commander is simple, you just need to declare the `commands`, `usage` of the commander, and then call `Commander().dispatch()`, the Commander will automatically decode the command line arguments and dispatch the decoded options to the specific command given by command line.\n\nJust as simple as following:\n\n```swift\nimport Commander\n\nCommander.commands = [\n  SampleCommand.self,\n  NoArgsCommand.self\n]\nCommander.usage = \"The sample usage command of 'Commander'\"\nCommander().dispatch()\n```\n## Command\n\nIn Commander, a command is a type(`class` or `struct`) that conforms to protocol `CommandRepresentable`. The protocol *CommandRepresentable* declares the infos of the conforming commands:\n\n- `Options`: The associated type of command's options.\n- `symbol`: The symbol of the command used by command line shell.\n- `usage`: The usage help message for that command.\n- `children`: The subcommands of that command.\n\n### Creating A Command\n\n```swift\npublic struct Hello: CommandRepresentable {\n  public struct Options: OptionsRepresentable {\n    public enum CodingKeys: String, CodingKeysRepresentable {\n      case verbose\n    }\n    \n    public static let descriptions: [SampleCommand.Options.CodingKeys : OptionDescription] = [\n      .verbose: .usage(\"Prints the logs of the command\"),\n    ]\n    \n    public var verbose: Bool = false\n  }\n  \n  public static let symbol: String = \"sample\"\n  public static let usage: String = \"Show sample usage of commander\"\n  \n  public static func main(_ options: Options) throws {\n    if options.verbose {\n      print(options.argiments.first ?? \"\")\n    }\n  }\n}\n```\n\n### Dispatching A Command\n\nOnce a command has been created, it can be dispathed against a list of arguments, usually taken from CommandLine.arguments with dropping of the symbol of command itself.\n\n```swift\nlet arguments = [\"sample\", \"--verbose\", \"Hello world\"]\nCommand.dispatch(with: arguments.dropFirst())\n// Hello world\n```\n\nAs a real dispatching of command, you don't need to dispatch the command manually, the dispatching will be handled by Commander automatically.\n\n### Adding Subcommands\n\nAdding subcommands in Commander is by declaring the `children` of type `[CommandDescribable.Type]`:\n\n```swift\npublic struct Hello: CommandRepresentable {\n  ...\n  public static let children: [CommandDescribable.Type] = [\n    Subcommand1.self,\n    Subcommand2.self\n  ]\n  ...\n}\n```\n\n## Options\n\nThe `Options` is the same as command, is a type(`class` or `struct`) that conforms to protocol `OptionsRepresentable` which inherited from `Decodable` and can be treated as a simple data model, will be decoed by the built in code type `OptionsDecoder` in Commander.\n\n### Declaring An Options\n\nAs mentioned earlier in *[Creating a Command](#Creating-a-Command)*, declaring an options type is extremely easy, just another data model represents the raw string in command line arguments:\n\n```swift\npublic struct Options: OptionsRepresentable {\n  public enum CodingKeys: String, CodingKeysRepresentable {\n    case verbose\n  }\n\n  public static let descriptions: [SampleCommand.Options.CodingKeys : OptionDescription] = [\n    .verbose: .usage(\"Prints the logs of the command\"),\n  ]\n\n  public var verbose: Bool = false\n}\n```\n\n### Changing Option Symbol\n\nAs declared as `public var verbose: Bool`, we can use symbol in command line with `--verbose` accordingly, but how to use another different symbol in command line to wrap `verbose` such as `--is-verbose`? In Commander, we can just do as this:\n\n```swift\npublic enum CodingKeys: String, CodingKeysRepresentable {\n  case verbose = \"is-verbose\"\n}\n```\n\n### Providing A Short Key\n\nSometimes in develping command line tools, using a pattern like `-v` is necessary and helpful. In Commander, providing a short key for option is easy, we just need to declare a key-value pairs of type `[CodingKeys: Character]` in `Options.keys`:\n\n```swift\npublic struct Options: OptionsRepresentable {\n  ...\n  public static let keys: [CodingKeys: Character] = [\n    .verbose: \"v\"\n  ]\n  ...\n}\n```\n\n### Providing A Default Value\n\nWhen we difine a flag option in our command, provide a default value for flag is required because if we miss typing the flag in command line, the value of that flag means `false`. Providing default value in Commander is by add declaration in `Options.descritions` as this:\n\n```swift\npublic struct Options: OptionsRepresentable {\n  ...\n  public static let descriptions: [SampleCommand.Options.CodingKeys : OptionDescription] = [\n    .verbose: .default(value: false, usage:\"Prints the logs of the command\")\n  ]\n  ...\n}\n```\n\n## Help Menu\n\nIn Commander, help menu is generated by `CommandDescriber` describing types conforming `CommandDescribable` automatically, including commander itself and all declared commands.\n\nTo provide help menu usages, in commands:\n\n```swift\npublic struct Hello: CommandRepresentable {\n  ...\n  public static let symbol: String = \"sample\"\n  public static let usage: String = \"Show sample usage of commander\"\n  ...\n}\n```\n\nIn options:\n\n```swift\npublic struct Options: OptionsRepresentable {\n  ...\n  public static let descriptions: [SampleCommand.Options.CodingKeys : OptionDescription] = [\n    .verbose: .default(value: false, usage:\"Prints the logs of the command\")\n  ]\n  ...\n}\n```\n\nNormally, the help usage message and default can both be provided by type `OptionsDescriotion`.\n\nAfter declaration of usages, run `help` in terminal:\n\n```bash\ncommander-sample --help # or, commander-sample help\n# Usage:\n#\n#   $ commander-sample [COMMAND] [OPTIONS]\n#\n#     The sample usage command of 'Commander'\n#\n#   Commands:\n#\n#     help        Prints the help message of the command. Usage: [help [COMMANDS]]\n#     sample      Show sample usage of commander\n#     set-args    Set arguments of the command with given arguments\n#\n#   Options:\n#\n#     -h, --help  Prints the help message of the command. Usage: [[--help|-h][COMMAND --help][COMMAND -h]]\n```\n\nFor specific commands, run as this:\n\n```bash\ncommander-sample help sample # or, commander-sample sample --help\n# Usage of 'sample':\n#\n#   $ commander-sample sample [SUBCOMMAND] [OPTIONS] [ARGUMENTS]\n#\n#     Show sample usage of commander\n#\n#   Subcommands:\n#\n#     set-args            Set arguments of the command with given arguments\n#\n#   Options:\n#\n#     -s, --string-value  Pass a value of String to the command\n#     -h, --help          Prints the help message of the command. Usage: [[--help|-h][COMMAND --help][COMMAND -h]]\n#     -v, --verbose       Prints the logs of the command\n#\n#   Arguments:\n#\n#     [String]            commander-sample sample [options] arg1 arg2 ...\n```\n\n## Arguments\n\nIn Commander, an option can take multiple arguments from command line arguments as the arguments of that option, and can be accessed by calling `options.arguments`. The arguments decoding can not be resolvable by default, if you want to resolve the decoding of arguments, you must declare the `ArgumentsResolver` of the options:\n\n```swift\npublic struct Options: OptionsRepresentable {\n  ...\n  public typealias ArgumentsResolver = AnyArgumentsResolver\u003cString\u003e\n  ...\n}\n```\n\nThe type `AnyArgumentsResolver\u003cT\u003e` is generic type where the type `T` representing the type of arguments' element. With the declaration above, we can do this is command line:\n\n```bash\ncommander hello --verbose -- \"Hello world\" \"Will be dropped\"\n# \"Hello world\" \"Will be dropped\" are both the arguments of Hello.Options\n```\n\n## Completions\n\nCommander provided the api to write auto-completion in bash/zsh, the requirement is declared in protocol `ShellCompletable`. The `CommandDescribable` and `OptionsDescribable` is inherited from `ShellCompletable` by default.\n\nTo implemente auto-completion, you just need to write:\n```swift\nimport Commander.Utility\n// Options:\npublic static func completions(for commandLine: Utility.CommandLine) -\u003e [String] {\n  switch key {\n  case \"--string-value\":\n    return [\n      \"a\", \"b\", \"c\"\n    ]\n  default:\n    return [ ]\n  }\n}\n```\n\nIn terminal, type this:\n\n```bash\ncommander sample --string-value \u003cTab\u003e\n# a\tb\tc\n```\n\n### Installing Completion Scripts\n\nCommander can generate auto-completion scripts for you, you can run the built-in command `complete generate` to generate the scripts according to the shell type. Currently available shells are:\n\n- bash\n- zsh\n\n#### Bash\n\n- run in terminal：`commander complete generate --shell=bash \u003e ./bash_completion`\n- then：`source ./bash_completion`\n- or, install the scripts to the login scripts of bash for good at `~/.profile`\n\n#### Zsh\n\n- run in terminal：`commander complete generate --shell=zsh \u003e ~/zsh_completions/_commander`\n- add contents to `~/.zshrc`:\n  ```zsh \n  fpath=(~/zsh_completions $fpath)\n  autoload -U +X compinit \u0026\u0026 compinit\n  autoload -U +X bashcompinit \u0026\u0026 bashcompinit\n  ```\n- restart you terminal\n\n### Write Your Own Completion\n\n`CommandDescribable` already provided the default implementation of completion, by default, CommandDescribable provides the subcommands alongwith options as the completions for shell, you can override the default implementation to provide your custom completions to Commander.\n\n`OptionsDescribable` returns an empty completions by default, OptionsDescribable will be called during the calling of CommandDescribable automatically, You must override the implementation of OptionsDescribable to provide your completions or an empty completions will be used.\n\nThis is an example to provide `git branchs` completions to shell:\n\n```swift\nimport Commander.Utility\n\npublic static func completions(for commandLine: Utility.CommandLine) -\u003e [String] {\n  let current = commandLine.arguments.last\n  let previous = commandLine.arguments.dropLast().last\n\n  switch current {\n  default:\n    let outputs = ShellIn(\"git branch -r\").execute().output.flatMap {\n      String(data: $0, encoding: .utf8)\n    } ?? \"\"\n\n    return outputs.split(whereSeparator: {\n      \" *-\u003e\\n\".contains($0)\n    }).map {\n      if $0.hasPrefix(\"origin/\") {\n        return String(String($0)[\"origin/\".endIndex...])\n      } else {\n        return String($0)\n      }\n    }\n  }\n}\n```\n\n# License\n\nCommander is released under the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevedbox%2Fcommander","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevedbox%2Fcommander","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevedbox%2Fcommander/lists"}