bkirwi / decline

A composable command-line parser for Scala.
http://monovore.com/decline/
Apache License 2.0
646 stars 71 forks source link

Idea: Add a zsh-completions output extension #250

Open jona7o opened 3 years ago

jona7o commented 3 years ago

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"?

bkirwi commented 3 years ago

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

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

ziggystar commented 3 years ago

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).

morgen-peschke commented 3 years ago

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

kubukoz commented 2 years ago

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 https://github.com/kubukoz/spotify-next/commit/d3f0d92316c4f53d7bd8373253734969e9678564 (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)

bkirwi commented 2 years ago

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.)

morgen-peschke commented 2 years ago

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).

bkirwi commented 2 years ago

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.)