V1 / 8f6c47b125e8
TextLogSink.cs
Lilith/Core/Logging/TextLogSink.cs
Changed in this versionCS
namespace Lilith.Core.Logging;
/// <summary>Renders log types consistently; files retain the last update of each progress phase.</summary>
public sealed class TextLogSink(TextWriter writer, bool overwriteProgress = false, Func<int>? width = null)
{
private readonly object _sync = new();
private string? _progress;
private int _drawnLength;
private bool _inputActive;
private readonly List<LogEntry> _deferred = [];
/// <summary>Defer background output until the current console input has finished.</summary>
public IDisposable BeginInput()
{
lock (_sync)
{
if (_inputActive) throw new InvalidOperationException("Console input is already active.");
FinishProgress();
_inputActive = true;
return new TextLogInputLease(EndInput);
}
}
public void Handle(LogEntry entry)
{
lock (_sync)
{
if (_inputActive && !(entry.Sender == "Input" && entry.Type == LogType.Write))
{
if (entry.Type == LogType.Progress && _deferred.Count > 0 &&
_deferred[^1].Type == LogType.Progress && _deferred[^1].Sender == entry.Sender)
_deferred[^1] = entry;
else _deferred.Add(entry);
return;
}
if (entry.Type == LogType.Progress)
{
_progress = entry.Description;
if (overwriteProgress)
{
int available = Math.Max(1, width?.Invoke() ?? 120);
string text = entry.Description.Replace('\r', ' ').Replace('\n', ' ');
if (text.Length > available) text = text[..available];
writer.Write("\r" + text.PadRight(Math.Min(available, Math.Max(_drawnLength, text.Length))));
_drawnLength = text.Length;
writer.Flush();
}
return;
}
FinishProgress();
if (entry.Type == LogType.Write) writer.Write(entry.Description);
else writer.WriteLine(entry.Description);
writer.Flush();
}
}
public void Flush()
{
lock (_sync)
{
FinishProgress();
writer.Flush();
}
}
private void FinishProgress()
{
if (_progress is null) return;
if (overwriteProgress) writer.WriteLine();
else writer.WriteLine(_progress);
_progress = null;
_drawnLength = 0;
}
private void EndInput()
{
lock (_sync)
{
_inputActive = false;
if (_deferred.Count > 0) writer.WriteLine();
foreach (var entry in _deferred) Handle(entry);
_deferred.Clear();
}
}
}