Skip to content

Shell completions#3481

Merged
itowlson merged 1 commit intospinframework:mainfrom
itowlson:completions-5-is-it-5-ive-lost-track
May 1, 2026
Merged

Shell completions#3481
itowlson merged 1 commit intospinframework:mainfrom
itowlson:completions-5-is-it-5-ive-lost-track

Conversation

@itowlson
Copy link
Copy Markdown
Collaborator

FIFTH TIME'S THE CHARM PLEASE LET FIFTH TIME BE THE CHARM

Okay this is still kinda WIP. I need to do a pass for other things that would benefit from completions other than "uh filename", and I need to figure out how to get any completions working at all with the new spin up because oof. It also needs testing on zsh at minimum. But in the meantime, tyre kicking fans:

HOW IT WORKS IF IT DOES WORK WHICH IS YET TO BE CONFIRMED

The idea is that spin maintenance generate-completions generates a bash script, and that generated bash script calls back into Spin to get the completions. That's why Spin now needs to check "am I being called for completions" and divert processing before doing normal command parsing. I am not entirely easy about this but it is what it is. Open to better thoughts.

HOW TO USE IT

IMPORTANT: the spin binary must be on your PATH (as far as I can tell)

  1. Run spin maintenance generate-completions with the COMPLETE environment variable set to your shell. This will produce a completion script. E.g. COMPLETE=bash spin maintenance generate-completions >completions.sh
  2. source the completion script e.g. source ./completions.sh

If this works reliably, then we can do what clap-complete describes - at startup, pipe the output script directly to source. In this model, to install the completions is:

echo "source <(COMPLETE=bash spin maintenance generate-completions)" >> ~/.bashrc

(But obviously, "this works reliably" is vanishingly unlikely, so I'll probably see y'all back here in a year's time.)

@itowlson itowlson changed the title Shall completions Shell completions Apr 28, 2026
@itowlson
Copy link
Copy Markdown
Collaborator Author

I think this is now working on my machine. We have custom completions for template names (in spin new -t), components (in spin build/up -c), profiles, and plugins (in spin plugin install/uninstall/upgrade).

Two hacks and one red herring were harmed in the making of this PR, but otherwise it has been surprisingly torment-free.

@itowlson
Copy link
Copy Markdown
Collaborator Author

Oh I suppose I should do the template management commands but those seem to happen mostly in the installer those days so my motivation is not skyrocketing.

Copy link
Copy Markdown
Contributor

@vdice vdice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tire kicker reporting in for duty. This appears to work a charm with my setup (Mac, bash). Very handy!

A few minor items:

  • When the only option is --help, repeated Tabs will just keep appending. (eg spin plugins update --help --help --help --help --help --help --help --help --help --help --help --help --help --help --help --help) (Clearly I need help.)

    Any chance when there is only one option (likely, --help as above), auto-complete won't attempt to append after the first injection? Or it could be this is just the case with completions in general; I admit I haven't cross-referenced others. (If it might be addressable, clearly a follow-up candidate!)

  • For the new generate-completions sub-command, I'm seeing the following:

    $ spin maintenance generate-completions --help
    Generate shell completions
    
    Usage: spin maintenance generate-completions
    
    Options:
      -h, --help  Print help
    

    Any chance this help output can include that a COMPLETE=<shell> is required to do anything meaningful? And/or perhaps update the command itself to error out if no COMPLETE var is present (currently it appears to no-op).

Otherwise, a few vision-casting Qs:

  1. Any thoughts on attempting an out-of-the-box experience with these completions? Not sure if that would mean bundling the supported shell completion scripts in with the binary, fetching them at install (script) time or what.

  2. Is there a vision for plugins to offer completion scripts? Thinking eg cloud or aka deploy plugins but presumably could/would apply to all. Do they somehow need to be added to the main/core Spin completion script or would they just be add'l scripts for the user to source?

@itowlson
Copy link
Copy Markdown
Collaborator Author

Thanks so much for trying this out, Vaughn. It's very reassuring!

When the only option is --help, repeated Tabs will just keep appending. (eg spin plugins update --help --help --help

Hmm, that might be a clap-complete bug, although I don't see one listed.

Any chance this help output can include that a COMPLETE= is required to do anything meaningful?

Good catch - let me see if I can come up with something. The maintenance command is hidden so users hopefully won't stumble across it outside of "do this incantation" docs, but I agree it's better to have something than nothing.

Any thoughts on attempting an out-of-the-box experience with these completions?

Not sure yet. We could in theory run the echo ... >>.bashrc in the install script, but 1. I am not sure about the shell detection thing, and 2. Spin is not on PATH at that point so who knows what it would do.

I imagine we could integrate it into the Homebrew package, although I dunno if those are allowed to modify the profile.

(It would not mean bundling the generated shell scripts. The idea seems to be that you run source <(COMPLETE=bash spin maintenance generate-completions) without the shell script ever needing to hit the disk. So it is that literal source command that you add to bashrc.)

Is there a vision for plugins to offer completion scripts?

Would you settle for a swirling mass of fog with vague hints of things that might be the shapes of visions barely perceptible within it? Shell completions go only off the program name, which is always spin, so Spin would have to be the first point of call. I think we can recognise that we are in the plugin invocation case and do a custom completion that calls to... something. But I have no idea yet how this would actually work!

@itowlson itowlson force-pushed the completions-5-is-it-5-ive-lost-track branch from 577cc46 to 2d3c781 Compare April 29, 2026 00:22
@itowlson
Copy link
Copy Markdown
Collaborator Author

Tried it on Mac/zsh and it seems to work although not as snappy as I'd expect.

But maybe we should ship it with the caveat that it may not be perfect but hey it's probably less worse than no completions at all and anyway if you do prefer nothing to imperfect then just don't install the completions?

@fibonacci1729 @vdice

@itowlson itowlson marked this pull request as ready for review April 29, 2026 03:47
@itowlson itowlson force-pushed the completions-5-is-it-5-ive-lost-track branch 2 times, most recently from 3b6c5eb to a18ad3c Compare April 29, 2026 03:49
@itowlson itowlson mentioned this pull request Apr 29, 2026
Copy link
Copy Markdown
Contributor

@vdice vdice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely agree that it would be great to get this functionality in now and then iterate as needed from there. Might give @fibonacci1729 a chance to review finer points of the implementation; otherwise I can vouch the feature works nicely!

@itowlson itowlson requested a review from fibonacci1729 April 29, 2026 19:29

impl GenerateCompletions {
async fn run() -> anyhow::Result<()> {
if std::env::var_os("COMPLETE").is_none() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we re-use the is_completion_request func from lib.rs? Right now the emptiness check between these two are inconsistent.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's intentional that I didn't reuse is_completion_request - that function may well evolve if we find there are false positives. Whereas the check here is basically just to give a good error message if someone decides to type it into their terminal rather than following instructions, and is intentionally as minimal as possible so as not to give false negatives.

But I should add comments to explain that reasoning because it is highly non-obvious (and may, of course, be entirely wrong).

Comment thread src/commands/maintenance.rs Outdated
next_display_order = None,
)]
#[expect(clippy::large_enum_variant)]
enum TheRealSpinApp {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a favor to future us, could you leave a comment as to why this is needed?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like:

// We use `UpCommandInner` here because `UpCommand` is intentionally lossy to handle trigger
specific flags and the completion generator require the lossless command.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but what has future us done for me lately

Copy link
Copy Markdown
Collaborator

@fibonacci1729 fibonacci1729 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great if we could figure out how to eliminate TheRealSpinApp but that can be a follow up.

@itowlson itowlson force-pushed the completions-5-is-it-5-ive-lost-track branch from a18ad3c to cbf4b3c Compare April 30, 2026 23:38
@itowlson
Copy link
Copy Markdown
Collaborator Author

itowlson commented Apr 30, 2026

It would be great if we could figure out how to eliminate TheRealSpinApp

Ha, that is almost exactly what I wrote in my comment explaining why this stain on our otherwise beautiful program had to exist.

The only way I can think of offhand is a type parameter SpinApp<U> and that feels just as ghastly although possibly more maintainable. But I agree we should not block on this.

EDIT: BRIAN FIGURED OUT A WAY. Noting this here to give credit where credit is due.

(Also, it occurs to me that spin maintenance generate-reference has to do some nasty special-casing of spin up and I'm wondering if we can solve two problems in one. But that's not a requirement, just a thing to explore.)

This was referenced May 1, 2026
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
@itowlson itowlson force-pushed the completions-5-is-it-5-ive-lost-track branch from cbf4b3c to ad41439 Compare May 1, 2026 00:25
@itowlson itowlson enabled auto-merge May 1, 2026 00:32
@itowlson itowlson merged commit 1b4feaf into spinframework:main May 1, 2026
17 checks passed
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

Successfully merging this pull request may close these issues.

3 participants