using BytecodeApi.Extensions;
namespace BytecodeApi.ConsoleUI;
///
/// Class that retrieves user input from the in form of questions or confirmations.
///
public static class ConsoleInput
{
///
/// Gets or sets the global theme for the class.
///
public static ConsoleInputTheme Theme { get; set; }
static ConsoleInput()
{
Theme = new();
}
///
/// Writes to the console and prompts the user to input a . This process is repeated, until the entered is not empty.
///
/// A to display before the user input prompt.
///
/// The text that the user has entered. This is not empty.
///
public static string Text(string question)
{
Check.ArgumentNull(question);
Check.ArgumentNull(Theme);
Check.ArgumentNull(Theme.QuestionStyle);
Check.ArgumentNull(Theme.UserInputStyle);
Flush();
string text;
do
{
Theme.QuestionStyle.Write(question);
Theme.UserInputStyle.Write(" ");
text = Theme.UserInputStyle.ReadLine().Trim();
}
while (text == "");
return text;
}
///
/// Writes to the console and prompts the user to input yes ("y") or no ("n").
///
/// A to display before the user input prompt.
///
/// , if the user selected yes;
/// , if the user selected no.
///
public static bool Confirmation(string question)
{
return Confirmation(question, null);
}
///
/// Writes to the console and prompts the user to input yes ("y") or no ("n").
///
/// A to display before the user input prompt.
/// A value that is returned, if the user did not enter any text, or to require the user to input yes or no.
///
/// , if the user selected yes;
/// , if the user selected no.
///
public static bool Confirmation(string question, bool? defaultChoice)
{
Check.ArgumentNull(question);
Check.ArgumentNull(Theme);
Check.ArgumentNull(Theme.QuestionStyle);
Check.ArgumentNull(Theme.UserInputStyle);
Check.ArgumentNull(Theme.ConfirmationPostfix);
Check.ArgumentNull(Theme.ConfirmationPostfixDefaultYes);
Check.ArgumentNull(Theme.ConfirmationPostfixDefaultNo);
Check.ArgumentNull(Theme.ConfirmationAnswerYes);
Check.ArgumentEx.StringNotEmpty(Theme.ConfirmationAnswerYes);
Check.ArgumentNull(Theme.ConfirmationAnswerNo);
Check.ArgumentEx.StringNotEmpty(Theme.ConfirmationAnswerNo);
string defaultChoiceString = defaultChoice switch
{
null => Theme.ConfirmationPostfix,
true => Theme.ConfirmationPostfixDefaultYes,
false => Theme.ConfirmationPostfixDefaultNo
};
Flush();
bool? choice;
do
{
Theme.QuestionStyle.Write($"{question} {defaultChoiceString}?");
Theme.UserInputStyle.Write(" ");
string answer = Theme.UserInputStyle.ReadLine().Trim();
if (answer == "") choice = defaultChoice;
else if (answer.Equals(Theme.ConfirmationAnswerYes, StringComparison.OrdinalIgnoreCase)) choice = true;
else if (answer.Equals(Theme.ConfirmationAnswerNo, StringComparison.OrdinalIgnoreCase)) choice = false;
else choice = null;
}
while (choice == null);
return choice.Value;
}
///
/// Writes and an ordered list with to the console and prompts the user to select an option.
///
/// A to display before the user input prompt.
/// A [] with options that the user can select from.
///
/// A one-based index within that represents the user selection.
///
public static int Select(string question, params string[] options)
{
Check.ArgumentNull(question);
Check.ArgumentNull(options);
Check.ArgumentEx.ArrayValuesNotNull(options);
Check.ArgumentNull(Theme);
Check.ArgumentNull(Theme.QuestionStyle);
Check.ArgumentNull(Theme.SelectOptionsStyle);
Check.ArgumentNull(Theme.UserInputStyle);
Flush();
Theme.QuestionStyle.WriteLine(question);
for (int i = 0; i < options.Length; i++)
{
Theme.SelectOptionsStyle.WriteLine($" [{i + 1}] {options[i]}");
}
while (true)
{
Theme.QuestionStyle.Write(Theme.SelectOptionsPromptText);
Theme.UserInputStyle.Write(" ");
if (Theme.UserInputStyle.ReadLine().ToInt32OrNull() is int selection &&
selection >= 1 &&
selection <= options.Length)
{
return selection;
}
}
}
private static void Flush()
{
// Important: If the user presses return, this would skip a confirmation that appears even a minute later.
// So, flush the input buffer directly before prompting user input.
while (Console.KeyAvailable)
{
Console.ReadKey(true);
}
}
}