#nullable enable
namespace Terminal.Gui;
///
/// Describes an ongoing ANSI request sent to the console.
/// Send a request using which will return the response.
///
public class AnsiEscapeSequenceRequest
{
internal readonly object _responseLock = new (); // Per-instance lock
///
/// Gets the response received from the request.
///
public AnsiEscapeSequenceResponse? AnsiEscapeSequenceResponse { get; internal set; }
///
/// The value expected in the response after the CSI e.g.
///
/// EscSeqUtils.CSI_ReportTerminalSizeInChars.Value
///
/// should result in a response of the form ESC [ 8 ; height ; width t. In this case,
///
/// will be "8".
///
public string? ExpectedResponseValue { get; init; }
///
/// Gets the request string to send e.g. see
///
/// EscSeqUtils.CSI_SendDeviceAttributes.Request
///
///
public required string Request { get; init; }
///
///
/// Gets the terminator that uniquely identifies the response received from
/// the console. e.g. for
///
/// EscSeqUtils.CSI_SendDeviceAttributes.Request
///
/// the terminator is
///
/// EscSeqUtils.CSI_SendDeviceAttributes.Terminator
///
/// .
///
///
/// After sending a request, the first response with matching terminator will be matched
/// to the oldest outstanding request.
///
///
public required string Terminator { get; init; }
internal void RaiseResponseFromInput (string? response)
{
ProcessResponse (response);
ResponseFromInput?.Invoke (this, AnsiEscapeSequenceResponse);
}
///
/// Raised with the response object and validation.
///
internal event EventHandler? ResponseFromInput;
///
/// Process the of an ANSI escape sequence request.
///
/// The response.
private void ProcessResponse (string? response)
{
var error = new StringBuilder ();
var values = new string? [] { null };
try
{
if (!string.IsNullOrEmpty (response) && !response.StartsWith (AnsiEscapeSequenceRequestUtils.KeyEsc))
{
throw new InvalidOperationException ($"Invalid Response: {response}");
}
if (string.IsNullOrEmpty (Terminator))
{
throw new InvalidOperationException ("Terminator request is empty.");
}
if (string.IsNullOrEmpty (response))
{
throw new InvalidOperationException ("Response request is null.");
}
if (!string.IsNullOrEmpty (response) && !response.EndsWith (Terminator [^1]))
{
string resp = string.IsNullOrEmpty (response) ? "" : response.Last ().ToString ();
throw new InvalidOperationException ($"Terminator ends with '{resp}'\nand doesn't end with: '{Terminator [^1]}'");
}
}
catch (Exception ex)
{
error.AppendLine ($"Error executing ANSI request:\n{ex.Message}");
}
finally
{
if (string.IsNullOrEmpty (error.ToString ()))
{
(string? _, string? _, values, string? _) = AnsiEscapeSequenceRequestUtils.GetEscapeResult (response?.ToCharArray ());
}
}
AnsiEscapeSequenceResponse = new ()
{
Response = response, Error = error.ToString (),
Terminator = string.IsNullOrEmpty (response) ? "" : response [^1].ToString (),
ExpectedResponseValue = values [0],
Valid = string.IsNullOrWhiteSpace (error.ToString ()) && !string.IsNullOrWhiteSpace (response)
};
}
}