diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs index 1b7878a..382503f 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs @@ -34,6 +34,21 @@ public static partial class AnsiConsoleExtensions return new TextPrompt(prompt).Show(console); } + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The console. + /// The prompt markup text. + /// Specific CultureInfo to use when converting input. + /// The prompt input result. + public static T Ask(this IAnsiConsole console, string prompt, CultureInfo? culture) + { + var textPrompt = new TextPrompt(prompt); + textPrompt.Culture = culture; + return textPrompt.Show(console); + } + /// /// Displays a prompt with two choices, yes or no. /// diff --git a/src/Spectre.Console/Internal/TypeConverterHelper.cs b/src/Spectre.Console/Internal/TypeConverterHelper.cs index 0b4fc24..901b308 100644 --- a/src/Spectre.Console/Internal/TypeConverterHelper.cs +++ b/src/Spectre.Console/Internal/TypeConverterHelper.cs @@ -21,6 +21,28 @@ internal static class TypeConverterHelper } } + public static bool TryConvertFromStringWithCulture(string input, CultureInfo? info, [MaybeNull] out T result) + { + try + { + if (info == null) + { + return TryConvertFromString(input, out result); + } + else + { + result = (T)GetTypeConverter().ConvertFromString(null!, info, input); + } + + return true; + } + catch + { + result = default; + return false; + } + } + public static TypeConverter GetTypeConverter() { var converter = TypeDescriptor.GetConverter(typeof(T)); diff --git a/src/Spectre.Console/Prompts/TextPrompt.cs b/src/Spectre.Console/Prompts/TextPrompt.cs index 2bd4b64..e48ed60 100644 --- a/src/Spectre.Console/Prompts/TextPrompt.cs +++ b/src/Spectre.Console/Prompts/TextPrompt.cs @@ -4,7 +4,7 @@ namespace Spectre.Console; /// Represents a prompt. /// /// The prompt result type. -public sealed class TextPrompt : IPrompt +public sealed class TextPrompt : IPrompt, IHasCulture { private readonly string _prompt; private readonly StringComparer? _comparer; @@ -19,6 +19,11 @@ public sealed class TextPrompt : IPrompt /// public List Choices { get; } = new List(); + /// + /// Gets or sets the culture to use when converting input to object. + /// + public CultureInfo? Culture { get; set; } + /// /// Gets or sets the message for invalid choices. /// @@ -28,12 +33,12 @@ public sealed class TextPrompt : IPrompt /// Gets or sets a value indicating whether input should /// be hidden in the console. /// - public bool IsSecret { get; set; } - + public bool IsSecret { get; set; } + /// - /// Gets or sets the character to use while masking + /// Gets or sets the character to use while masking /// a secret prompt. - /// + /// public char? Mask { get; set; } = '*'; /// @@ -131,7 +136,7 @@ public sealed class TextPrompt : IPrompt if (string.IsNullOrWhiteSpace(input)) { if (DefaultValue != null) - { + { var defaultValue = converter(DefaultValue.Value); console.Write(IsSecret ? defaultValue.Mask(Mask) : defaultValue, promptStyle); console.WriteLine(); @@ -160,7 +165,7 @@ public sealed class TextPrompt : IPrompt continue; } } - else if (!TypeConverterHelper.TryConvertFromString(input, out result) || result == null) + else if (!TypeConverterHelper.TryConvertFromStringWithCulture(input, Culture, out result) || result == null) { console.MarkupLine(ValidationErrorMessage); WritePrompt(console); @@ -208,8 +213,8 @@ public sealed class TextPrompt : IPrompt { appendSuffix = true; var converter = Converter ?? TypeConverterHelper.ConvertToString; - var defaultValueStyle = DefaultValueStyle?.ToMarkup() ?? "green"; - var defaultValue = converter(DefaultValue.Value); + var defaultValueStyle = DefaultValueStyle?.ToMarkup() ?? "green"; + var defaultValue = converter(DefaultValue.Value); builder.AppendFormat( CultureInfo.InvariantCulture, diff --git a/test/Spectre.Console.Tests/Unit/AnsiConsoleTests.Prompt.cs b/test/Spectre.Console.Tests/Unit/AnsiConsoleTests.Prompt.cs index 9ec084e..e6fa30c 100644 --- a/test/Spectre.Console.Tests/Unit/AnsiConsoleTests.Prompt.cs +++ b/test/Spectre.Console.Tests/Unit/AnsiConsoleTests.Prompt.cs @@ -20,4 +20,35 @@ public partial class AnsiConsoleTests result.ShouldBe(expected); } } + + public sealed class Ask + { + [Fact] + public void Should_Return_Correct_DateTime_When_Asked_PL_Culture() + { + // Given + var console = new TestConsole().EmitAnsiSequences(); + console.Input.PushTextWithEnter("1/2/1998"); + + // When + var dateTime = console.Ask(string.Empty, CultureInfo.GetCultureInfo("pl-PL")); + + // Then + dateTime.ShouldBe(new DateTime(1998, 2, 1)); + } + + [Fact] + public void Should_Return_Correct_DateTime_When_Asked_US_Culture() + { + // Given + var console = new TestConsole().EmitAnsiSequences(); + console.Input.PushTextWithEnter("2/1/1998"); + + // When + var dateTime = console.Ask(string.Empty, CultureInfo.GetCultureInfo("en-US")); + + // Then + dateTime.ShouldBe(new DateTime(1998, 2, 1)); + } + } }