dotnet / command-line-api

Command line parsing, invocation, and rendering of terminal output.
https://github.com/dotnet/command-line-api/wiki
MIT License
3.37k stars 378 forks source link

Two-column text in option description in --help #1883

Open KalleOlaviNiemitalo opened 1 year ago

KalleOlaviNiemitalo commented 1 year ago

When --help describes an option that takes an enum-like argument, how can I format the possible values and their descriptions in two columns?

Like in DIR /? of cmd.exe:

  /T          Controls which time field displayed or used for sorting
  timefield   C  Creation
              A  Last Access
              W  Last Written

or in a private tool that queries DbProviderFactories.GetFactoryClasses():

  /Provider:PROVIDER        Select the ADO.NET provider.
                            PROVIDER must be one of:
    System.Data.Odbc          .Net Framework Data Provider for Odbc
    System.Data.OleDb         .Net Framework Data Provider for OleDb
    System.Data.OracleClient  .Net Framework Data Provider for Oracle
    System.Data.SqlClient     .Net Framework Data Provider for SqlServer

Such a feature almost exists for completions, as CompletionItem has both InsertText and Documentation properties, but HelpBuilder.Default.GetArgumentUsageLabel currently uses CompletionItem.Label only: https://github.com/dotnet/command-line-api/blob/209b724a3c843253d3071e8348c353b297b0b8b5/src/System.CommandLine/Help/HelpBuilder.Default.cs#L67-L71

KalleOlaviNiemitalo commented 1 year ago

In another app, I sort-of solved this by adding a custom help section with the values and descriptions, and referencing that from the description of the option. However, I'd also like to have a bit of one-column explanatory text in the custom section but I didn't find a way to indent and word-wrap that properly. I'd rather not try to implement the word-wrapping myself because it gets tricky with CJK:

KalleOlaviNiemitalo commented 1 year ago

dotnet new globaljson --help on .NET SDK 7.0.100:

Template options:
  --sdk-version <sdk-version>  The version of the .NET SDK to use.
                               Type: string
  --roll-forward <choice>      The roll-forward policy to use when selecting an
                               SDK version.
                               Type: choice
                                 patch          Uses the specified version. If
                               not found, rolls forward to the latest patch
                               level. If not found, fails. This value is the
                               legacy behavior from the earlier versions of the
                               SDK.
                                 feature        Uses the latest patch level for
                               the specified major, minor, and feature band. If
                               not found, rolls forward to the next higher
                               feature band within the same major/minor and
                               uses the latest patch level for that feature
                               band. If not found, fails.

In my opinion, it would look nicer if the \<choice> values were moved to the left column, but System.CommandLine does not have an easy API for that:

Template options:
  --sdk-version <sdk-version>  The version of the .NET SDK to use.
                               Type: string
  --roll-forward <choice>      The roll-forward policy to use when selecting an
                               SDK version.
                               Type: choice
    patch                        Uses the specified version. If not found, rolls
                               forward to the latest patch level. If not found,
                               fails. This value is the legacy behavior from
                               the earlier versions of the SDK.
    feature                      Uses the latest patch level for the specified
                               major, minor, and feature band. If not found,
                               rolls forward to the next higher feature band
                               within the same major/minor and uses the latest
                               patch level for that feature band. If not found,
                               fails.