using System.Text; namespace Nonemm.Spotting.Telnet; /// Splits the text coming off a telnet stream into lines and keeps the tail /// that has no line ending yet. Cluster nodes write their login prompt without /// one, so the tail has to be readable before the line is finished. public sealed class LineAssembler { private readonly StringBuilder pending = new(); private bool afterCarriageReturn; /// What has arrived since the last line ending. public string Pending => pending.ToString(); /// Breaks on CR, LF or CRLF. Most nodes send CRLF, but N1MM splits on CR /// alone, which says some of them leave the LF out. public IReadOnlyList Add(string text) { List lines = []; foreach (char character in text) { bool wasAfterCarriageReturn = afterCarriageReturn; afterCarriageReturn = character == '\r'; switch (character) { case '\n' when wasAfterCarriageReturn: break; case '\n' or '\r': lines.Add(pending.ToString()); pending.Clear(); break; default: pending.Append(character); break; } } return lines; } public void Clear() { pending.Clear(); afterCarriageReturn = false; } }