Improve child command usage info in help text

This commit is contained in:
Tyrrrz
2020-10-23 23:36:36 +03:00
parent 9557d386e2
commit 3abdfb1acf
3 changed files with 100 additions and 73 deletions

View File

@@ -64,6 +64,33 @@ namespace CliFx.Tests
_output.WriteLine(stdOut.GetString());
}
[Fact]
public async Task Help_text_shows_usage_format_which_lists_available_sub_commands()
{
// Arrange
var (console, stdOut, _) = VirtualConsole.CreateBuffered();
var application = new CliApplicationBuilder()
.AddCommand<DefaultCommand>()
.AddCommand<NamedCommand>()
.AddCommand<NamedSubCommand>()
.UseConsole(console)
.Build();
// Act
var exitCode = await application.RunAsync(new[] {"--help"});
// Assert
exitCode.Should().Be(0);
stdOut.GetString().Should().ContainAll(
"Usage",
"... named",
"... named sub"
);
_output.WriteLine(stdOut.GetString());
}
[Fact]
public async Task Help_text_shows_all_valid_values_for_enum_arguments()
{

View File

@@ -105,6 +105,54 @@ namespace CliFx.Domain
WriteLine();
}
private void WriteCommandUsageLineItem(CommandSchema command, bool showChildCommandsPlaceholder)
{
// Command name
if (!string.IsNullOrWhiteSpace(command.Name))
{
Write(ConsoleColor.Cyan, command.Name);
Write(' ');
}
// Child command placeholder
if (showChildCommandsPlaceholder)
{
Write(ConsoleColor.Cyan, "[command]");
Write(' ');
}
// Parameters
foreach (var parameter in command.Parameters)
{
Write(parameter.IsScalar
? $"<{parameter.Name}>"
: $"<{parameter.Name}...>"
);
Write(' ');
}
// Required options
foreach (var option in command.Options.Where(o => o.IsRequired))
{
Write(ConsoleColor.White, !string.IsNullOrWhiteSpace(option.Name)
? $"--{option.Name}"
: $"-{option.ShortName}"
);
Write(' ');
Write(option.IsScalar
? "<value>"
: "<values...>"
);
Write(' ');
}
// Options placeholder
Write(ConsoleColor.White, "[options]");
WriteLine();
}
private void WriteCommandUsage(
CommandSchema command,
IReadOnlyList<CommandSchema> childCommands)
@@ -114,74 +162,26 @@ namespace CliFx.Domain
WriteHeader("Usage");
WriteCommandUsageLineItem(command, childCommands.Count > 0);
// Exe name
WriteHorizontalMargin();
Write(_metadata.ExecutableName);
Write(' ');
if (!IsEmpty)
// Current command usage
WriteCommandUsageLineItem(command, childCommands.Any());
// Sub commands usage
if (childCommands.Any())
{
WriteVerticalMargin();
foreach (var childCommand in childCommands)
{
WriteCommandUsageLineItem(childCommand, compactCommand: false, size: 4);
WriteHorizontalMargin();
Write("... ");
WriteCommandUsageLineItem(childCommand, false);
}
}
private void WriteCommandUsageLineItem(
CommandSchema command,
bool compactCommand = true,
int size = 2)
{
WriteHorizontalMargin(size);
if (compactCommand)
{
// Exe name
Write(_metadata.ExecutableName);
Write(' ');
}
// Command name
if (!string.IsNullOrWhiteSpace(command.Name))
{
// this is fragile, because we rely that subcommand name consists
// of all required tokens
Write(ConsoleColor.Cyan, command.Name);
}
// Child command placeholder
if (compactCommand)
{
Write(' ');
Write(ConsoleColor.Cyan, "[command]");
}
// Parameters
foreach (var parameter in command.Parameters)
{
Write(' ');
Write(parameter.IsScalar
? $"<{parameter.Name}>"
: $"<{parameter.Name}...>"
);
}
// Required options
foreach (var option in command.Options.Where(o => o.IsRequired))
{
Write(' ');
Write(ConsoleColor.White, !string.IsNullOrWhiteSpace(option.Name)
? $"--{option.Name}"
: $"-{option.ShortName}"
);
Write(' ');
Write(option.IsScalar
? "<value>"
: "<values...>"
);
}
// Options placeholder
Write(' ');
Write(ConsoleColor.White, "[options]");
WriteLine();
}
private void WriteCommandParameters(CommandSchema command)
@@ -285,7 +285,7 @@ namespace CliFx.Domain
if (!option.IsRequired)
{
var defaultValue = argumentDefaultValues.GetValueOrDefault(option);
var defaultValueFormatted = FormatDefaultValue(defaultValue);
var defaultValueFormatted = TryFormatDefaultValue(defaultValue);
if (defaultValueFormatted != null)
{
Write($"Default: {defaultValueFormatted}.");
@@ -377,7 +377,7 @@ namespace CliFx.Domain
private static string FormatValidValues(IReadOnlyList<string> values) =>
values.Select(v => v.Quote()).JoinToString(", ");
private static string? FormatDefaultValue(object? defaultValue)
private static string? TryFormatDefaultValue(object? defaultValue)
{
if (defaultValue == null)
return null;

View File

@@ -178,6 +178,12 @@ namespace CliFx
{
var parameter = stackFrame.Parameters[i];
// Separator
if (i > 0)
{
console.Error.Write(", ");
}
// "IConsole"
console.WithForegroundColor(ConsoleColor.Blue, () =>
console.Error.Write(parameter.Type)
@@ -192,12 +198,6 @@ namespace CliFx
console.Error.Write(parameter.Name)
);
}
// Separator
if (stackFrame.Parameters.Count > 1 && i < stackFrame.Parameters.Count - 1)
{
console.Error.Write(", ");
}
}
console.Error.Write(") ");