Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 39 additions & 7 deletions src/System.CommandLine.Tests/Help/HelpBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ public void Command_arguments_show_argument_name_in_first_column()
new Argument<bool>("boolArgument") { Description = "Some value" },
new Argument<int>("intArgument") { Description = "Another value" },
};

var helpBuilder = GetHelpBuilder(SmallMaxWidth);

helpBuilder.Write(command, _console);
Expand Down Expand Up @@ -777,16 +777,16 @@ public void Help_describes_default_value_for_argument()

help.Should().Contain("[default: the-arg-value]");
}

[Fact]
public void Help_does_not_show_default_value_for_argument_when_default_value_is_empty()
{
var argument = new Argument<string>("the-arg")
{
{
Description = "The argument description",
DefaultValueFactory = (_) => ""
};

var command = new Command("the-command", "The command description")
{
argument
Expand Down Expand Up @@ -824,6 +824,38 @@ public void Help_does_not_show_default_value_for_option_when_default_value_is_em
help.Should().NotContain("[default");
}

[Flags]
public enum Letters
{
A = 1,
B = 2
}

[Fact]
public void Help_does_not_show_arguments_for_enum_backed_option_when_arity_is_zero()
{
var option = new Option<Letters>("--all")
{
Description = "Passes both A and B",
Arity = ArgumentArity.Zero,
CustomParser = _ => Letters.A | Letters.B
};

var command = new Command("the-command", "The command description")
{
option
};

var helpBuilder = GetHelpBuilder(SmallMaxWidth);

helpBuilder.Write(command, _console);

var help = _console.ToString();

help.Should().NotContain("--all <A|B>");
}


[Fact]
public void Command_arguments_default_value_provided()
{
Expand Down Expand Up @@ -864,7 +896,7 @@ public void Command_arguments_with_default_values_that_are_enumerable_display_pi
new Argument<List<int>>("filter-size")
{
DefaultValueFactory = (_) => new List<int>() { 0, 2, 4 }
}
}
};

_helpBuilder.Write(command, _console);
Expand Down Expand Up @@ -905,7 +937,7 @@ public void Command_shared_arguments_with_one_or_more_arity_are_displayed_as_bei

_console.ToString().Should().Contain(expected);
}

#endregion Arguments

#region Options
Expand Down Expand Up @@ -1491,7 +1523,7 @@ public void Help_describes_default_value_for_subcommand_with_arguments_and_only_
{
Hidden = true
};
argument.DefaultValueFactory = _ => "the-arg-value";
argument.DefaultValueFactory = _ => "the-arg-value";
otherArgumentHidden.DefaultValueFactory = _ => "the-other-hidden-arg-value";

var command = new Command("outer", "outer command help")
Expand Down
17 changes: 10 additions & 7 deletions src/System.CommandLine/Help/HelpBuilder.Default.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,22 @@ public static string GetArgumentUsageLabel(Symbol parameter)
// By default Option.Name == Argument.Name, don't repeat it
return parameter switch
{
Argument argument => GetUsageLabel(argument.HelpName, argument.ValueType, argument.CompletionSources, argument) ?? $"<{argument.Name}>",
Option option => GetUsageLabel(option.HelpName, option.ValueType, option.CompletionSources, option) ?? "",
Argument argument => GetUsageLabel(argument.HelpName, argument.ValueType, argument.CompletionSources, argument, argument.Arity) ?? $"<{argument.Name}>",
Option option => GetUsageLabel(option.HelpName, option.ValueType, option.CompletionSources, option, option.Arity) ?? "",
_ => throw new InvalidOperationException()
};

static string? GetUsageLabel(string? helpName, Type valueType, List<Func<CompletionContext, IEnumerable<CompletionItem>>> completionSources, Symbol symbol)
static string? GetUsageLabel(string? helpName, Type valueType, List<Func<CompletionContext, IEnumerable<CompletionItem>>> completionSources, Symbol symbol, ArgumentArity arity)
{
// Argument.HelpName is always first choice
if (!string.IsNullOrWhiteSpace(helpName))
{
return $"<{helpName}>";
}
else if (!(valueType == typeof(bool) || valueType == typeof(bool?)) && completionSources.Count > 0)
else if (
!(valueType == typeof(bool) || valueType == typeof(bool?))
&& arity.MaximumNumberOfValues > 0 // allowing zero arguments means we don't need to show usage
&& completionSources.Count > 0)
{
IEnumerable<string> completions = symbol
.GetCompletions(CompletionContext.Empty)
Expand Down Expand Up @@ -94,9 +97,9 @@ public static string GetOptionUsageLabel(Option symbol)

private static string GetIdentifierSymbolUsageLabel(Symbol symbol, ICollection<string>? aliasSet)
{
var aliases = aliasSet is null
? new [] { symbol.Name }
: new [] {symbol.Name}.Concat(aliasSet)
var aliases = aliasSet is null
? new[] { symbol.Name }
: new[] { symbol.Name }.Concat(aliasSet)
.Select(r => r.SplitPrefix())
.OrderBy(r => r.Prefix, StringComparer.OrdinalIgnoreCase)
.ThenBy(r => r.Alias, StringComparer.OrdinalIgnoreCase)
Expand Down