dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.65k stars 1.05k forks source link

Automatically register and improve CLI completions for the dotnet CLI #42397

Open baronfel opened 1 month ago

baronfel commented 1 month ago

Is your feature request related to a problem? Please describe.

The dotnet CLI today has pervasive completion support for commands, options, and arguments. However, our telemetry data suggests that very few users do the configuration required to enable completion support in their shells. In the recent CLI usability study, the top-requested item across all users regardless of experience levels, IDE, or OS was automatic registration of CLI completions and more pervasive and informative completions across the CLI commands (and commands that feel like they are part of the dotnet CLI).

Describe the solution you'd like

The dotnet CLI should

This will bring the CLI in-line with patterns used by other widely-used CLI tools, vastly improve the user experience of the CLI, and improve the performance of completions all-up.

Reduce the work required to register tab completions for shells

Today, users configure completion for their shells by manually inserting shell-specific completion scripts into their shell-specific profile scripts - scripts that shells either explicitly or implicitly by convention load when starting or requesting completions for a command. These scripts are 'frozen' in time and users have to remember to update them if CLI capabilities change.

Instead, we should provide a two new commands to make this process easier:

We should also extend the first-run experience to prompt the user for permission to perform the register command on first-run, but only if the current shell is interactive (meaning a user is at the keyboard). There is an existing go/bash convention for this: COMP_INSTALL=1 and COMP_UNINSTALL=1 environment variables signal willingness to automatically configure and remove completions for programs.

Invest in statically-generated completion scripts

With the previous step done, we now have a way to solve the 'out of date completions script' problem. User shells will automatically generate and load completions scripts on each load, so the dotnet CLI can begin investments in generating better scripts.

The first iteration of the dotnet completions script [<SHELL>] command would only emit the 'dynamic' completion script that we ask users to set up today. However, subsequent iterations should generate scripts that are more static - meaning they generation completions without having to call dotnet complete, instead relying on the features of the different shell completion systems to prevent the need to spawn dotnet processes (with all the overhead that entails) and enable better shell-completion-system integration and performance overall.

This can be done opportunistically and at different levels for different shells, because many shells have varying degrees of sophistication here.

Expand the information provided from completions

Today, all completions for the dotnet CLI provide only the completion value. The underlying System.CommandLine completions subsystem allows for providing more details, like descriptions or extended help for a given completion item. The completions systems for different shells are often capable of rendering this information inline when completions are requested, but it has been hard to provide that information in a way that didn't invalidate the existing shell script shims that users have added to their profiles.

With dotnet completions register [<$SHELL>] all of these blockers are removed and we can create new completion commands to provide whatever level of context is required. At minimum we should provide descriptions and integrate them into the statically-generated completions from the previous section.

KalleOlaviNiemitalo commented 1 month ago

How would statically-generated completion scripts work with global.json files in different directories specifying different versions of .NET SDK; would you make the shell parse JSON and choose the appropriate completion script?

baronfel commented 1 month ago

That's a potential problem, but per telemetry the vast majority of .NET projects do not use global.json at all so it's not a scenario I'm incredibly worried about. In many ways the source (dotnet completions generate bash) pattern in your $PROFILE actually helps in multi-version scenarios - if you have one shell per project then the dotnet selected by the global.json at shell creation would generate the completions, so you get a greater likelihood of alignment there.

For more complex scenarios than that I don't think we'd spend much time trying to handle that - the CLI itself has a pretty high compat bar for commands/flags/etc so completions from older versions should still be correct/relevant.