Skip to content

Commit 29ab313

Browse files
tmdsFrankRay78
andauthored
Async overloads for AnsiConsole Prompt/Ask/Confirm. (#1194)
* Add async overloads for Prompt/Ask/Confirm. * Added unit test coverage - AskAsync, ConfirmAsync * Reordered methods to group non-async/async of the same tests together --------- Co-authored-by: Frank Ray <[email protected]>
1 parent 92daeb7 commit 29ab313

File tree

3 files changed

+169
-11
lines changed

3 files changed

+169
-11
lines changed

src/Spectre.Console/AnsiConsole.Prompt.cs

+62
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Threading.Tasks;
2+
13
namespace Spectre.Console;
24

35
/// <summary>
@@ -21,6 +23,23 @@ public static T Prompt<T>(IPrompt<T> prompt)
2123
return prompt.Show(Console);
2224
}
2325

26+
/// <summary>
27+
/// Displays a prompt to the user.
28+
/// </summary>
29+
/// <typeparam name="T">The prompt result type.</typeparam>
30+
/// <param name="prompt">The prompt to display.</param>
31+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
32+
/// <returns>The prompt input result.</returns>
33+
public static Task<T> PromptAsync<T>(IPrompt<T> prompt, CancellationToken cancellationToken = default)
34+
{
35+
if (prompt is null)
36+
{
37+
throw new ArgumentNullException(nameof(prompt));
38+
}
39+
40+
return prompt.ShowAsync(Console, cancellationToken);
41+
}
42+
2443
/// <summary>
2544
/// Displays a prompt to the user.
2645
/// </summary>
@@ -32,6 +51,18 @@ public static T Ask<T>(string prompt)
3251
return new TextPrompt<T>(prompt).Show(Console);
3352
}
3453

54+
/// <summary>
55+
/// Displays a prompt to the user.
56+
/// </summary>
57+
/// <typeparam name="T">The prompt result type.</typeparam>
58+
/// <param name="prompt">The prompt markup text.</param>
59+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
60+
/// <returns>The prompt input result.</returns>
61+
public static Task<T> AskAsync<T>(string prompt, CancellationToken cancellationToken = default)
62+
{
63+
return new TextPrompt<T>(prompt).ShowAsync(Console, cancellationToken);
64+
}
65+
3566
/// <summary>
3667
/// Displays a prompt to the user with a given default.
3768
/// </summary>
@@ -46,6 +77,21 @@ public static T Ask<T>(string prompt, T defaultValue)
4677
.Show(Console);
4778
}
4879

80+
/// <summary>
81+
/// Displays a prompt to the user with a given default.
82+
/// </summary>
83+
/// <typeparam name="T">The prompt result type.</typeparam>
84+
/// <param name="prompt">The prompt markup text.</param>
85+
/// <param name="defaultValue">The default value.</param>
86+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
87+
/// <returns>The prompt input result.</returns>
88+
public static Task<T> AskAsync<T>(string prompt, T defaultValue, CancellationToken cancellationToken = default)
89+
{
90+
return new TextPrompt<T>(prompt)
91+
.DefaultValue(defaultValue)
92+
.ShowAsync(Console, cancellationToken);
93+
}
94+
4995
/// <summary>
5096
/// Displays a prompt with two choices, yes or no.
5197
/// </summary>
@@ -60,4 +106,20 @@ public static bool Confirm(string prompt, bool defaultValue = true)
60106
}
61107
.Show(Console);
62108
}
109+
110+
/// <summary>
111+
/// Displays a prompt with two choices, yes or no.
112+
/// </summary>
113+
/// <param name="prompt">The prompt markup text.</param>
114+
/// <param name="defaultValue">Specifies the default answer.</param>
115+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
116+
/// <returns><c>true</c> if the user selected "yes", otherwise <c>false</c>.</returns>
117+
public static Task<bool> ConfirmAsync(string prompt, bool defaultValue = true, CancellationToken cancellationToken = default)
118+
{
119+
return new ConfirmationPrompt(prompt)
120+
{
121+
DefaultValue = defaultValue,
122+
}
123+
.ShowAsync(Console, cancellationToken);
124+
}
63125
}

src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs

+66
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Threading.Tasks;
2+
13
namespace Spectre.Console;
24

35
/// <summary>
@@ -64,4 +66,68 @@ public static bool Confirm(this IAnsiConsole console, string prompt, bool defaul
6466
}
6567
.Show(console);
6668
}
69+
70+
/// <summary>
71+
/// Displays a prompt to the user.
72+
/// </summary>
73+
/// <typeparam name="T">The prompt result type.</typeparam>
74+
/// <param name="console">The console.</param>
75+
/// <param name="prompt">The prompt to display.</param>
76+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
77+
/// <returns>The prompt input result.</returns>
78+
public static Task<T> PromptAsync<T>(this IAnsiConsole console, IPrompt<T> prompt, CancellationToken cancellationToken = default)
79+
{
80+
if (prompt is null)
81+
{
82+
throw new ArgumentNullException(nameof(prompt));
83+
}
84+
85+
return prompt.ShowAsync(console, cancellationToken);
86+
}
87+
88+
/// <summary>
89+
/// Displays a prompt to the user.
90+
/// </summary>
91+
/// <typeparam name="T">The prompt result type.</typeparam>
92+
/// <param name="console">The console.</param>
93+
/// <param name="prompt">The prompt markup text.</param>
94+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
95+
/// <returns>The prompt input result.</returns>
96+
public static Task<T> AskAsync<T>(this IAnsiConsole console, string prompt, CancellationToken cancellationToken = default)
97+
{
98+
return new TextPrompt<T>(prompt).ShowAsync(console, cancellationToken);
99+
}
100+
101+
/// <summary>
102+
/// Displays a prompt to the user.
103+
/// </summary>
104+
/// <typeparam name="T">The prompt result type.</typeparam>
105+
/// <param name="console">The console.</param>
106+
/// <param name="prompt">The prompt markup text.</param>
107+
/// <param name="culture">Specific CultureInfo to use when converting input.</param>
108+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
109+
/// <returns>The prompt input result.</returns>
110+
public static Task<T> AskAsync<T>(this IAnsiConsole console, string prompt, CultureInfo? culture, CancellationToken cancellationToken = default)
111+
{
112+
var textPrompt = new TextPrompt<T>(prompt);
113+
textPrompt.Culture = culture;
114+
return textPrompt.ShowAsync(console, cancellationToken);
115+
}
116+
117+
/// <summary>
118+
/// Displays a prompt with two choices, yes or no.
119+
/// </summary>
120+
/// <param name="console">The console.</param>
121+
/// <param name="prompt">The prompt markup text.</param>
122+
/// <param name="defaultValue">Specifies the default answer.</param>
123+
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
124+
/// <returns><c>true</c> if the user selected "yes", otherwise <c>false</c>.</returns>
125+
public static Task<bool> ConfirmAsync(this IAnsiConsole console, string prompt, bool defaultValue = true, CancellationToken cancellationToken = default)
126+
{
127+
return new ConfirmationPrompt(prompt)
128+
{
129+
DefaultValue = defaultValue,
130+
}
131+
.ShowAsync(console, cancellationToken);
132+
}
67133
}

src/Tests/Spectre.Console.Tests/Unit/AnsiConsoleTests.Prompt.cs

+41-11
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,29 @@ namespace Spectre.Console.Tests.Unit;
22

33
public partial class AnsiConsoleTests
44
{
5-
public sealed class Prompt
5+
public sealed class Confirm
66
{
77
[Theory]
8-
[InlineData(true, true)]
9-
[InlineData(false, false)]
10-
public void Should_Return_Default_Value_If_Nothing_Is_Entered(bool expected, bool defaultValue)
8+
[InlineData(true, true, true)]
9+
[InlineData(false, true, true)]
10+
[InlineData(true, false, false)]
11+
[InlineData(false, false, false)]
12+
public async Task Should_Return_Default_Value_If_Nothing_Is_Entered(bool async, bool defaultValue, bool expected)
1113
{
1214
// Given
1315
var console = new TestConsole().EmitAnsiSequences();
1416
console.Input.PushKey(ConsoleKey.Enter);
1517

1618
// When
17-
var result = console.Confirm("Want some prompt?", defaultValue);
19+
bool result;
20+
if (async)
21+
{
22+
result = await console.ConfirmAsync("Want some prompt?", defaultValue);
23+
}
24+
else
25+
{
26+
result = console.Confirm("Want some prompt?", defaultValue);
27+
}
1828

1929
// Then
2030
result.ShouldBe(expected);
@@ -23,29 +33,49 @@ public void Should_Return_Default_Value_If_Nothing_Is_Entered(bool expected, boo
2333

2434
public sealed class Ask
2535
{
26-
[Fact]
27-
public void Should_Return_Correct_DateTime_When_Asked_PL_Culture()
36+
[Theory]
37+
[InlineData(true)]
38+
[InlineData(false)]
39+
public async Task Should_Return_Correct_DateTime_When_Asked_PL_Culture(bool async)
2840
{
2941
// Given
3042
var console = new TestConsole().EmitAnsiSequences();
3143
console.Input.PushTextWithEnter("1/2/1998");
3244

3345
// When
34-
var dateTime = console.Ask<DateTime>(string.Empty, CultureInfo.GetCultureInfo("pl-PL"));
46+
DateTime dateTime;
47+
if (async)
48+
{
49+
dateTime = await console.AskAsync<DateTime>(string.Empty, CultureInfo.GetCultureInfo("pl-PL"));
50+
}
51+
else
52+
{
53+
dateTime = console.Ask<DateTime>(string.Empty, CultureInfo.GetCultureInfo("pl-PL"));
54+
}
3555

3656
// Then
3757
dateTime.ShouldBe(new DateTime(1998, 2, 1));
3858
}
3959

40-
[Fact]
41-
public void Should_Return_Correct_DateTime_When_Asked_US_Culture()
60+
[Theory]
61+
[InlineData(true)]
62+
[InlineData(false)]
63+
public async Task Should_Return_Correct_DateTime_When_Asked_US_Culture(bool async)
4264
{
4365
// Given
4466
var console = new TestConsole().EmitAnsiSequences();
4567
console.Input.PushTextWithEnter("2/1/1998");
4668

4769
// When
48-
var dateTime = console.Ask<DateTime>(string.Empty, CultureInfo.GetCultureInfo("en-US"));
70+
DateTime dateTime;
71+
if (async)
72+
{
73+
dateTime = await console.AskAsync<DateTime>(string.Empty, CultureInfo.GetCultureInfo("en-US"));
74+
}
75+
else
76+
{
77+
dateTime = console.Ask<DateTime>(string.Empty, CultureInfo.GetCultureInfo("en-US"));
78+
}
4979

5080
// Then
5181
dateTime.ShouldBe(new DateTime(1998, 2, 1));

0 commit comments

Comments
 (0)