using System.Diagnostics;
using System.Text;
namespace StabilityMatrix.Core.Processes;
///
/// Process supporting parsing of ANSI escape sequences
///
public class AnsiProcess : Process
{
private AsyncStreamReader? stdoutReader;
private AsyncStreamReader? stderrReader;
public AnsiProcess(ProcessStartInfo startInfo)
{
StartInfo = startInfo;
EnableRaisingEvents = false;
StartInfo.UseShellExecute = false;
StartInfo.CreateNoWindow = true;
StartInfo.RedirectStandardOutput = true;
StartInfo.RedirectStandardInput = true;
StartInfo.RedirectStandardError = true;
// Need this to parse ANSI escape sequences correctly
StartInfo.StandardOutputEncoding = Encoding.UTF8;
StartInfo.StandardErrorEncoding = Encoding.UTF8;
StartInfo.StandardInputEncoding = Encoding.UTF8;
}
///
/// Start asynchronous reading of stdout and stderr
///
/// Called on each new line
public void BeginAnsiRead(Action callback)
{
var stdoutStream = StandardOutput.BaseStream;
stdoutReader = new AsyncStreamReader(stdoutStream, s =>
{
if (s == null) return;
callback(ProcessOutput.FromStdOutLine(s));
}, StandardOutput.CurrentEncoding);
var stderrStream = StandardError.BaseStream;
stderrReader = new AsyncStreamReader(stderrStream, s =>
{
if (s == null) return;
callback(ProcessOutput.FromStdErrLine(s));
}, StandardError.CurrentEncoding);
stdoutReader.BeginReadLine();
stderrReader.BeginReadLine();
}
///
/// Waits for output readers to finish
///
public async Task WaitUntilOutputEOF(CancellationToken ct = default)
{
if (stdoutReader is not null)
{
await stdoutReader.EOF.WaitAsync(ct).ConfigureAwait(false);
}
if (stderrReader is not null)
{
await stderrReader.EOF.WaitAsync(ct).ConfigureAwait(false);
}
}
}