Add text prompt support

This commit is contained in:
Patrik Svensson
2020-10-30 14:58:17 +01:00
committed by Patrik Svensson
parent 380c6aca45
commit 0d209d8f18
27 changed files with 1326 additions and 72 deletions

View File

@ -0,0 +1,49 @@
using System;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IAnsiConsole"/>.
/// </summary>
public static partial class AnsiConsoleExtensions
{
internal static string ReadLine(this IAnsiConsole console, Style? style, bool secret)
{
if (console is null)
{
throw new ArgumentNullException(nameof(console));
}
style ??= Style.Plain;
var result = string.Empty;
while (true)
{
var key = console.Input.ReadKey(true);
if (key.Key == ConsoleKey.Enter)
{
return result;
}
if (key.Key == ConsoleKey.Backspace)
{
if (result.Length > 0)
{
result = result.Substring(0, result.Length - 1);
console.Write("\b \b");
}
continue;
}
result += key.KeyChar.ToString();
if (!char.IsControl(key.KeyChar))
{
console.Write(secret ? "*" : key.KeyChar.ToString(), style);
}
}
}
}
}

View File

@ -0,0 +1,50 @@
using System;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="IAnsiConsole"/>.
/// </summary>
public static partial class AnsiConsoleExtensions
{
/// <summary>
/// Displays a prompt to the user.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="console">The console.</param>
/// <param name="prompt">The prompt to display.</param>
/// <returns>The prompt input result.</returns>
public static T Prompt<T>(this IAnsiConsole console, IPrompt<T> prompt)
{
if (prompt is null)
{
throw new ArgumentNullException(nameof(prompt));
}
return prompt.Show(console);
}
/// <summary>
/// Displays a prompt to the user.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="console">The console.</param>
/// <param name="prompt">The prompt markup text.</param>
/// <returns>The prompt input result.</returns>
public static T Ask<T>(this IAnsiConsole console, string prompt)
{
return new TextPrompt<T>(prompt).Show(console);
}
/// <summary>
/// Displays a prompt with two choices, yes or no.
/// </summary>
/// <param name="console">The console.</param>
/// <param name="prompt">The prompt markup text.</param>
/// <returns><c>true</c> if the user selected "yes", otherwise <c>false</c>.</returns>
public static bool Confirm(this IAnsiConsole console, string prompt)
{
return new ConfirmationPrompt(prompt).Show(console);
}
}
}

View File

@ -18,6 +18,16 @@ namespace Spectre.Console
return new Recorder(console);
}
/// <summary>
/// Writes the specified string value to the console.
/// </summary>
/// <param name="console">The console to write to.</param>
/// <param name="text">The text to write.</param>
public static void Write(this IAnsiConsole console, string text)
{
Write(console, text, Style.Plain);
}
/// <summary>
/// Writes the specified string value to the console.
/// </summary>
@ -31,6 +41,11 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(console));
}
if (text is null)
{
throw new ArgumentNullException(nameof(text));
}
console.Write(new Segment(text, style));
}
@ -48,6 +63,16 @@ namespace Spectre.Console
console.Write(Environment.NewLine, Style.Plain);
}
/// <summary>
/// Writes the specified string value, followed by the current line terminator, to the console.
/// </summary>
/// <param name="console">The console to write to.</param>
/// <param name="text">The text to write.</param>
public static void WriteLine(this IAnsiConsole console, string text)
{
WriteLine(console, text, Style.Plain);
}
/// <summary>
/// Writes the specified string value, followed by the current line terminator, to the console.
/// </summary>
@ -61,6 +86,11 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(console));
}
if (text is null)
{
throw new ArgumentNullException(nameof(text));
}
console.Write(new Segment(text, style));
console.WriteLine();
}

View File

@ -0,0 +1,135 @@
using System;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="ConfirmationPrompt"/>.
/// </summary>
public static class ConfirmationPromptExtensions
{
/// <summary>
/// Show or hide choices.
/// </summary>
/// <param name="obj">The prompt.</param>
/// <param name="show">Whether or not the choices should be visible.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static ConfirmationPrompt ShowChoices(this ConfirmationPrompt obj, bool show)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.ShowChoices = show;
return obj;
}
/// <summary>
/// Shows choices.
/// </summary>
/// <param name="obj">The prompt.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static ConfirmationPrompt ShowChoices(this ConfirmationPrompt obj)
{
return ShowChoices(obj, true);
}
/// <summary>
/// Hides choices.
/// </summary>
/// <param name="obj">The prompt.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static ConfirmationPrompt HideChoices(this ConfirmationPrompt obj)
{
return ShowChoices(obj, false);
}
/// <summary>
/// Show or hide the default value.
/// </summary>
/// <param name="obj">The prompt.</param>
/// <param name="show">Whether or not the default value should be visible.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static ConfirmationPrompt ShowDefaultValue(this ConfirmationPrompt obj, bool show)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.ShowDefaultValue = show;
return obj;
}
/// <summary>
/// Shows the default value.
/// </summary>
/// <param name="obj">The prompt.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static ConfirmationPrompt ShowDefaultValue(this ConfirmationPrompt obj)
{
return ShowDefaultValue(obj, true);
}
/// <summary>
/// Hides the default value.
/// </summary>
/// <param name="obj">The prompt.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static ConfirmationPrompt HideDefaultValue(this ConfirmationPrompt obj)
{
return ShowDefaultValue(obj, false);
}
/// <summary>
/// Sets the "invalid choice" message for the prompt.
/// </summary>
/// <param name="obj">The prompt.</param>
/// <param name="message">The "invalid choice" message.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static ConfirmationPrompt InvalidChoiceMessage(this ConfirmationPrompt obj, string message)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.InvalidChoiceMessage = message;
return obj;
}
/// <summary>
/// Sets the character to interpret as "yes".
/// </summary>
/// <param name="obj">The confirmation prompt.</param>
/// <param name="character">The character to interpret as "yes".</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static ConfirmationPrompt Yes(this ConfirmationPrompt obj, char character)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Yes = character;
return obj;
}
/// <summary>
/// Sets the character to interpret as "no".
/// </summary>
/// <param name="obj">The confirmation prompt.</param>
/// <param name="character">The character to interpret as "no".</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static ConfirmationPrompt No(this ConfirmationPrompt obj, char character)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.No = character;
return obj;
}
}
}

View File

@ -0,0 +1,266 @@
using System;
namespace Spectre.Console
{
/// <summary>
/// Contains extension methods for <see cref="TextPrompt{T}"/>.
/// </summary>
public static class TextPromptExtensions
{
/// <summary>
/// Allow empty input.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> AllowEmpty<T>(this TextPrompt<T> obj)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.AllowEmpty = true;
return obj;
}
/// <summary>
/// Sets the prompt style.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <param name="style">The prompt style.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> PromptStyle<T>(this TextPrompt<T> obj, Style style)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
if (style is null)
{
throw new ArgumentNullException(nameof(style));
}
obj.PromptStyle = style;
return obj;
}
/// <summary>
/// Show or hide choices.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <param name="show">Whether or not choices should be visible.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> ShowChoices<T>(this TextPrompt<T> obj, bool show)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.ShowChoices = show;
return obj;
}
/// <summary>
/// Shows choices.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> ShowChoices<T>(this TextPrompt<T> obj)
{
return ShowChoices(obj, true);
}
/// <summary>
/// Hides choices.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> HideChoices<T>(this TextPrompt<T> obj)
{
return ShowChoices(obj, false);
}
/// <summary>
/// Show or hide the default value.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <param name="show">Whether or not the default value should be visible.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> ShowDefaultValue<T>(this TextPrompt<T> obj, bool show)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.ShowDefaultValue = show;
return obj;
}
/// <summary>
/// Shows the default value.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> ShowDefaultValue<T>(this TextPrompt<T> obj)
{
return ShowDefaultValue(obj, true);
}
/// <summary>
/// Hides the default value.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> HideDefaultValue<T>(this TextPrompt<T> obj)
{
return ShowDefaultValue(obj, false);
}
/// <summary>
/// Sets the validation error message for the prompt.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <param name="message">The validation error message.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> ValidationErrorMessage<T>(this TextPrompt<T> obj, string message)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.ValidationErrorMessage = message;
return obj;
}
/// <summary>
/// Sets the "invalid choice" message for the prompt.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <param name="message">The "invalid choice" message.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> InvalidChoiceMessage<T>(this TextPrompt<T> obj, string message)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.InvalidChoiceMessage = message;
return obj;
}
/// <summary>
/// Sets the default value of the prompt.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <param name="value">The default value.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> DefaultValue<T>(this TextPrompt<T> obj, T value)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.DefaultValue = new TextPrompt<T>.DefaultValueContainer(value);
return obj;
}
/// <summary>
/// Sets the validation criteria for the prompt.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <param name="validator">The validation criteria.</param>
/// <param name="message">The validation error message.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> Validate<T>(this TextPrompt<T> obj, Func<T, bool> validator, string? message = null)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Validator = result =>
{
if (validator(result))
{
return ValidationResult.Success();
}
return ValidationResult.Error(message);
};
return obj;
}
/// <summary>
/// Sets the validation criteria for the prompt.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <param name="validator">The validation criteria.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> Validate<T>(this TextPrompt<T> obj, Func<T, ValidationResult> validator)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Validator = validator;
return obj;
}
/// <summary>
/// Adds a choice to the prompt.
/// </summary>
/// <typeparam name="T">The prompt result type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <param name="choice">The choice to add.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> AddChoice<T>(this TextPrompt<T> obj, T choice)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.Choices.Add(choice);
return obj;
}
/// <summary>
/// Replaces prompt user input with asterixes in the console.
/// </summary>
/// <typeparam name="T">The prompt type.</typeparam>
/// <param name="obj">The prompt.</param>
/// <returns>The same instance so that multiple calls can be chained.</returns>
public static TextPrompt<T> Secret<T>(this TextPrompt<T> obj)
{
if (obj is null)
{
throw new ArgumentNullException(nameof(obj));
}
obj.IsSecret = true;
return obj;
}
}
}