mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Improve child command usage info in help text
This commit is contained in:
@@ -64,6 +64,33 @@ namespace CliFx.Tests
|
|||||||
_output.WriteLine(stdOut.GetString());
|
_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]
|
[Fact]
|
||||||
public async Task Help_text_shows_all_valid_values_for_enum_arguments()
|
public async Task Help_text_shows_all_valid_values_for_enum_arguments()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -105,6 +105,54 @@ namespace CliFx.Domain
|
|||||||
WriteLine();
|
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(
|
private void WriteCommandUsage(
|
||||||
CommandSchema command,
|
CommandSchema command,
|
||||||
IReadOnlyList<CommandSchema> childCommands)
|
IReadOnlyList<CommandSchema> childCommands)
|
||||||
@@ -114,76 +162,28 @@ namespace CliFx.Domain
|
|||||||
|
|
||||||
WriteHeader("Usage");
|
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();
|
WriteVerticalMargin();
|
||||||
|
|
||||||
foreach (var childCommand in childCommands)
|
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)
|
private void WriteCommandParameters(CommandSchema command)
|
||||||
{
|
{
|
||||||
if (!command.Parameters.Any())
|
if (!command.Parameters.Any())
|
||||||
@@ -285,7 +285,7 @@ namespace CliFx.Domain
|
|||||||
if (!option.IsRequired)
|
if (!option.IsRequired)
|
||||||
{
|
{
|
||||||
var defaultValue = argumentDefaultValues.GetValueOrDefault(option);
|
var defaultValue = argumentDefaultValues.GetValueOrDefault(option);
|
||||||
var defaultValueFormatted = FormatDefaultValue(defaultValue);
|
var defaultValueFormatted = TryFormatDefaultValue(defaultValue);
|
||||||
if (defaultValueFormatted != null)
|
if (defaultValueFormatted != null)
|
||||||
{
|
{
|
||||||
Write($"Default: {defaultValueFormatted}.");
|
Write($"Default: {defaultValueFormatted}.");
|
||||||
@@ -377,7 +377,7 @@ namespace CliFx.Domain
|
|||||||
private static string FormatValidValues(IReadOnlyList<string> values) =>
|
private static string FormatValidValues(IReadOnlyList<string> values) =>
|
||||||
values.Select(v => v.Quote()).JoinToString(", ");
|
values.Select(v => v.Quote()).JoinToString(", ");
|
||||||
|
|
||||||
private static string? FormatDefaultValue(object? defaultValue)
|
private static string? TryFormatDefaultValue(object? defaultValue)
|
||||||
{
|
{
|
||||||
if (defaultValue == null)
|
if (defaultValue == null)
|
||||||
return null;
|
return null;
|
||||||
@@ -408,4 +408,4 @@ namespace CliFx.Domain
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,6 +178,12 @@ namespace CliFx
|
|||||||
{
|
{
|
||||||
var parameter = stackFrame.Parameters[i];
|
var parameter = stackFrame.Parameters[i];
|
||||||
|
|
||||||
|
// Separator
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
console.Error.Write(", ");
|
||||||
|
}
|
||||||
|
|
||||||
// "IConsole"
|
// "IConsole"
|
||||||
console.WithForegroundColor(ConsoleColor.Blue, () =>
|
console.WithForegroundColor(ConsoleColor.Blue, () =>
|
||||||
console.Error.Write(parameter.Type)
|
console.Error.Write(parameter.Type)
|
||||||
@@ -192,12 +198,6 @@ namespace CliFx
|
|||||||
console.Error.Write(parameter.Name)
|
console.Error.Write(parameter.Name)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separator
|
|
||||||
if (stackFrame.Parameters.Count > 1 && i < stackFrame.Parameters.Count - 1)
|
|
||||||
{
|
|
||||||
console.Error.Write(", ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.Error.Write(") ");
|
console.Error.Write(") ");
|
||||||
|
|||||||
Reference in New Issue
Block a user