dotnet / dotnet/command-line-api

Shell Completions

Open
#2,425 3 comments 0 reactions 0 assignees View on GitHub
Area-Completions enhancement
Dominant language
C#
Stars
3.7k
Forks
428
PR merge metrics
No merged PRs in 30d

Description

I've just caught up on [the last community standup](https://www.youtube.com/watch?v=SzpFCVg3JbA) and was interested to hear the direction for completions, and wanted to share how I'm solving this today.

First off, I love the _idea_ of the automagic self-describing directives based completions today (dotnet-suggest), however as was mentioned this is slow (although very workable when AOTing). I abandoned this approach in the end mostly because:
* implementation was very buggy, to the point it wouldn't work in many scenarios
* shell support was lacking
* Fish allows for a better experience than just "here is are the valid tokens you can use here", it can show them in a grid with descriptions, which again wasn't supported with the dotnet-suggest approach.

So what I do for my internal tool (can't share the code sorry) is have a separate file that has the grammar of the command line in, and using a tool ([complgen](https://github.com/adaszko/complgen)) to produce the per-shell scripts. I have the outputs of these then embedded my tool, so I can say `jaz completions fish` (the tool is named jaz) and it will output the `fish` shell snipped. This plays well with eco-system tools like homebrew ([example](https://github.com/Homebrew/homebrew-core/blob/a0db09dc6d6d7188ead73f5aea85434b1979fbbe/Formula/g/gh.rb#L38)).

Here is what my usage grammar looks like:
```
jaz []... [];
jaz [];

::= info "About jaz"
| clear "Remove credentials from your profile" []
| doctor "Perform checkup to diagnose any issues"
| logout "Logout of SSO sessions"
| whoami "Get the caller ID of the current session" [] []
| update-metadata "Update the environment metadata"
| list-profiles "List session profiles"
| generate-profiles "Generate SSO profiles"
;

::= --sso-session "The AWS SSO session to use"
| --account-id "The AWS account ID to use"
| --role "The AWS role to use"
| --region "The AWS region to use"
|
| --version "Show version information"
;

::= --show-role-arn "Show the role ARN";

::= --profile "The AWS profile to use" ;
::= --profile "The AWS profile to use" ;

::= {{{ jaz list-profiles --include-all }}};
::= {{{ jaz list-profiles }}};

::= (-h | --help) "Show help and usage information";
```

You can see this supports calling back into itself for completions (see ``), this is awesome because I get nice completions across all shells, and it's fast because it's static, but I get the dynamic behaviours when I want them.

I'm not suggesting that this _exact_ tool/grammar be selected as the approach, but as a general pattern I think this is really powerful yet simple for developers.

image

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.