Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tab-completion #132

Open
icio opened this issue Mar 8, 2024 · 7 comments
Open

Tab-completion #132

icio opened this issue Mar 8, 2024 · 7 comments

Comments

@icio
Copy link

icio commented Mar 8, 2024

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.

@peterbourgon
Copy link
Owner

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

@icio
Copy link
Author

icio commented Apr 4, 2024

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.

@peterbourgon
Copy link
Owner

peterbourgon commented Apr 4, 2024

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.

@icio
Copy link
Author

icio commented Apr 4, 2024

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 CLI tab-completion 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.

@peterbourgon
Copy link
Owner

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 👍

@peterbourgon
Copy link
Owner

peterbourgon commented Apr 13, 2024

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!!

@icio
Copy link
Author

icio commented Apr 17, 2024

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 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants