-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathConsoleInput.cs
More file actions
160 lines (139 loc) · 5.33 KB
/
ConsoleInput.cs
File metadata and controls
160 lines (139 loc) · 5.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using BytecodeApi.Extensions;
namespace BytecodeApi.ConsoleUI;
/// <summary>
/// Class that retrieves user input from the <see cref="Console" /> in form of questions or confirmations.
/// </summary>
public static class ConsoleInput
{
/// <summary>
/// Gets or sets the global theme for the <see cref="ConsoleInput" /> class.
/// </summary>
public static ConsoleInputTheme Theme { get; set; }
static ConsoleInput()
{
Theme = new();
}
/// <summary>
/// Writes <paramref name="question" /> to the console and prompts the user to input a <see cref="string" />. This process is repeated, until the entered <see cref="string" /> is not empty.
/// </summary>
/// <param name="question">A <see cref="string" /> to display before the user input prompt.</param>
/// <returns>
/// The text that the user has entered. This <see cref="string" /> is not empty.
/// </returns>
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;
}
/// <summary>
/// Writes <paramref name="question" /> to the console and prompts the user to input yes ("y") or no ("n").
/// </summary>
/// <param name="question">A <see cref="string" /> to display before the user input prompt.</param>
/// <returns>
/// <see langword="true" />, if the user selected yes;
/// <see langword="false" />, if the user selected no.
/// </returns>
public static bool Confirmation(string question)
{
return Confirmation(question, null);
}
/// <summary>
/// Writes <paramref name="question" /> to the console and prompts the user to input yes ("y") or no ("n").
/// </summary>
/// <param name="question">A <see cref="string" /> to display before the user input prompt.</param>
/// <param name="defaultChoice">A <see cref="bool" /> value that is returned, if the user did not enter any text, or <see langword="null" /> to require the user to input yes or no.</param>
/// <returns>
/// <see langword="true" />, if the user selected yes;
/// <see langword="false" />, if the user selected no.
/// </returns>
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;
}
/// <summary>
/// Writes <paramref name="question" /> and an ordered list with <paramref name="options" /> to the console and prompts the user to select an option.
/// </summary>
/// <param name="question">A <see cref="string" /> to display before the user input prompt.</param>
/// <param name="options">A <see cref="string" />[] with options that the user can select from.</param>
/// <returns>
/// A one-based index within <paramref name="options" /> that represents the user selection.
/// </returns>
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);
}
}
}