public static LinkedList <CSI_BLOCK> Compile_Command_Blocks(ReadOnlyMemory <char> Data) { // Each escape sequence begins with ESC (0x1B) followed by a single char in the range <64-95>(most often '[') followed by a series of command chars each sperated by a semicolon ';', the entire sequence is ended with a character in the range <64-126>(most often 'm') var RetList = new LinkedList <CSI_BLOCK>(); DataStream <char> Stream = new DataStream <char>(Data, char.MinValue); while (!Stream.atEnd) { int[] Codes = null; byte? FinalByte = null; int BlockStart = Stream.Position; if (Stream.Next == ANSI.CSI) { if (Consume_CSI_Parameters(Stream, out List <int> outCodes, out byte?outFinalByte)) { Codes = outCodes.ToArray(); FinalByte = outFinalByte; } } else { Codes = new int[0]; } /* Consume all text up until the next Control Sequence Initiator */ int TextStart = Stream.Position; bool HasControlChar = false; /* While we are consuming the text we can also check for control chars */ Stream.Consume_While(x => x != ANSI.CSI && !char.IsControl(x)); if (Stream.Next != ANSI.CSI && char.IsControl(Stream.Next)) { HasControlChar = true; Stream.Consume_While(x => x != ANSI.CSI);/* Go to the next CSI */ } int BlockEnd = Stream.Position; int TextLength = BlockEnd - TextStart; var Text = Stream.AsMemory().Slice(TextStart, TextLength); var block = new CSI_BLOCK(FinalByte, Codes, Text, BlockStart, BlockEnd, TextStart, HasControlChar); RetList.AddLast(block); } return(RetList); }