bkirwi / decline

A composable command-line parser for Scala.

Home Page:http://monovore.com/decline/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Idea: Add a zsh-completions output extension

jona7o opened this issue · comments

I think most of the mac users are using zsh instead of bash. zsh has this awesome plugin for auto completion. I think it could be a great extension for "decline" to autogenerate this zsh-autocompletion output from the Opts. I have seen this output in several CLIs like kubectl for kubernetes (source <(kubectl completion zsh)).

So my suggestion is to build an plugin for decline that generates the needed output for example with ./my-decline-cli completion zsh. Perhaps as "com.monovore" %% "decline-zsh-completions" % "1.3.0"?

Yeah, I think this would be a cool enhancement! Some quick thoughts:

  • You'd probably want to support bash too at some point. My understanding is that they're not so different, but I haven't looked into it much!
  • You could do a pretty reasonable version using just the information we already track... completing option names, etc. If you wanted to complete argument types like paths / enums / etc. we'd need to extend the AST and argument interface. I'm usually very hesitant to make core changes like this, but I'd consider it in this case.
  • It should be possible to expose this as a Command[_] => String function in a library somewhere. You could then use that to provide the interface you're suggesting... or folks using native packager could hook it into their build and generate completion files automatically maybe.

I'm unlikely to work on this myself, but I'd certainly be open to contributions of this shape! Labelling as such.

To add to bkirwi: When this will be done, I suggest to make it a general extension with support for multiple shells from the start (even if only one gets implemented initially).

One change that could make it easier to experiment with this and other enhancements may be providing access to some of the Opt ADT.

FYI I have a POC of this for zsh and I'm going to try and generalize it so it doesn't work with just my app. Current work in kubukoz/spotify-next@d3f0d92 (It needs to come from the decline package because Opts's subtypes are scoped like that, so when I have something more generalized I'll push it upstream)

Since it's come up in this thread, a quick note on why the Opts ADT is not public:

Opts implements Alternative, and is required to respect the Alternative laws, including some distribution laws. Usually, the way you ensure you meet the laws is to have the left-hand side generate the same AST as the right-hand side. Unfortunately, for the right distributivity law, the structure on the left turns out to be both very common and substantially more efficient at parse time than the one on the right, which means it's really important to have different internal representations for them. So we basically can't expose the AST without breaking the Alternative laws or killing performance. (And we have test that ensure that the observable / public behaviour of both representations is the same, aside from performance anyways - they parse the same inputs to the same outputs, give identical errors on parse failures, etc.)

Would it be possible to expose a method to emit a public ADT (possibly, but not necessarily, one of the two you mentioned)?

That way the internal performance optimizations aren't perturbed, and nobody has to pay for the cost of the more expensive representation unless they need it to do something unusual like generating completions or prototyping functionality (one I've wanted to explore is generating linked markdown readme files, which would greatly benefit from being able to traverse the subcommand tree).

Would it be possible to expose a method to emit a public ADT (possibly, but not necessarily, one of the two you mentioned)?

One idea, which came up in the context of #138, would be to capture more structural information in the Help object. Right now Help is just a bag of Strings, but if we preserved more of the original structure, it could be handy for some of these programmatic uses you have in mind, and adding it to Help means we're not adding another top-level concept to the API.

(In that context, we could satisfy the distributive law by converting the "distributed" representation on the right-hand side to the undistributed form on the left. That's not an option for the original AST because we can't check function equality, but in the context of Help it ought to work.)