mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 17:02:51 +08:00
Adds optional function to get the display string for TextPrompt choices
This commit is contained in:
parent
041aea2ae5
commit
0bbf9b81a9
@ -0,0 +1 @@
|
|||||||
|
Favorite fruit? [Apple/Banana]: Banana
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Shouldly;
|
||||||
using VerifyXunit;
|
using VerifyXunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -168,5 +169,24 @@ namespace Spectre.Console.Tests.Unit
|
|||||||
// Then
|
// Then
|
||||||
return Verifier.Verify(console.Output);
|
return Verifier.Verify(console.Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public Task Should_Use_Custom_Converter()
|
||||||
|
{
|
||||||
|
// Given
|
||||||
|
var console = new PlainConsole();
|
||||||
|
console.Input.PushTextWithEnter("Banana");
|
||||||
|
|
||||||
|
// When
|
||||||
|
var result = console.Prompt(
|
||||||
|
new TextPrompt<(int, string)>("Favorite fruit?")
|
||||||
|
.AddChoice((1, "Apple"))
|
||||||
|
.AddChoice((2, "Banana"))
|
||||||
|
.WithConverter(testData => testData.Item2));
|
||||||
|
|
||||||
|
// Then
|
||||||
|
result.Item1.ShouldBe(2);
|
||||||
|
return Verifier.Verify(console.Output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -15,6 +16,7 @@ namespace Spectre.Console
|
|||||||
public sealed class TextPrompt<T> : IPrompt<T>
|
public sealed class TextPrompt<T> : IPrompt<T>
|
||||||
{
|
{
|
||||||
private readonly string _prompt;
|
private readonly string _prompt;
|
||||||
|
private readonly StringComparer? _comparer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the prompt style.
|
/// Gets or sets the prompt style.
|
||||||
@ -24,7 +26,7 @@ namespace Spectre.Console
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the list of choices.
|
/// Gets the list of choices.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HashSet<T> Choices { get; }
|
public List<T> Choices { get; } = new List<T>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the message for invalid choices.
|
/// Gets or sets the message for invalid choices.
|
||||||
@ -59,6 +61,12 @@ namespace Spectre.Console
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowEmpty { get; set; }
|
public bool AllowEmpty { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the converter to get the display string for a choice. By default
|
||||||
|
/// the corresponding <see cref="TypeConverter"/> is used.
|
||||||
|
/// </summary>
|
||||||
|
public Func<T, string>? Converter { get; set; } = TypeConverterHelper.ConvertToString;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the validator.
|
/// Gets or sets the validator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -74,11 +82,10 @@ namespace Spectre.Console
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="prompt">The prompt markup text.</param>
|
/// <param name="prompt">The prompt markup text.</param>
|
||||||
/// <param name="comparer">The comparer used for choices.</param>
|
/// <param name="comparer">The comparer used for choices.</param>
|
||||||
public TextPrompt(string prompt, IEqualityComparer<T>? comparer = null)
|
public TextPrompt(string prompt, StringComparer? comparer = null)
|
||||||
{
|
{
|
||||||
_prompt = prompt;
|
_prompt = prompt;
|
||||||
|
_comparer = comparer;
|
||||||
Choices = new HashSet<T>(comparer ?? EqualityComparer<T>.Default);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -95,7 +102,9 @@ namespace Spectre.Console
|
|||||||
}
|
}
|
||||||
|
|
||||||
var promptStyle = PromptStyle ?? Style.Plain;
|
var promptStyle = PromptStyle ?? Style.Plain;
|
||||||
var choices = Choices.Select(choice => TypeConverterHelper.ConvertToString(choice));
|
var converter = Converter ?? TypeConverterHelper.ConvertToString;
|
||||||
|
var choices = Choices.Select(choice => converter(choice)).ToList();
|
||||||
|
var choiceMap = Choices.ToDictionary(choice => converter(choice), choice => choice, _comparer);
|
||||||
|
|
||||||
WritePrompt(console);
|
WritePrompt(console);
|
||||||
|
|
||||||
@ -108,7 +117,7 @@ namespace Spectre.Console
|
|||||||
{
|
{
|
||||||
if (DefaultValue != null)
|
if (DefaultValue != null)
|
||||||
{
|
{
|
||||||
console.Write(TypeConverterHelper.ConvertToString(DefaultValue.Value), promptStyle);
|
console.Write(converter(DefaultValue.Value), promptStyle);
|
||||||
console.WriteLine();
|
console.WriteLine();
|
||||||
return DefaultValue.Value;
|
return DefaultValue.Value;
|
||||||
}
|
}
|
||||||
@ -121,17 +130,10 @@ namespace Spectre.Console
|
|||||||
|
|
||||||
console.WriteLine();
|
console.WriteLine();
|
||||||
|
|
||||||
// Try convert the value to the expected type.
|
T? result;
|
||||||
if (!TypeConverterHelper.TryConvertFromString<T>(input, out var result) || result == null)
|
|
||||||
{
|
|
||||||
console.MarkupLine(ValidationErrorMessage);
|
|
||||||
WritePrompt(console);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Choices.Count > 0)
|
if (Choices.Count > 0)
|
||||||
{
|
{
|
||||||
if (Choices.Contains(result))
|
if (choiceMap.TryGetValue(input, out result) && result != null)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -142,6 +144,12 @@ namespace Spectre.Console
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!TypeConverterHelper.TryConvertFromString<T>(input, out result) || result == null)
|
||||||
|
{
|
||||||
|
console.MarkupLine(ValidationErrorMessage);
|
||||||
|
WritePrompt(console);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Run all validators
|
// Run all validators
|
||||||
if (!ValidateResult(result, out var validationMessage))
|
if (!ValidateResult(result, out var validationMessage))
|
||||||
@ -171,7 +179,8 @@ namespace Spectre.Console
|
|||||||
|
|
||||||
if (ShowChoices && Choices.Count > 0)
|
if (ShowChoices && Choices.Count > 0)
|
||||||
{
|
{
|
||||||
var choices = string.Join("/", Choices.Select(choice => TypeConverterHelper.ConvertToString(choice)));
|
var converter = Converter ?? TypeConverterHelper.ConvertToString;
|
||||||
|
var choices = string.Join("/", Choices.Select(choice => converter(choice)));
|
||||||
builder.AppendFormat(CultureInfo.InvariantCulture, " [blue][[{0}]][/]", choices);
|
builder.AppendFormat(CultureInfo.InvariantCulture, " [blue][[{0}]][/]", choices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Spectre.Console
|
namespace Spectre.Console
|
||||||
{
|
{
|
||||||
@ -246,6 +247,33 @@ namespace Spectre.Console
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds multiple choices to the prompt.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The prompt result type.</typeparam>
|
||||||
|
/// <param name="obj">The prompt.</param>
|
||||||
|
/// <param name="choices">The choices to add.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static TextPrompt<T> AddChoices<T>(this TextPrompt<T> obj, IEnumerable<T> choices)
|
||||||
|
{
|
||||||
|
if (obj is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choices is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(choices));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var choice in choices)
|
||||||
|
{
|
||||||
|
obj.Choices.Add(choice);
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Replaces prompt user input with asterixes in the console.
|
/// Replaces prompt user input with asterixes in the console.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -262,5 +290,23 @@ namespace Spectre.Console
|
|||||||
obj.IsSecret = true;
|
obj.IsSecret = true;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the function to create a display string for a given choice.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The prompt type.</typeparam>
|
||||||
|
/// <param name="obj">The prompt.</param>
|
||||||
|
/// <param name="displaySelector">The function to get a display string for a given choice.</param>
|
||||||
|
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||||
|
public static TextPrompt<T> WithConverter<T>(this TextPrompt<T> obj, Func<T, string>? displaySelector)
|
||||||
|
{
|
||||||
|
if (obj is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Converter = displaySelector;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user