Custom Components
About
Its possible to create custom components, for that we only need to extend the
abstract class BaseInputRender<T>
and implement the method Task<T> RequestInput()
.
Then we can register it in the InputRenderProvider
just like any other component
Example
public class InputText<T> : BaseInputRender<T>
{
public Type Target => typeof(T);
/// <summary>
/// Message to show before requesting input
/// </summary>
/// <value></value>
public string Message { get; set; }
/// <summary>
/// Default value to use if no input
/// </summary>
/// <value></value>
public object? DefaultValue { get; set; }
public InputText() {
Message = $"Input value for a {Target}";
}
public override async Task<T> RequestInput()
{
const string BUFFER_NAME = "#INTERNAL.COMPONENT.TEXTINPUT.TOP";
// Write message with default value
Console.WriteLine(BuildMessage());
// Save current console position
ConsoleBuffer.MemoriseBufferPosition(BUFFER_NAME);
T ToObject(string v) => GetConverter().ToObject(v);
while (true) {
try {
var res = Console.ReadLine();
var data = (string.IsNullOrEmpty(res), DefaultValue is null) switch
{
(false, _) => ToObject(res), // is not empty
(true, false) => (T)DefaultValue!, // empty but has default value
(_, _) => ToObject("") // empty without default value
};
var (valid, message) = await Validators.ValidateInput(data);
if (!valid) throw new Exception(message ?? "Error validating input");
// return converted input
return data;
} catch (Exception ex) {
// Write to console
Console.WriteLine(ex.Message + ",\nPress [Return] to retry...");
// Wait user confirmation
Console.ReadKey();
// Clear input and return to question
ConsoleBuffer.ClearBufferFrom(BUFFER_NAME);
}
}
}
private string BuildMessage() {
var converter = GetConverter();
var defaultVal = DefaultValue is null ? "" : $"({converter.ToString(DefaultValue)})";
return $"{Message} {defaultVal}";
}
}