Add support for URL completions in buf curl#4402
Add support for URL completions in buf curl#4402stefanvanburen wants to merge 9 commits intomainfrom
buf curl#4402Conversation
First mentioned in #2044, which is long something I've wanted. This adds support for completing URLs based on the available RPCs, which either comes from the existing `--schema` flag or gRPC reflection. The completion itself works somewhat similar to LSP completion, in that it attempts to complete as far as it can before giving the user an option between the remaining values to disambiguate. It will complete up to the entire service URL, and then provide completions for RPCs within the service (if there are multiple). This requires one fix upstream in app-go so that subcommands that define `ModifyCobra` actually run: bufbuild/app-go#5. We'll want to land upstream to `main` before landing this. Open to suggestions on the completion UX. It feels fairly natural to me currently, but I'm sure there are edge cases. Future work here could include better completions for `--schema` values, either using local directories or BSR modules, and completions for `--data` values (if we know the schema and the specific RPC targeted by the URL, we know the shape of the JSON for the `--data` flag). Also, following this pattern of using ModifyCobra, other commands could be made to have better contextual completion. Also fixes the buf curl help examples to have consistent indentation. Resolves #2044.
|
The latest Buf updates on your PR. Results from workflow Buf CI / buf (pull_request).
|
|
using the following vhs tape: Output curl-completion.gif
Set Shell fish
Set FontSize 14
Set Width 900
Set Height 400
Set Padding 16
Set Theme "Catppuccin Mocha"
Env PATH "/Users/stefanvanburen/.cache/buf/Darwin/arm64/gobin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
Hide
Sleep 1s
Type "source ~/.config/fish/completions/buf.fish"
Enter
Sleep 200ms
Show
Ctrl+L
Sleep 200ms
# --protocol flag: static completions (connect, grpc, grpcweb)
Type "buf curl --protocol "
Sleep 500ms
Tab
Sleep 2s
Ctrl+C
Sleep 1s
# --reflect-protocol flag: static completions (grpc-v1, grpc-v1alpha)
Type "buf curl --reflect-protocol "
Sleep 500ms
Tab
Sleep 2s
Ctrl+C
Sleep 1s
# URL via reflection — Tab 1: unambiguous prefix collapses to full service name
Type "buf curl https://demo.connectrpc.com/"
Sleep 500ms
Tab
Sleep 4s
# Tab 2: method completions (Converse, Introduce, Say)
Tab
Sleep 2s
# Select a method by typing a prefix and completing
Type "Say"
Tab
Sleep 2s
Ctrl+C
Sleep 1s
# Same via --schema (no running server needed) — Tab 1: service name
Type "buf curl --schema buf.build/connectrpc/eliza https://demo.connectrpc.com/"
Sleep 500ms
Tab
Sleep 4s
# Tab 2: method completions
Tab
Sleep 2s
Ctrl+C |
via `go get buf.build/go/app@main`.
We've added descriptions to the URL completions about _where_ the completion is coming from (the local module, the schema flag, or gRPC reflection), which should help users understand better why they're getting completions. We've also added error handling, for now targeting issues with the `--schema` parameter.
|
Quick UX update: in 20a16ea I added descriptions to the RPC completions about where the schema is coming from (local module, reflection, --schema flag), and also added some basic error handling. Updated gif: via this tape: Output curl-completion.gif
Set Shell fish
Set FontSize 14
Set Width 900
Set Height 400
Set Padding 16
Set Theme "Catppuccin Mocha"
Env PATH "/Users/stefanvanburen/.cache/buf/Darwin/arm64/gobin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
Hide
Sleep 1s
Type "source ~/.config/fish/completions/buf.fish"
Enter
Sleep 200ms
Show
Ctrl+L
Sleep 200ms
# --protocol flag: static completions (connect, grpc, grpcweb)
Type "buf curl --protocol "
Sleep 500ms
Tab
Sleep 2s
Ctrl+C
Sleep 1s
# --reflect-protocol flag: static completions (grpc-v1, grpc-v1alpha)
Type "buf curl --reflect-protocol "
Sleep 500ms
Tab
Sleep 2s
Ctrl+C
Sleep 1s
# URL via reflection — Tab 1: unambiguous prefix collapses to full service name
Type "buf curl https://demo.connectrpc.com/"
Sleep 500ms
Tab
Sleep 4s
# Tab 2: method completions (Converse, Introduce, Say)
Tab
Sleep 2s
# Select a method by typing a prefix and completing
Type "Say"
Tab
Sleep 2s
Ctrl+C
Sleep 1s
# Same via --schema (no running server needed) — Tab 1: service name
Type "buf curl --schema buf.build/connectrpc/eliza https://demo.connectrpc.com/"
Sleep 500ms
Tab
Sleep 4s
# Tab 2: method completions
Tab
Sleep 2s
Ctrl+C |
Similar to standard, now that we're off an official release.
This takes a pass at improving the shell completions provided by `buf` by wiring into cobra's completion system. This: * Adds completions for "enum" based flags (provides the potential values; disables flags & generally orders from most-used to least-used) * Adds directory-only completions for `--output` in generate and export * Adds file-extension completions for `--template` (yaml extensions) and `--binary` (wasm) * Disables file completions for free-form string flags like `--label`, `--source-control-url`, `--header`, etc. where it's unlikely that a user would want to supply a local file name Implementation-wise, this is all wired up under ModifyCobra, so we need the latest version of app-go which fixes that working on subcommands. It generally uses `errors.Join` just to simplify the error cases, which should not occur. Shared completions are in `private/buf/bufcli/completions.go`. Vaguely related to #4402, which is aiming to add more dynamic completions. In that PR, I mentioned further improvements to completions for more dynamic situations, but this should shore up the "base case" of the relatively straightforward static-ish completions. Ref: https://cobra.dev/docs/how-to-guides/shell-completion/
This takes a pass at improving the shell completions provided by `buf` by wiring into cobra's completion system. This: * Adds completions for "enum" based flags (provides the potential values; disables flags & generally orders from most-used to least-used) * Adds directory-only completions for `--output` in generate and export * Adds file-extension completions for `--template` (yaml extensions) and `--binary` (wasm) * Disables file completions for free-form string flags like `--label`, `--source-control-url`, `--header`, etc. where it's unlikely that a user would want to supply a local file name Implementation-wise, this is all wired up under ModifyCobra, so we need the latest version of app-go which fixes that working on subcommands. It generally uses `errors.Join` just to simplify the error cases, which should not occur. Shared completions are in `private/buf/bufcli/completions.go`. Vaguely related to #4402, which is aiming to add more dynamic completions. In that PR, I mentioned further improvements to completions for more dynamic situations, but this should shore up the "base case" of the relatively straightforward static-ish completions. Ref: https://cobra.dev/docs/how-to-guides/shell-completion/
And pass through more of the flags, so that the TLS flags will impact the client used.
doriable
left a comment
There was a problem hiding this comment.
Overall, this is reasonable, and thank you for updating the cobra helpers, etc. I do think that this should work off the existing resolvers, so I suggested a refactor, but let me know if the suggestion doesn't work ^^"
|
|
||
| // 2. Live server reflection. | ||
| isSecure := parsed.Scheme == "https" | ||
| if httpClient, ok := makeCompletionHTTPClient(cmd, isSecure); ok { |
There was a problem hiding this comment.
Would we be instantiating a new httpClient each time we are resolving a completion? When using reflection to resolve schemas at the top-level, we reuse the same transport as the invoker.
There was a problem hiding this comment.
yes, we'd be instantiating a new client each time the user presses tab (or whatever their keyboard shortcut for invoking completions is)?
| // 1. --schema flag (explicit schemas provided by the user) | ||
| // 2. Live server reflection against the URL being completed | ||
| // 3. The buf module found by walking up from the current working directory |
There was a problem hiding this comment.
So this pattern makes sense to me, and mirrors the way buf curl works in general, but I wonder if we can leverage and refactor the existing code paths to support this.
Basically, the command does some validation upfront, sets up the URL, and then sets up the client + resolvers for the schema. I wonder if we can refactor a little bit so that we set up the resolvers for the schema after the validation, and then use that for completions for the URL.
That way, we have a single, consistent code path, and also uses the same container, client, transport, etc.
There was a problem hiding this comment.
added in c48c0a6 if I'm understanding properly!


First mentioned in #2044, which is long something I've wanted. This adds support for completing URLs based on the available RPCs, which either comes from the existing
--schemaflag or gRPC reflection.The completion itself works somewhat similar to LSP completion, in that it attempts to complete as far as it can before giving the user an option between the remaining values to disambiguate. It will complete up to the entire service URL, and then provide completions for RPCs within the service (if there are multiple).
This requires one fix upstream in app-go so that subcommands that define
ModifyCobraactually run: bufbuild/app-go#5. We'll want to land upstream tomainbefore landing this.Open to suggestions on the completion UX. It feels fairly natural to me currently, but I'm sure there are edge cases.
Future work here could include better completions for
--schemavalues, either using local directories or BSR modules, and completions for--datavalues (if we know the schema and the specific RPC targeted by the URL, we know the shape of the JSON for the--dataflag). Also, following this pattern of using ModifyCobra, other commands could be made to have better contextual completion.Also fixes the buf curl help examples to have consistent indentation.
Resolves #2044.