google / subcommands

Go subcommand library.
Apache License 2.0
749 stars 48 forks source link

Programmatically Generating Autocompletion Hints #42

Open matttproud opened 1 year ago

matttproud commented 1 year ago

I'm a big fan of subcommands for its simplicity, so I'm curious about the best way to go about adding support for this feature in the project without ruining the simplicity. The basic idea is I would like to create a generator that can walk the registered commands and their flags and generate bash (1, 2) and zsh autocompletion hints for any given binary programmatically.

I see there being three main ways this could be done:

  1. Contribute a subcommands.Command implementation directly to subcommands similar to subcommands.FlagsCommand that emits the necessary bash magic. This has the advantage that the API of subcommands can remain generally the same while avoiding exporting additional state about the implementation. And it introduces a potential disadvantage of tightly coupling bash and zsh shenanigans into an otherwise spartan project.
  2. Export the needed data by expanding the surface of (*subcommands.Commander).VisitCommands such that it includes the *flag.FlagSet and importance metadata about all registered commands. This would be needed to meaningfully attribute command line flags per subcommand in an autocompletion generator. The advantage is that a bash and zsh generator could be built outside of subcommands. The disadvantage is that it exposes some internal implementation details that are — otherwise — innocuous while likely breaking API compatibility with existing users of (*subcommands.Commander).VisitCommands if the signature changes. Alternatively a new visiting method could be introduced that exposes this data while keeping the original ones as-is.
  3. For completeness: there is a hybrid of nos. 1 and 2, wherein the needed exposition capabilities of no. 2 could be exposed through an internal package. Then, autocompletion hints code could be provided in a contrib directory rooted from the same parent directory that the internal one lives under. This has the advantage of keeping the public API parsimonious with the disadvantage of a contrib directory hierarchy. I'm not crazy about this option.

What do you folks think? Any preferences between the three, or am I overlooking a better alternative? I lean more toward no. 2.