using System.Text; namespace Facepunch; /// /// Captures console output while maintaining a buffer of the last N lines /// public class ConsoleOutputCapture : TextWriter { private readonly TextWriter originalOut; private readonly int maxLines; private readonly List outputBuffer; private StringBuilder currentLine = new StringBuilder(); public ConsoleOutputCapture( TextWriter originalOut, int maxLines = 100 ) { this.originalOut = originalOut; this.maxLines = maxLines; this.outputBuffer = new List( maxLines ); } public override Encoding Encoding => originalOut.Encoding; public override void Write( char value ) { // Write to the original output originalOut.Write( value ); // Capture for our buffer if ( value == '\n' ) { // Line completed, add to buffer AddToBuffer( currentLine.ToString() ); currentLine.Clear(); } else if ( value != '\r' ) // Ignore carriage returns { currentLine.Append( value ); } } public override void Write( string value ) { if ( string.IsNullOrEmpty( value ) ) { originalOut.Write( value ); return; } // Write to the original output originalOut.Write( value ); // Process the string for our buffer ProcessString( value ); } public override void WriteLine( string value ) { // Write to the original output originalOut.WriteLine( value ); // Process the string and add a line ProcessString( value ); AddToBuffer( currentLine.ToString() ); currentLine.Clear(); } private void ProcessString( string value ) { int start = 0; int newlinePos; // Process any complete lines in the string while ( (newlinePos = value.IndexOf( '\n', start )) != -1 ) { string line = value.Substring( start, newlinePos - start ); // Trim carriage return if present if ( line.EndsWith( '\r' ) ) { line = line.Substring( 0, line.Length - 1 ); } // Add current buffer + this segment as a line AddToBuffer( currentLine + line ); currentLine.Clear(); start = newlinePos + 1; } // Add any remaining part to the current line buffer if ( start < value.Length ) { currentLine.Append( value.Substring( start ) ); } } private void AddToBuffer( string line ) { outputBuffer.Add( line ); // Keep only the last maxLines if ( outputBuffer.Count > maxLines ) { outputBuffer.RemoveAt( 0 ); } } /// /// Get the captured output as a string with each line separated by newlines /// public string GetCapturedOutput() { return string.Join( "\n", outputBuffer ); } /// /// Get the last n lines of captured output /// /// Number of lines to return /// String containing the last n lines public string GetLastLines( int lineCount ) { if ( lineCount <= 0 || outputBuffer.Count == 0 ) return string.Empty; int startIndex = Math.Max( 0, outputBuffer.Count - lineCount ); return string.Join( "\n", outputBuffer.Skip( startIndex ) ); } /// /// Check if the buffer has any content /// public bool HasContent => outputBuffer.Count > 0; }