private void RenderSourceLine(SourceLine sourceLine)
        {
            var xOffset = buffer.CursorX;

            // Print the source line with a default color
            buffer.ForegroundColor = ConsoleColor.White;
            var line    = sourceLine.Source.Line(sourceLine.Line);
            var lineCur = new LineCursor {
                TabSize = TabSize
            };

            foreach (var ch in line)
            {
                if (ch == '\r' || ch == '\n')
                {
                    break;
                }
                if (lineCur.Append(ch, out var advance))
                {
                    buffer.CursorX += advance;
                }
                else
                {
                    buffer.Write(ch);
                }
            }
            // Do syntax highlighting, if needed
            var tokenInfo = SyntaxHighlighter.GetHighlightingForLine(sourceLine.Source, sourceLine.Line).ToList();

            if (tokenInfo.Count > 0)
            {
                // There are tokens to highlight
                var charIdx = 0;
                lineCur.Column = 0;
                var tokenInfoList = tokenInfo.OrderBy(ti => ti.StartIndex).ToList();
                foreach (var token in tokenInfoList)
                {
                    // Skip until the next token
                    for (; charIdx < token.StartIndex; ++charIdx)
                    {
                        lineCur.Append(line[charIdx], out var advance);
                    }
                    // Go through the token
                    var tokenStart = lineCur.Column;
                    for (; charIdx < token.StartIndex + token.Length; ++charIdx)
                    {
                        lineCur.Append(line[charIdx], out var advance);
                    }
                    var tokenEnd = lineCur.Column;
                    // Recolor the token
                    buffer.ForegroundColor = TokenKindToColor(token.Kind);
                    buffer.Recolor(xOffset + tokenStart, buffer.CursorY, tokenEnd - tokenStart, 1);
                }
            }
            buffer.ResetColor();
        }
        private void RenderAnnotationLines(AnnotationLine annotationLine, string prefix)
        {
            var sourceFile = annotationLine.Annotations.First().Span.Source;

            Debug.Assert(sourceFile != null);
            var line = sourceFile.Line(annotationLine.AnnotatedLine).TrimEnd();

            // Order annotations by starting position
            var annotationsOrdered = annotationLine.Annotations.OrderBy(si => si.Span.Start).ToList();
            // Now we draw the arrows to their correct places under the annotated line
            // Also collect physical column positions to extend the arrows
            var arrowHeadColumns = new List <(int Column, SpannedDiagnosticInfo Info)>();

            buffer.Write(prefix);
            var lineCur = new LineCursor {
                TabSize = TabSize
            };
            var charIdx = 0;

            foreach (var annot in annotationsOrdered)
            {
                // From the last character index until the start of this annotation we need to fill with spaces
                for (; charIdx < annot.Span.Start.Column; ++charIdx)
                {
                    if (charIdx < line.Length)
                    {
                        // Still in range of the line
                        lineCur.Append(line[charIdx], out var advance);
                        buffer.CursorX += advance;
                    }
                    else
                    {
                        // After the line
                        buffer.CursorX += 1;
                    }
                }
                // Now we are inside the span
                var arrowHead   = annot.Severity != null ? '^' : '-';
                var startColumn = buffer.CursorX;
                arrowHeadColumns.Add((startColumn, annot));
                if (annot.Severity != null)
                {
                    buffer.ForegroundColor = annot.Severity.Color;
                }
                for (; charIdx < annot.Span.End.Column; ++charIdx)
                {
                    if (charIdx < line.Length)
                    {
                        // Still in range of the line
                        lineCur.Append(line[charIdx], out var advance);
                        for (int i = 0; i < advance; ++i)
                        {
                            buffer.Write(arrowHead);
                        }
                    }
                    else
                    {
                        // After the line
                        buffer.Write(arrowHead);
                    }
                }
                var endColumn = buffer.CursorX;
                if (annot.Severity != null)
                {
                    // Recolor the source line too
                    buffer.Recolor(startColumn, buffer.CursorY - 1, endColumn - startColumn, 1);
                    buffer.ResetColor();
                }
            }
            // Now we are done with arrows in the line, it's time to do the arrow bodies downwards
            // The first one will have N, the last 0 length bodies, decreasing by one
            // The last one just has the message inline
            {
                var lastAnnot = annotationsOrdered.Last();
                if (lastAnnot.Message != null)
                {
                    buffer.Write($" {lastAnnot.Message}");
                }
                buffer.WriteLine();
            }
            // From now on all previous ones will be one longer than the ones later
            int arrowBaseLine   = buffer.CursorY;
            int arrowBodyLength = 0;

            // We only consider annotations with messages
            foreach (var(col, annot) in arrowHeadColumns.SkipLast(1).Reverse().Where(a => a.Info.Message != null))
            {
                if (annot.Severity != null)
                {
                    buffer.ForegroundColor = annot.Severity.Color;
                }
                // Draw the arrow
                buffer.Fill(col, arrowBaseLine, 1, arrowBodyLength, '│');
                buffer.Plot(col, arrowBaseLine + arrowBodyLength, '└');
                arrowBodyLength += 1;
                // Append the message
                buffer.Write($" {annot.Message}");
                if (annot.Severity != null)
                {
                    buffer.ResetColor();
                }
            }
            // Fill the in between lines with the prefix
            for (int i = 0; i < arrowBodyLength; ++i)
            {
                buffer.WriteAt(0, arrowBaseLine + i, prefix);
            }
            // Reset cursor position
            buffer.CursorX = 0;
            buffer.CursorY = arrowBaseLine + arrowBodyLength;
        }