peterbourgon / ff

Flags-first package for configuration

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Tab-completion

icio opened this issue Β· comments

I started building out some tab completion for the tailscale CLI based on v3 in tailscale/tailscale#11336. As mentioned, it's using the shell scripts that Cobra uses, so the implementation style is somewhat similar. I wonder whether you'd be interested in having a look over the implementation. If you can see a path to this being upstreamed into your project, I'd be interested to know what would be required.

Super interesting! I would love to have this kind of functionality, modulo cost/benefit considerations. Give me some time to review.

Hi @peterbourgon, any thoughts on this?

We're going to meet later today to speak about whether we want to merge this in. And if not, what changes we might want to make for it to be shippable.

I wonder what cost/benefit trade-offs came to your mind? One for me was whether we should package the completion scripts with the binary (which is what the PR currently does) or keep them a separate static/build-time artefact.

Sorry for the radio silence. I'm basically on board with this functionality. Can you show me a strawman PR?

edit: It looks like the best approach would be a separate package, ffcomplete seems as good a name as any. It's important to not depend on Cobra πŸ˜‡ so a copy-paste (with attribution) of the necessary code would be great.

Do you want the PR targeted at v4? I would guess so, and so I think I'll need to look into the parent flagset stuff and check whether that's supported. Are there any other fundamentally different parts to v4 that I might need to consider? I believe flag parsing is otherwise mostly unchanged, though I do have my eye on #124.

  • We currently hide tailscale completion __complete using HIDDEN: prefix on the description. Assuming you'd also like it to be hidden by default, any guidance on how you'd do that?

  • ff does not currently require the use of ff.Command, though ffcomplete depends on it. I suppose any users not using subcommands can just wrap their existing ff.Parse in a root := ff.Command{FlagSet: fs, Exec: ...}; ffcomplete.Inject(&root); root.Parse() without much trouble, if they want flag completion for a flags-only subcommand-less cli. Or I could change the injection trigger to be based on an environment variable, e.g. FFCOMPLETE=1 tailscale -- args... and calling ffcomplete.Inject(rootCmd) would actually respond with the events immediately, instead of just injecting the completion sub-command.

  • In tailscale/tailscale#11336 I have copied Cobra shell completion scripts and some constants that they depend on, retaining their license, in a ./tempfork/spf13/cobra directory. Would a simlar style work for you? I was thinking ./ffcomplete/cobra.go, with the license and notes copied in at the top.

v4

I suppose so, yes.

HIDDEN: ... ff.Command vs. ff.Parse

I think I need to better understand the constraints involved in completion before I can give useful feedback. Give me a bit πŸ™‡

ffcomplete/cobra.go

Ideally the file would be third_party.go or somesuch, but in general, yes πŸ‘

After looking at this in some detail, and based on the library as it exists right now, I don't think I can see a way to merge something that I'd be comfortable with supporting long-term. My apologies. I definitely want to support this feature, but I think it needs to wait until I have a proper solution to issues like #124, for example. For now, I think I'd recommend maintaining your fork. Sorry again!!

Hi @peterbourgon - I think it's very sensible you decide how to tackle #124 being continuing.

To implement the tab-completion in such a way that it could (1) send flag values to flag.FlagSet to really apply the flags, and (2) handle broken flags, it was necessary that I first separate the flag-args and arg-args, so that I can give the former to flag.FlagSet.Parse, and consume the latter as invalid flags, subcommands or other actual arguments: https://github.com/tailscale/tailscale/blob/icio/ffcli-cobra-complete/cmd/tailscale/cli/ffcomplete/internal/complete.go/#L64-L76.

I wonder if a similar split function could be given as an option to ff.Parse. The stdlib-compatible implementation would operate much the same as ffcomplete.splitFlagArgs while another implementation could continue looking for flags even after the first argument. Care would need to be taken to get the typo-handling semantics correct.

We'll start with our ffcomplete package. Feel free to reach out about our experience with it any time πŸ˜„