diff --git a/src/Spectre.Console.Cli/Internal/Binding/CommandValueBinder.cs b/src/Spectre.Console.Cli/Internal/Binding/CommandValueBinder.cs index cd4094ca0..8dfbee45d 100644 --- a/src/Spectre.Console.Cli/Internal/Binding/CommandValueBinder.cs +++ b/src/Spectre.Console.Cli/Internal/Binding/CommandValueBinder.cs @@ -65,6 +65,11 @@ private object GetLookup(CommandParameter parameter, ITypeResolver resolver, obj private object GetArray(CommandParameter parameter, object? value) { + if (value is Array) + { + return value; + } + // Add a new item to the array var array = (Array?)_lookup.GetValue(parameter); Array newArray; diff --git a/src/Spectre.Console.Cli/Internal/Binding/CommandValueResolver.cs b/src/Spectre.Console.Cli/Internal/Binding/CommandValueResolver.cs index 3b534199e..ccd7453a9 100644 --- a/src/Spectre.Console.Cli/Internal/Binding/CommandValueResolver.cs +++ b/src/Spectre.Console.Cli/Internal/Binding/CommandValueResolver.cs @@ -133,13 +133,33 @@ public static CommandValueLookup GetParameterValues(CommandTree? tree, ITypeReso var (converter, _) = GetConverter(lookup, binder, resolver, parameter); if (converter != null) { - result = converter.ConvertFrom(result); + result = result is Array array ? ConvertArray(array, converter) : converter.ConvertFrom(result); } } return result; } + private static Array ConvertArray(Array sourceArray, TypeConverter converter) + { + Array? targetArray = null; + for (var i = 0; i < sourceArray.Length; i++) + { + var item = sourceArray.GetValue(i); + if (item != null) + { + var converted = converter.ConvertFrom(item); + if (converted != null) + { + targetArray ??= Array.CreateInstance(converted.GetType(), sourceArray.Length); + targetArray.SetValue(converted, i); + } + } + } + + return targetArray ?? sourceArray; + } + [SuppressMessage("Style", "IDE0019:Use pattern matching", Justification = "It's OK")] private static (TypeConverter? Converter, ConstructorInfo? StringConstructor) GetConverter(CommandValueLookup lookup, CommandValueBinder binder, ITypeResolver resolver, CommandParameter parameter) { diff --git a/src/Spectre.Console.Cli/Internal/HelpWriter.cs b/src/Spectre.Console.Cli/Internal/HelpWriter.cs index da58da88e..8f8e5d453 100644 --- a/src/Spectre.Console.Cli/Internal/HelpWriter.cs +++ b/src/Spectre.Console.Cli/Internal/HelpWriter.cs @@ -348,7 +348,17 @@ static string GetOptionParts(HelpOption option) var columns = new List { GetOptionParts(option) }; if (defaultValueColumn) { - columns.Add(option.DefaultValue == null ? " " : $"[bold]{option.DefaultValue.ToString().EscapeMarkup()}[/]"); + static string Bold(object obj) => $"[bold]{obj.ToString().EscapeMarkup()}[/]"; + + var defaultValue = option.DefaultValue switch + { + null => " ", + "" => " ", + Array { Length: 0 } => " ", + Array array => string.Join(", ", array.Cast().Select(Bold)), + _ => Bold(option.DefaultValue), + }; + columns.Add(defaultValue); } columns.Add(option.Description?.TrimEnd('.') ?? " "); diff --git a/test/Spectre.Console.Cli.Tests/Data/Settings/LionSettings.cs b/test/Spectre.Console.Cli.Tests/Data/Settings/LionSettings.cs index 19aa6f259..ea740b5be 100644 --- a/test/Spectre.Console.Cli.Tests/Data/Settings/LionSettings.cs +++ b/test/Spectre.Console.Cli.Tests/Data/Settings/LionSettings.cs @@ -9,4 +9,9 @@ public class LionSettings : CatSettings [CommandOption("-c ")] [Description("The number of children the lion has.")] public int Children { get; set; } + + [CommandOption("-d ")] + [Description("The days the lion goes hunting.")] + [DefaultValue(new[] { DayOfWeek.Monday, DayOfWeek.Thursday })] + public DayOfWeek[] HuntDays { get; set; } } diff --git a/test/Spectre.Console.Cli.Tests/Data/Settings/OptionalArgumentWithDefaultValueSettings.cs b/test/Spectre.Console.Cli.Tests/Data/Settings/OptionalArgumentWithDefaultValueSettings.cs index d5167b062..f36dc8905 100644 --- a/test/Spectre.Console.Cli.Tests/Data/Settings/OptionalArgumentWithDefaultValueSettings.cs +++ b/test/Spectre.Console.Cli.Tests/Data/Settings/OptionalArgumentWithDefaultValueSettings.cs @@ -33,3 +33,18 @@ public sealed class RequiredArgumentWithDefaultValueSettings : CommandSettings [DefaultValue("Hello World")] public string Greeting { get; set; } } + +public sealed class OptionWithArrayOfEnumDefaultValueSettings : CommandSettings +{ + [CommandOption("--days")] + [DefaultValue(new[] { DayOfWeek.Sunday, DayOfWeek.Saturday })] + public DayOfWeek[] Days { get; set; } +} + +public sealed class OptionWithArrayOfStringDefaultValueAndTypeConverterSettings : CommandSettings +{ + [CommandOption("--numbers")] + [DefaultValue(new[] { "2", "3" })] + [TypeConverter(typeof(StringToIntegerConverter))] + public int[] Numbers { get; set; } +} diff --git a/test/Spectre.Console.Cli.Tests/Expectations/Help/Default.Output.verified.txt b/test/Spectre.Console.Cli.Tests/Expectations/Help/Default.Output.verified.txt index 7c2731bba..1ea12e364 100644 --- a/test/Spectre.Console.Cli.Tests/Expectations/Help/Default.Output.verified.txt +++ b/test/Spectre.Console.Cli.Tests/Expectations/Help/Default.Output.verified.txt @@ -10,8 +10,9 @@ ARGUMENTS: OPTIONS: DEFAULT - -h, --help Prints help information - -a, --alive Indicates whether or not the animal is alive + -h, --help Prints help information + -a, --alive Indicates whether or not the animal is alive -n, --name - --agility 10 The agility between 0 and 100 - -c The number of children the lion has \ No newline at end of file + --agility 10 The agility between 0 and 100 + -c The number of children the lion has + -d Monday, Thursday The days the lion goes hunting \ No newline at end of file diff --git a/test/Spectre.Console.Cli.Tests/Expectations/Help/DefaultExamples.Output.verified.txt b/test/Spectre.Console.Cli.Tests/Expectations/Help/DefaultExamples.Output.verified.txt index 8fc25ef9e..15ed7459c 100644 --- a/test/Spectre.Console.Cli.Tests/Expectations/Help/DefaultExamples.Output.verified.txt +++ b/test/Spectre.Console.Cli.Tests/Expectations/Help/DefaultExamples.Output.verified.txt @@ -13,8 +13,9 @@ ARGUMENTS: OPTIONS: DEFAULT - -h, --help Prints help information - -a, --alive Indicates whether or not the animal is alive + -h, --help Prints help information + -a, --alive Indicates whether or not the animal is alive -n, --name - --agility 10 The agility between 0 and 100 - -c The number of children the lion has \ No newline at end of file + --agility 10 The agility between 0 and 100 + -c The number of children the lion has + -d Monday, Thursday The days the lion goes hunting \ No newline at end of file diff --git a/test/Spectre.Console.Cli.Tests/Expectations/Help/Default_Without_Args.Output.verified.txt b/test/Spectre.Console.Cli.Tests/Expectations/Help/Default_Without_Args.Output.verified.txt index 7c2731bba..1ea12e364 100644 --- a/test/Spectre.Console.Cli.Tests/Expectations/Help/Default_Without_Args.Output.verified.txt +++ b/test/Spectre.Console.Cli.Tests/Expectations/Help/Default_Without_Args.Output.verified.txt @@ -10,8 +10,9 @@ ARGUMENTS: OPTIONS: DEFAULT - -h, --help Prints help information - -a, --alive Indicates whether or not the animal is alive + -h, --help Prints help information + -a, --alive Indicates whether or not the animal is alive -n, --name - --agility 10 The agility between 0 and 100 - -c The number of children the lion has \ No newline at end of file + --agility 10 The agility between 0 and 100 + -c The number of children the lion has + -d Monday, Thursday The days the lion goes hunting \ No newline at end of file diff --git a/test/Spectre.Console.Cli.Tests/Expectations/Help/Default_Without_Args_Additional.Output.verified.txt b/test/Spectre.Console.Cli.Tests/Expectations/Help/Default_Without_Args_Additional.Output.verified.txt index 2c38182a5..3bdda1733 100644 --- a/test/Spectre.Console.Cli.Tests/Expectations/Help/Default_Without_Args_Additional.Output.verified.txt +++ b/test/Spectre.Console.Cli.Tests/Expectations/Help/Default_Without_Args_Additional.Output.verified.txt @@ -10,11 +10,12 @@ ARGUMENTS: OPTIONS: DEFAULT - -h, --help Prints help information - -a, --alive Indicates whether or not the animal is alive + -h, --help Prints help information + -a, --alive Indicates whether or not the animal is alive -n, --name - --agility 10 The agility between 0 and 100 - -c The number of children the lion has + --agility 10 The agility between 0 and 100 + -c The number of children the lion has + -d Monday, Thursday The days the lion goes hunting COMMANDS: giraffe The giraffe command \ No newline at end of file diff --git a/test/Spectre.Console.Cli.Tests/Expectations/Help/Leaf.Output.verified.txt b/test/Spectre.Console.Cli.Tests/Expectations/Help/Leaf.Output.verified.txt index 5754d726f..9083b60a0 100644 --- a/test/Spectre.Console.Cli.Tests/Expectations/Help/Leaf.Output.verified.txt +++ b/test/Spectre.Console.Cli.Tests/Expectations/Help/Leaf.Output.verified.txt @@ -8,5 +8,7 @@ ARGUMENTS: The number of teeth the lion has OPTIONS: - -h, --help Prints help information - -c The number of children the lion has \ No newline at end of file + DEFAULT + -h, --help Prints help information + -c The number of children the lion has + -d Monday, Thursday The days the lion goes hunting \ No newline at end of file diff --git a/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.cs b/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.cs index 653a5ae7b..5d2276453 100644 --- a/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.cs +++ b/test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.cs @@ -396,6 +396,50 @@ public void Should_Assign_Default_Value_To_Optional_Argument_Using_Converter_If_ }); } + [Fact] + public void Should_Assign_Array_Default_Value_To_Command_Option() + { + // Given + var app = new CommandAppTester(); + app.SetDefaultCommand>(); + app.Configure(config => + { + config.PropagateExceptions(); + }); + + // When + var result = app.Run(Array.Empty()); + + // Then + result.ExitCode.ShouldBe(0); + result.Settings.ShouldBeOfType().And(settings => + { + settings.Days.ShouldBe(new[] { DayOfWeek.Sunday, DayOfWeek.Saturday }); + }); + } + + [Fact] + public void Should_Assign_Array_Default_Value_To_Command_Option_Using_Converter_If_Necessary() + { + // Given + var app = new CommandAppTester(); + app.SetDefaultCommand>(); + app.Configure(config => + { + config.PropagateExceptions(); + }); + + // When + var result = app.Run(Array.Empty()); + + // Then + result.ExitCode.ShouldBe(0); + result.Settings.ShouldBeOfType().And(settings => + { + settings.Numbers.ShouldBe(new[] { 2, 3 }); + }); + } + [Fact] public void Should_Throw_If_Required_Argument_Have_Default_Value() {