{"id":13586940,"url":"https://github.com/adaszko/complgen","last_synced_at":"2026-03-07T12:01:17.085Z","repository":{"id":175848430,"uuid":"619212821","full_name":"adaszko/complgen","owner":"adaszko","description":"Declarative bash/fish/zsh/pwsh completions without writing shell scripts!","archived":false,"fork":false,"pushed_at":"2026-03-06T13:29:41.000Z","size":1563,"stargazers_count":293,"open_issues_count":0,"forks_count":9,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-06T17:26:40.796Z","etag":null,"topics":["bash","bash-shell","completion","completions","fish","fish-shell","powershell","pwsh","shell-completion","zsh","zsh-shell"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adaszko.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-03-26T15:46:27.000Z","updated_at":"2026-03-06T13:29:45.000Z","dependencies_parsed_at":"2024-01-10T06:12:26.441Z","dependency_job_id":"6d5d5172-9c4c-4370-b2e8-188642f4f387","html_url":"https://github.com/adaszko/complgen","commit_stats":{"total_commits":511,"total_committers":3,"mean_commits":"170.33333333333334","dds":0.009784735812133127,"last_synced_commit":"5e29dcbf46840bd9eb0599dcf737ce786d26340c"},"previous_names":["adaszko/complgen"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/adaszko/complgen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adaszko%2Fcomplgen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adaszko%2Fcomplgen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adaszko%2Fcomplgen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adaszko%2Fcomplgen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adaszko","download_url":"https://codeload.github.com/adaszko/complgen/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adaszko%2Fcomplgen/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30212485,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T09:02:10.694Z","status":"ssl_error","status_checked_at":"2026-03-07T09:02:08.429Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["bash","bash-shell","completion","completions","fish","fish-shell","powershell","pwsh","shell-completion","zsh","zsh-shell"],"created_at":"2024-08-01T15:05:55.433Z","updated_at":"2026-03-07T12:01:17.056Z","avatar_url":"https://github.com/adaszko.png","language":"Rust","readme":"## Value Proposition\n\n`complgen` compiles man-page-like grammars into standalone completion scripts.  One grammar file compiles into\nseveral different scripts for most popular shells, freeing you from having to reimplement and maintain the\nsame (state-machine) logic for each shell separately.  `complgen` grammars are declarative and thus much\neasier to maintain than long completion scripts.  See [examples](examples/).\n\n## Demo\n\n![demo](https://github.com/adaszko/complgen/blob/demo/complgen.gif)\n\n## Usage\n\n### Bash\n\n\u003cdetails\u003e\n\n```sh\n$ cat hello.usage\nhello --color=(always | never | auto);\n$ complgen --bash hello.bash hello.usage\n$ source hello.bash\n$ hello --color=\u003cTAB\u003e\nalways auto never\n```\n\n\u003c/details\u003e\n\n### Fish\n\n\u003cdetails\u003e\n\n```sh\n$ cat hello.usage\nhello --color=(always | never | auto);\n$ complgen --fish hello.fish hello.usage\n$ source hello.fish\n$ hello --color=\u003cTAB\u003e\n--color=always  --color=auto  --color=never\n```\n\n\u003c/details\u003e\n\n### Zsh\n\n\u003cdetails\u003e\n\n```sh\n% cat hello.usage\nhello --color=(always | never | auto);\n% complgen --zsh _hello hello.usage\n% source _hello\n% hello --color=\u003cTAB\u003e\nalways\nauto\nnever\n```\n\n💡 Note: Under ZSH, `source` isn't strictly necessary — it is enough to put the output file in one of the\ndirectories listed in `$fpath` variable.\n\u003c/details\u003e\n\n### PowerShell\n\n\u003cdetails\u003e\n\n```powershell\nPS\u003e Get-Content hello.usage\nhello --color=(always | never | auto);\nPS\u003e complgen --pwsh hello.ps1 hello.usage\nPS\u003e . ./hello.ps1\nPS\u003e hello --color=\u003cTAB\u003e\n--color=always  --color=auto  --color=never\n```\n\n💡 Note: Requires PowerShell Core 7+ (pwsh). Add the script to your `$PROFILE` for persistent completions.\n\u003c/details\u003e\n\n## Installation\n\n```sh\ncargo install --git https://github.com/adaszko/complgen --tag v0.8.0 complgen\n```\n\nOr download a pre-built binary from [the latest GitHub release](https://github.com/adaszko/complgen/releases).\n\n## Syntax\n\nSee the [`examples` subdirectory](examples/).\n\nA first approximation of a grammar (not guaranteed to work!) can be produced by piping target program's usage\ninfo onto `complgen --scrape` as below.  Note that all scraping is meant to do is to save you from too much\ntyping.  The produced grammar will still need to be fleshed out by hand.\n\n```\n$ grep --help | complgen --scrape\n | (-E | --extended-regexp) \"PATTERNS are extended regular expressions\"\n | (-F | --fixed-strings) \"PATTERNS are strings\"\n | (-G | --basic-regexp) \"PATTERNS are basic regular expressions\"\n[...]\n```\n\n***\n\ncomplgen's grammar is based on\n[compleat](https://github.com/mbrubeck/compleat/blob/master/README.markdown#syntax)'s one.\n\nA grammar is a series of lines separated by a semicolon (`;`).  Each line either represents a single variant\nof invoking the completed command (e.g. `git status; git log`) or is a nonterminal definition (`\u003cFOO\u003e ::=\nbar`).\n\n * `a b` matches `a` followed by `b`.\n * `a b | c` matches either `a b` or `c` (IOW: sequence binds stronger than alternative).\n * `[a]` matches zero or one occurrences of `a`.\n * `a...` matches one or more occurrences of `a`\n * `[a]...` matches zero or more occurrences of `a`.\n * `(aaa | bbb || ccc)` shows `aaa` and `bbb` as candidates, and `ccc` only when current input matches neither\n   `aaa` nor `bbb`.  `||` behaves exactly like `|` when matching, it differs only when offering completions.\n\nUse parentheses to group patterns:\n\n * `a (b | c)` matches `a` followed by either `b` or `c`.\n * `(a | b) ...` matches `a` or `b` followed by any number of additional\n   `a` or `b`.\n\n### Filename Completion\n\nThere's a small set of predefined nonterminals that are handled specially by `complgen`:\n\n| Name          | bash | fish | zsh | pwsh | Description |\n|---------------|------|------|-----|------|-------------|\n|`\u003cPATH\u003e`       | ✅   | ✅   | ✅  | ✅   | file or directory path |\n|`\u003cDIRECTORY\u003e`  | ✅   | ✅   | ✅  | ✅   | directory path |\n\nThese can still be redefined in the grammar (`\u003cPATH\u003e ::= ...`), in which case their predefined meaning gets\noverridden.\n\n### Completion Descriptions (fish/zsh/pwsh)\n\nIf a literal is immediately followed with a quoted string, it's going to appear as a hint to the user at\ncompletion time.  E.g. the grammar:\n\n```sh\ngrep --extended-regexp \"PATTERNS are extended regular expressions\" | --exclude  \"skip files that match GLOB\";\n```\n\nresults in something like this under fish, zsh, and PowerShell:\n\n```fish\nfish\u003e grep --ex\u003cTAB\u003e\n--exclude  (skip files that match GLOB)  --extended-regexp  (PATTERNS are extended regular expressions)\n```\n\nNote that `bash` does not support showing descriptions. In PowerShell, descriptions appear as tooltips.\n\n### Sourcing Completions from External Commands\n\nIt is possible to produce completions based on an external command output:\n\n    cmd {{{ echo foo; echo bar; echo baz; echo quux }}};\n\n```\nbash$ cmd \u003cTAB\u003e\nbar   baz   foo   quux\n```\n\n##### Descriptions\n\nExternals commands are also assumed to produce descriptions similar to those described in the [section\nabove](#descriptions).  Their expected stdout format is a sequence of lines of the form\n\n```\nCOMPLETION\\tDESCRIPTION\n```\n\nFor fish and zsh, the `DESCRIPTION` part will be presented to the user.  Under bash, only the `COMPLETION`\npart will be visible.  All external commands nonetheless need to take care as to *not* produce superfluous\n`\\t` characters that may confuse the resulting shell scripts.\n\n### Target Shell-specific Behavior\n\nExternal commands quickly degrade into necessitating shell-specific syntax.  complgen provides support to\nconditionally choose the command based on the target shell.\n\nTo use an example: all shells are able to complete users present on the system although each has a different\nfunction for it:\n\n```\ncmd \u003cUSER\u003e;\n\u003cUSER@bash\u003e ::= {{{ compgen -A user | sort | uniq }}}; # produce candidates on stdout under bash\n\u003cUSER@fish\u003e ::= {{{ __fish_complete_users }}}; # produce candidates on stdout under fish\n\u003cUSER@zsh\u003e ::= {{{ _users }}}; # produce candidates via compadd and friends under zsh\n\u003cUSER@pwsh\u003e ::= {{{ Get-LocalUser | ForEach-Object { $_.Name } }}}; # PowerShell\n```\n\ncomplgen will pick the right definition of `\u003cUSER\u003e` depending on what you're compiling the grammar to.\n\n### Completion Within Words\n\nIt's possible to match not only entire shell words, but also *within* words, using largely the same grammar\nsyntax as for matching entire words, barring few spaces here and there.  The most common application is to\nhandle option arguments (e.g. `--option=ARGUMENT`):\n\n```\ngrep --color=(always | never | auto);\n```\n\nThe same mechanism works for more complicated things:\n\n```\nstrace -e \u003cEXPR\u003e;\n\u003cEXPR\u003e ::= [\u003cqualifier\u003e=][!]\u003cvalue\u003e[,\u003cvalue\u003e]...;\n\u003cqualifier\u003e ::= trace | read | write | fault;\n\u003cvalue\u003e ::= %file | file | all;\n```\n\nThe above grammar was pulled straight out of [`strace` man\npage](https://man7.org/linux/man-pages/man1/strace.1.html#OPTIONS), illustrating how complgen follows the de\nfacto standard man pages notation.\n\n\n### Control What Gets Shown First\n\nIf you do `git \u003cTAB\u003e` under the default completion that comes with git, you get something like:\n\n```\nbash$ git \u003cTAB\u003e\nabsorb              bisect              ci                  credential-gcloud   fork                help                mv                  reflog              revert              show                submodule           whatchanged\nad                  blame               citool              describe            format-patch        init                notes               refs                reword              show-branch         sw                  worktree\nadd                 br                  clang-format        diff                fsck                instaweb            prune               remote              rewrite             sparse-checkout     switch\nam                  branch              clean               difftool            gc                  lfs                 pull                repack              rm                  stage               tag\namend               bundle              clone               dlog                gitk                log                 push                replace             root                stash               touch\napply               checkout            co                  fetch               grep                maintenance         range-diff          request-pull        scalar              stash-all           tree\narchive             cherry              commit              filter-repo         gui                 merge               rebase              reset               send-email          stash-unstaged      uncommit\nbackfill            cherry-pick         config              forgit              head                mergetool           recent              restore             shortlog            status              wdiff\n```\n\nSo even though git accepts many global options, they don't show up here!  If OTOH you do `git --\u003cTAB\u003e`\ninstead:\n\n```\nbash$ git --\u003cTAB\u003e\n--bare                 --exec-path=           --help                 --info-path            --namespace=           --no-replace-objects   --version\n--exec-path            --git-dir=             --html-path            --man-path             --no-pager             --paginate             --work-tree=\n```\n\nYou get presented with options in place of subcommands.  It's a useful mechanism that allows to assigning\nlevels of priority to possible choices, surfacing the most frequently used ones.\n\nUnder complgen, the same effect is achieved via\n_fallbacks_ (`||`).  An abridged version version of the above would look like below:\n\n```\nmygit (\u003cSUBCOMMAND\u003e || \u003cOPTION\u003e);\n\u003cSUBCOMMAND\u003e ::= fetch | add | commit | push;\n\u003cOPTION\u003e ::= --help | --version;\n```\n\nThe effect:\n\n```\nbash$ mygit \u003cTAB\u003e\nadd      commit   fetch    push\n\nbash$ mygit --\u003cTAB\u003e\n--help      --version\n```\n\nIn the 2nd case (`mygit --\u003cTAB\u003e`), the completion script first tries to match the input (`--`) against\n`\u003cSUBCOMMAND\u003e` and failing that, proceeds to try matching the part on the right hand side of the fallback\noperator `||`, i.e. `\u003cOPTION\u003e`.\n\nNote that `||` behaves exactly like the regular `|` in when it comes to matching.  Where its behavior diverges\nis with respect to completion.  Where `|` variants would offer all alternative branches at once, `||` tries to\nmatch variants from left to right, stopping at the first branch that matches current user input.\n\n`||` has the lowest priority of all operators, so the grammar above might have been written without any use of\n`\u003cNONTERMINALS\u003e`.  They're there only for readability sake.\n\n## Caveats\n\n* Bash requires `bash-completion` OS package to be installed because completion scripts produced by\n  `complgen`, call shell functions from that package at *completion* time.  This is necessary to work around\n  Bash's default behavior of [breaking shell words on any character present in the\n  `$COMP_WORDBREAKS`](https://stackoverflow.com/a/12495480) environment variable.\n\n* [Fish 4.0 fuzzy subsequence filtering](https://fishshell.com/docs/4.0/relnotes.html#completions) does not\n  work in scripts generated by complgen.\n\n* PowerShell completions require PowerShell Core 7+ (pwsh). Windows PowerShell 5.x is not supported.\n\n* Non-regular grammars aren't completed 100% *precisely*. For instance, in case of `find(1)`, `complgen` will\n  still suggest `)` even in cases when all `(` have already been properly closed before the cursor.\n\n## License\n\n`complgen`'s source code is covered by [License](LICENSE).  Completion scripts generated by `complgen` are\nsubject only to [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).\n","funding_links":[],"categories":["Other Resources","Rust"],"sub_categories":["ZSH Tools"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadaszko%2Fcomplgen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadaszko%2Fcomplgen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadaszko%2Fcomplgen/lists"}