{"id":32996857,"url":"https://gitlab.com/oldrwxrob/cmdtab","last_synced_at":"2026-04-08T14:32:41.290Z","repository":{"id":61722002,"uuid":"17698759","full_name":"oldrwxrob/cmdtab","owner":"oldrwxrob","description":"","archived":false,"fork":false,"pushed_at":null,"size":null,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":null,"default_branch":"master","last_synced_at":"2026-01-02T10:55:23.086Z","etag":null,"topics":["Switches","bash","commander","completion","documentation","flags","golang","help","options","shell","tab"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://gitlab.com/oldrwxrob/cmdtab/-/avatar","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-25T02:14:18.574Z","updated_at":"2020-09-21T02:09:25.384Z","dependencies_parsed_at":"2022-10-20T12:00:30.161Z","dependency_job_id":null,"html_url":"https://gitlab.com/oldrwxrob/cmdtab","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"purl":"pkg:gitlab/oldrwxrob/cmdtab","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/gitlab.com/repositories/oldrwxrob%2Fcmdtab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/gitlab.com/repositories/oldrwxrob%2Fcmdtab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/gitlab.com/repositories/oldrwxrob%2Fcmdtab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/gitlab.com/repositories/oldrwxrob%2Fcmdtab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/gitlab.com/owners/oldrwxrob","download_url":"https://gitlab.com/oldrwxrob/cmdtab/-/archive/master/cmdtab-master.zip","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/gitlab.com/repositories/oldrwxrob%2Fcmdtab/sbom","scorecard":null,"host":{"name":"gitlab.com","url":"https://gitlab.com","kind":"gitlab","repositories_count":4521539,"owners_count":7348,"icon_url":"https://github.com/gitlab.png","version":null,"created_at":"2022-05-30T11:31:42.605Z","updated_at":"2026-01-12T22:45:04.389Z","status":"online","status_checked_at":"2026-04-08T02:00:06.506Z","response_time":256,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.382Z","robots_txt_url":"https://gitlab.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/gitlab.com","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/gitlab.com/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/gitlab.com/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/gitlab.com/owners"}},"keywords":["Switches","bash","commander","completion","documentation","flags","golang","help","options","shell","tab"],"created_at":"2025-11-13T12:00:52.190Z","updated_at":"2026-04-08T14:32:41.278Z","avatar_url":"https://gitlab.com/oldrwxrob/cmdtab/-/avatar","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Go Tab Complete Commander\n\n[![Go Report\nCard](https://goreportcard.com/badge/gitlab.com/rwxrob/cmdtab)](https://goreportcard.com/report/gitlab.com/rwxrob/cmdtab)\n[![Coverage](https://gocover.io/_badge/gitlab.com/rwxrob/cmdtab)](https://gocover.io/gitlab.com/rwxrob/cmdtab)\n[![GoDoc](https://godoc.org/gitlab.com/rwxrob/cmdtab?status.svg)](https://godoc.org/gitlab.com/rwxrob/cmdtab)\n\n*A commander for modern command-line human-computer interactions.*\n\n![logo](cmdtab.png)\n\n*Tab Complete Commander* is a lightweight commander package focused on\ncreating human-friendly terminal command-line interfaces composed of\nmodular subcommands with portable completion and embedded, dynamic\ndocumentation.\n\n## Installation\n\nNormally you would simply `import \"gitlab.com/rwxrob/cmdtab\"` but you\ncan install it for review using the following as well:\n\n```\ngo get -u gitlab.com/rwxrob/cmdtab\n```\n\n## Advantages\n\n* Build the command-line interface to your application completely\n  independently from your core library.\n\n* Automatic and extendible Bash tab completion built in.\n\n* Modular, interchangeable, readable subcommands.\n\n* Easiest possible command documentation with support for emphasis with\n  simple Markdown formatting.\n\n## Ongoing Project\n\nAlthough Complete Commander is fully functional now it should still be\nconsidered beta until the final [TODO](#TODO) items are complete. Most\nof them are related to better default actions and output formatting.\n\n## How It Works\n\nThe magic of *Complete Commander* comes from the clean separation of\nsubcommands into their own files and composing them into an internal\ncommand index within the main executable program. This is accomplished\nthrough simple, judicious use of the `init()` function in each file.\nThis approach incurs no more performance hit than would already be\nrequired for any other such solution and is 100% concurrency safe.\n\nBy the time the command-line application's `main()` function is called\nall it has to do is `cmd.Execute(\"mycmd\")` to execute the top-level\ncommand:\n\n1. Detects and responds to programmable shell completion context\n1. Optionally adds the `help`, `usage`, and `version` builtins\n1. Delegates to any subcommands, or\n1. Runs its own top-level method\n\nBecause of the loose coupling, and top-down design a full subcommand\nnode tree can easily be displayed and documented, indeed the builtin\ncommands do exactly that. When care is given to maintain this loose\ncoupling between subcommands a file can be modularly added or moved to\nany other executable directory creating very clean sharing and\ncomposition possibilities.\n\n## Motivation\n\nThis package scratches several \"personal itches\" that have come up from\nthe needs of modern human-computer interaction clearly passing what is\ncurrently available:\n\n1. No commanders exist for writing simple commands with human-friendly subcommands\n1. No commanders exist that know anything about tab completion\n1. Tab completion is the simplest way to provide good help to the user\n1. Getopt-style options are ancient, ridiculously bad HCI\n1. More users are voicing their commands rather than typing them\n1. More users are using keyboard input with their thumbs\n1. Modern command-line programs need to be easily distributed\n1. Distributing executables with separate documentation complicates understanding the program\n1. Modern monolithic command approaches allow embedded documentation and better distribution\n1. Operating system package managers are overkill for distributing most command executables\n1. Documentation only needs to cover what the user is specifically interested in\n1. Documentation can be provided dynamically when embedded within the command it documents\n\n### Times Have Changed\n\nThe world has outgrown the original UNIX model for both command design\nand documentation, presumably due to the resource constraints of the\nday. These constraints forced shared library dependencies and commands\nwere designed to be as minimal as possible doing \"only one thing really\nwell.\" Combining several actions into a single command (think `git\nclone` or `go tool dist list`) or embedding full command documentation\ninto the executable would have been considered monstrously wasteful at\nthat time. The result was lots of small commands dependent on specific\nshared libraries and a separate documentation system (`man` pages).\n\nToday Go has revolutionized applications development and respectfully\nembraced modern use of resources. Static linking, cross-compilation,\nbuilt in concurrency, reflection and documentation are all evidence of\nhow time have changed.  It follows then, that our command interface\ndesigns and documentation approaches should equally modernize.\n\nThere is now plenty of room to compose several commands and subcommands\ninto a single monolithic executable. In fact, this has become idiomatic\nfor Go's own tool set. Distribution and portability are more important\nthan memory and storage size these days.\n\n### Sometimes You Just Need Tab\n\nUsually completion context is triggered simply by tapping tab once or\ntwice from the shell when typing in the command and its different\nsubcommand arguments. Tab completion is supported as a standard in most\nall modern shells. Tab completion is often all that is needed, even\nusage would be overkill. A user simply wants to remember what the\ncommand name is.\n\n### Keep the Docs with the Command\n\nClean, standardized, extensive documentation needs to travel with the\ncommand it documents rather than being separate from it. There is no\ntelling what operating systems will emerge nor how (and if) they will\nimplement system documentation of any kind. Indeed, with the use of\nmodern web and git hosting documentation the need for any system-level\ndocumentation system is sharply diminishing. Better to embed it with the\ncommand itself when needed.\n\nEmbedded documentation has the ability to dynamically sense the\nenvironment and context for its use thereby creating more useful,\nspecific help to the user. This means that rather than dumping every\nsingle usage option into a massive man page separate from the command\n(think `gpg`), such documentation can be broken up and displayed\nprogrammatically by the command itself.\n\nMost modern terminals support color (ANSI escapes) and UTF-8 (yes even\nWindows) and regularly display more than 80 columns of text.\n\n### Modern Human-Computer Interaction\n\nVoice and human-friendly textual command-line interfaces are becoming\nmore and more popular as more humans interact with command line\ninterfaces in chat applications, messaging and more. This influence has\npermeated to system command design and deprecated the design decision to\nuse traditional getopt-like switches and options, which cannot be voiced\nor tab-completed easily. (Consider how difficult it is to type or voice\na simple dash into most text applications.)\n\nSimplicity on the command-line has been an ignored requirement for some\ntime. Why? Because only amazing technical people are using the command\nline? Perhaps. But that is a very bad reason. Interfaces need not be\noverly complex or difficult to memorize just because most users are\ntechnical.\n\nThe *Complete Commander* approach takes these HCI considerations very\nseriously placing priority on how humans use modern command-line\ninterfaces and developing them accordingly. Human interaction is the\nsingle most important design decision for any application, including one\nthat runs on the command line.\n\n## Design Decisions\n\nThis is a summary of the design decisions made roughly in the order they\nwere made. It is provided in the hopes of addressing other design\nconcerns anyone reviewing this package might have before choosing to use\nit.\n\n* To this day command options plague developers and users by different\n  ways of dealing with single or double dashes, the equals sign, single\n  letter options and more. Most are also not friendly to the use of\n  UTF-8 runes in the upper ranges.\n\n* Even through `getopt` can be problematic (having had to code for it\n  and around it for two decades and still has nightmares about `gpg`'s\n  interface) `MapOpts` is available for those who insist on using them\n  giving the command author the choice. Parsing traditional getopt-type\n  options and switches was originally dropped since the goals of this\n  project are to deprecate such designs in favor of modern HCI\n  approaches to command-line user interfaces. But, choice prevails over\n  opinion in this case. Still, please don't use `-f \u003cfile\u003e` when the\n  tab-completable `file \u003cfile\u003e` could be used instead. Even a single\n  dash `-` is nearly impossible to voice-to-text command-line interface.\n\n* Semantic emphasis `*bold*`, `**italic**`, `***bold-italic***` are the\n  only inline formatting options allowed. This seems prudent given the\n  fundamental requirement for readability as well as the complication of\n  other inline formatting and escapes.  These three inline formats have\n  been supported by all system documentation formats from the beginning\n  and play nicely with Go's back-ticked raw-strings. Users can change\n  the colors of these on terminals that use term(cap|info)-aware man\n  pages and less/more (i.e.  `LESS_TERMCAP_??` or `COMPCMD_??`) without\n  any need to provide theming in the package itself.\n\n* The decision to not use other Markdown for formatting was easy given\n  the minimal three formats allowed. The decision to keep documentation\n  100% compatible with CommonMark was a no-brainer decision. \n\n* Pager application (i.e. less, more) detection seems practical since\n  most everyone would want such when help output exceeds the page height\n  (when such can be determined). There is a TODO to add fall-back\n  builtin pager support.\n\n* Allowing more than 80 columns and never hard-wrapping lines allows the\n  user to decide the preferred width of documentation.  Lines that are\n  hard-wrapped are unreadable when the column count drops to less than\n  that of the hard-wrapping. With TMUX small pane widths are common.\n  (This is one thing Go documentation seriously failed to consider.)\n\n* Internationalization was a big design consideration from the\n  beginning. All code containing the English defaults is separate from\n  the rest allowing build tools to generate language specific versions.\n  The idea of putting all supported languages into monolithic files with\n  locale templates was considered but quickly dismissed given the\n  potential impact to executable size. Localized builds are a common\n  industry practice. The English naming of the default builtin commands\n  is at least as appropriate as these standard keywords are included in\n  many other contexts `help`, `version`, and `usage` are very\n  ubiquitous. If needed, these can be aliased easily by adding commands\n  that encapsulate them with `Call()`.\n\n* Using `structs` instead of interfaces makes more sense given the goals\n  to enable quick and easy to read and write documentation embedded in\n  the source.\n\n* Including a fair amount of output formatting and printing code seemed\n  appropriate given that one of the three main goals of the project was\n  to produce consistent command output formatting. It had been suggested\n  to put such into another package instead but this package is so small\n  that ultimately turned out to be overkill. Besides, the formatting\n  used by `cmd` is highly specific to making output look good on a\n  terminal as it relates to command documentation.\n\n* Rather than hard-code a dependency on Bash completion, every effort\n  has been made to decouple completion from any specific shell\n  completion API (despite the many references to Bash, which dominates\n  currently). As long as any shell completion implementation sets an\n  environment variable containing the full line to be completed package\n  `cmd` will always be able to sense completion context and perform.\n  This puts the completion logic safely embedded into the command that\n  needs the completion and exposes as little dependency on shell\n  completion methods as possible.\n\n* Inferring the main (top-level) command to use was considered to be the\n  first argument (`os.Args[0]`) for some time but further research\n  revealed it can never be relied upon fully. It also initially seemed\n  clever to change the behavior of an executable simply by changing its\n  name but this was quickly dismissed when clearer thinking prevailed\n  concerning this and other security concerns. Therefore, the first\n  command must be passed as an argument to `cmd.Execute(\"mytopcmd\")`. It\n  is simple enough, however, to compile other executables with different\n  main commands. Indeed, only the argument to need change to do so.\n\n* Rather than add the complication of wrapping lines in a block and\n  indenting the proper number of spaces for a given terminal width\n  (which could be resized), the choice to keep all blocks beginning from\n  the leftmost column was made. This makes the best use of screen space,\n  is consistent with the help documentation from Go itself, and allows\n  the output to be sized to any width without complication. Instead,\n  emphasis has been given to the headers of the specific blocks. When\n  indentation is truly needed raw-text (initial four spaces) can be\n  used.\n\n* Full DocOpt parsing of usage was considered and dismissed. DocOpt\n  solves a different problem with different priorities (which do no\n  include consideration of getopt-style command lines interfaces as an\n  anti-pattern in terms of HCI). In fact, the only thing that should\n  every really been in a usage string are lists of subcommands or\n  arguments called out by name with `\u003csomething\u003e` both of which are\n  automatically formatted when detected. In other words, no usage should\n  ever include `-` or `--` prefixed anything. *Everything* should be\n  voice-able. This makes even the most complicated commands extremely\n  easy to understand quickly. \n\n* Support for all-caps keywords (ex: `[OPTIONS]`) in usage strings was\n  considered and dismissed because angle-bracket notation already covers\n  that and having single suggested usage format is simpler. It is also\n  far easier for the formatting parser to determine what should be\n  italicized using angle-brackets.\n\n* Decided against any paged output of any special hidden builtin to\n  allow combination with other shell scripts when quick customization is\n  needed. Paged output remains for the main `help`, `usage`, and\n  `version` builtins however.\n\n* Removed all color and formatting from the special hidden builtin\n  output since is will mostly likely be used by shell scripts that\n  further parse it, for example to email all the authors.\n\n* `Emphasize()`, `Wrap()`, and `Indent()` have been made public in addition to\n  `Format()` for convenient use by command authors, but the values for\n  italic, bold, and bolditalic have not been. This is to preserve the\n  look and feel of commands that use `Emphasize()` and put the power to\n  control appearance into the hands of users instead of developers. \n\n* At one point the internal `map[string]*Command` index was private to\n  discourage tight coupling between commands. But it was decided that\n  this inflexibility came at too great a cost to potential needs of\n  command creators in the future who might want to inspect the Index\n  directly themselves without necessarily doing anything to is, say to\n  use some sort of prefix convention. `Has()` was kept as a convenience.\n  This does not change the fact that subcommands should be as independent\n  and uncoupled as possible. In the extreme case when subcommands need\n  to communicate they should use system environment variables as would\n  any other two commands normally.\n\n## How Does Completion Work?\n\nReading about [Bash Programmable Completion](https://duck.com/lite?kae=t\u0026q=Bash Programmable Completion) is probably a good idea.\n\nFor Bash all you need to add to your `~.bashrc` or `~/.bash_completion` file is the following:\n\n```bash\n\ncomplete -C mycmd mycmd\n\n```\n\nThis will cause the shell to run `mycmd` and set the `COMP_LINE`\nenvironment variable every time you tap the tab key once or twice. This\nallows *Complete Commander* to detect completion context and only print\nthe words that should be possible for the last word of the command when\nthe tab key was pressed.\n\nThe `cmd` package then sees completion context it resolves it by calling\nComplete(). See the package docs for more on the specific algorithm\nused, but generally it does the following:\n\n* Prints the output of any completion function found, or\n* Recursively looks up any matching Subcommand names and prints them\n\n## Machine Learning in Simple Terminal Commands?\n\nYep. Allowing a completion function allows incredible interesting\npossibilities with completion that uses full human language semantics\nrather than just prefixing the most likely candidates. Even a full\nmachine learning code module could be added allowing any possible\nspeech. Such considerations seem very absent from the HCI conversation\nregarding terminal command line usage.\n\n## Automatic (Builtin) Subcommands\n\nUnless specifically disabled with `OmitBuiltins` (although the size to\nadd these builtins is trivial), the following internal subcommands are\nadded to any executable that is created using the `cmd` package:\n\n* `help [\u003csubcmd\u003e]`\n* `usage`\n* `version`\n\nThese subcommands are so common they have become something of an\nunspoken standard for modern commands. \n\nSeveral other utility subcommands are also builtin for help integrating\nwith shell environments, producing documentation in other formats, and\nmore:\n\n```\n\n_authors       list names and authors\n_bash_complete print line to add for bash completion\n_builtins      list all cmd package builtins names and summaries\n_cmdversion    print the cmd package version\n_complete      force completion context\n_copyrights    list names and copyrights\n_descriptions  list names and descriptions\n_examples      list names and examples\n_gits          list names and git source repos\n_help_json     dump help documentation as JSON\n_index         list all names and summaries from cmd package index\n_issues        list names and issue reporting URLs\n_licenses      list names and licenses\n_names         list names, main first\n_summaries     list names and summaries\n_usages        list names and usages\n_versions      list names and versions\n\n```\n\n### Help Documentation\n\nHelp documentation is inspired by the look and design of UNIX `man`\npages so as to feel comfortable to those using such documentation for\ncommands for decades. It contains all the details for the given command\nor `\u003csubcmd\u003e`. Rather than dump all the documentation into a single\npage, however, details of subcommands can be displayed separately.\n\n### Usage Documentation\n\nUsage is when double-tab doesn't provide enough hints about how the\ncommand is to be used. Usage is meant to provide only minimal usage\noutput while 'help' provides the full detailed information for the\ncommand.  If an additional argument is provided the detailed help for\nthat specific subcommand will be provided. If the subcommand does not\nexist it will be ignored and the main help information shown instead.\n\n### Version Documentation\n\nHaving a `version` subcommand in particular is well-defined as being the\nplace to put all legal and authorship information in addition to just\nthe version. Such is required by most all free software and open-source\nlicenses.\n\n## TODO\n\nHere's some stuff we know I want to add but haven't made issues or time for yet:\n\n* `add:addmember` - aliases to allow `sl member add` but `addmember` in `Index`\n* `_help_md` - output a markdown file containing doc info\n* `_help_html` - output a standalone HTML5 document with doc info\n* `_help_http` - serves the `_help_html` document locally\n* internal paging when `less` not found (`go-pager`?)\n* assume use of the standard logger `log`, trap and beautify output\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/gitlab.com%2Foldrwxrob%2Fcmdtab","html_url":"https://awesome.ecosyste.ms/projects/gitlab.com%2Foldrwxrob%2Fcmdtab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/gitlab.com%2Foldrwxrob%2Fcmdtab/lists"}