Como personalizar a ajuda em aplicativos criados com a biblioteca System.Commandline

Você poderá personalizar a ajuda para um comando, opção ou argumento específico e adicionar ou substituir as seções de ajuda inteiras.

Os exemplos neste artigo funcionam com o seguinte aplicativo de linha de comando:

Esse código requer uma diretiva using:

using System.CommandLine;
var fileOption = new Option<FileInfo>(
    "--file",
    description: "The file to print out.",
    getDefaultValue: () => new FileInfo("scl.runtimeconfig.json"));
var lightModeOption = new Option<bool> (
    "--light-mode",
    description: "Determines whether the background color will be black or white");
var foregroundColorOption = new Option<ConsoleColor>(
    "--color",
    description: "Specifies the foreground color of console output",
    getDefaultValue: () => ConsoleColor.White);

var rootCommand = new RootCommand("Read a file")
{
    fileOption,
    lightModeOption,
    foregroundColorOption
};

rootCommand.SetHandler((file, lightMode, color) =>
    {
        Console.BackgroundColor = lightMode ? ConsoleColor.White: ConsoleColor.Black;
        Console.ForegroundColor = color;
        Console.WriteLine($"--file = {file?.FullName}");
        Console.WriteLine($"File contents:\n{file?.OpenText().ReadToEnd()}");
    },
    fileOption,
    lightModeOption,
    foregroundColorOption);

await rootCommand.InvokeAsync(args);

Sem personalização, é produzida a seguinte saída de ajuda:

Description:
  Read a file

Usage:
  scl [options]

Options:
  --file <file>                                               The file to print out. [default: scl.runtimeconfig.json]
  --light-mode                                                Determines whether the background color will be black or
                                                              white
  --color                                                     Specifies the foreground color of console output
  <Black|Blue|Cyan|DarkBlue|DarkCyan|DarkGray|DarkGreen|Dark  [default: White]
  Magenta|DarkRed|DarkYellow|Gray|Green|Magenta|Red|White|Ye
  llow>
  --version                                                   Show version information
  -?, -h, --help                                              Show help and usage information

Personalizar a ajuda para uma única opção ou argumento

Importante

Atualmente, System.CommandLine está em VERSÃO PRÉVIA, e essa documentação é para a versão 2.0 beta 4. Algumas informações estão relacionadas a produtos de pré-lançamento que poderão ser substancialmente modificados antes do lançamento. A Microsoft não oferece garantias, expressas ou implícitas, das informações aqui fornecidas.

Para personalizar o nome do argumento de uma opção, use a propriedade ArgumentHelpName da opção. E HelpBuilder.CustomizeSymbol permite que você personalize várias partes da saída de ajuda para um comando, opção ou argumento (Symbol é a classe base para todos os três tipos). Com CustomizeSymbol, é possível especificar:

  • O texto da primeira coluna.
  • O texto da segunda coluna.
  • A maneira como um valor padrão será descrito.

No aplicativo de exemplo, --light-mode é explicado adequadamente, mas as alterações nas descrições das opções --file e --color serão úteis. Para --file, o argumento pode ser identificado como um <FILEPATH> em vez de <file>. Para a opção --color é possível encurtar a lista de cores disponíveis na coluna um, e na coluna dois você pode adicionar um aviso de que algumas cores não funcionarão com alguns planos de fundo.

Para fazer essas alterações, exclua a linha await rootCommand.InvokeAsync(args); mostrada no código anterior e adicione em seu lugar o seguinte código:

fileOption.ArgumentHelpName = "FILEPATH";

var parser = new CommandLineBuilder(rootCommand)
        .UseDefaults()
        .UseHelp(ctx =>
        {
            ctx.HelpBuilder.CustomizeSymbol(foregroundColorOption,
                firstColumnText: "--color <Black, White, Red, or Yellow>",
                secondColumnText: "Specifies the foreground color. " +
                    "Choose a color that provides enough contrast " +
                    "with the background color. " + 
                    "For example, a yellow foreground can't be read " +
                    "against a light mode background.");
        })
        .Build();

parser.Invoke(args);

O código atualizado requer diretivas using adicionais:

using System.CommandLine.Builder;
using System.CommandLine.Help;
using System.CommandLine.Parsing;

O aplicativo agora produz a seguinte saída de ajuda:

Description:
  Read a file

Usage:
  scl [options]

Options:
  --file <FILEPATH>                       The file to print out. [default: CustomHelp.runtimeconfig.json]
  --light-mode                            Determines whether the background color will be black or white
  --color <Black, White, Red, or Yellow>  Specifies the foreground color. Choose a color that provides enough contrast
                                          with the background color. For example, a yellow foreground can't be read
                                          against a light mode background.
  --version                               Show version information
  -?, -h, --help                          Show help and usage information

Essa saída mostra que os parâmetros firstColumnText e secondColumnText dão suporte a quebra de linha na colunas.

Adicionar ou substituir seções de ajuda

É possível adicionar ou substituir uma seção inteira da saída de ajuda. Por exemplo, suponha que você queira adicionar alguma arte ASCII à seção de descrição usando o pacote NuGetSpectre.Console.

Altere o layout adicionando uma chamada HelpBuilder.CustomizeLayout no lambda passado ao método UseHelp:

fileOption.ArgumentHelpName = "FILEPATH";

var parser = new CommandLineBuilder(rootCommand)
        .UseDefaults()
        .UseHelp(ctx =>
        {
            ctx.HelpBuilder.CustomizeSymbol(foregroundColorOption,
                firstColumnText: "--color <Black, White, Red, or Yellow>",
                secondColumnText: "Specifies the foreground color. " +
                    "Choose a color that provides enough contrast " +
                    "with the background color. " +
                    "For example, a yellow foreground can't be read " +
                    "against a light mode background.");
            ctx.HelpBuilder.CustomizeLayout(
                _ =>
                    HelpBuilder.Default
                        .GetLayout()
                        .Skip(1) // Skip the default command description section.
                        .Prepend(
                            _ => Spectre.Console.AnsiConsole.Write(
                                new FigletText(rootCommand.Description!))
                ));
        })
        .Build();

await parser.InvokeAsync(args);

O código anterior requer uma diretiva using adicional:

using Spectre.Console;

A classe System.CommandLine.Help.HelpBuilder.Default permite reutilizar partes da funcionalidade de formatação de ajuda existente e redigi-las na ajuda personalizada.

A saída da ajuda agora tem esta aparência:

  ____                       _                __   _   _
 |  _ \    ___    __ _    __| |     __ _     / _| (_) | |   ___
 | |_) |  / _ \  / _` |  / _` |    / _` |   | |_  | | | |  / _ \
 |  _ <  |  __/ | (_| | | (_| |   | (_| |   |  _| | | | | |  __/
 |_| \_\  \___|  \__,_|  \__,_|    \__,_|   |_|   |_| |_|  \___|


Usage:
  scl [options]

Options:
  --file <FILEPATH>                       The file to print out. [default: CustomHelp.runtimeconfig.json]
  --light-mode                            Determines whether the background color will be black or white
  --color <Black, White, Red, or Yellow>  Specifies the foreground color. Choose a color that provides enough contrast
                                          with the background color. For example, a yellow foreground can't be read
                                          against a light mode background.
  --version                               Show version information
  -?, -h, --help                          Show help and usage information

Se você quiser usar apenas uma string como o texto da seção de substituição em vez de formatá-la com Spectre.Console, substitua o código Prepend no exemplo anterior pelo seguinte código:

.Prepend(
    _ => _.Output.WriteLine("**New command description section**")

Confira também

System.CommandLine overview