void WriteSingleBlock()

in Clients/Xamarin.Interactive.Client/CommonMark/MarkdownFormatter.cs [156:312]


        void WriteSingleBlock (Block block)
        {
            switch (block.Tag) {
            case BlockTag.Document:
                WriteBlock (block.FirstChild);
                break;

            case BlockTag.ReferenceDefinition:
                // FIXME: these are completely broken in CommonMark.NET as it
                // only persists reference definitions on the document (root)
                // node, which means all context is lost regarding _where_ in
                // the document a reference definition exists. The block here
                // is completely empty. Additionally, it upper-cases the keys
                // the reference dictionary, which means they also cannot be
                // round-tripped correctly :(
                //
                // However - we can still write out _mostly_ semantically
                // identical (e.g. functional) markdown since CommonMark.NET's
                // link inlines will have the resolved URLs.
                break;

            case BlockTag.BlockQuote:
                writer.PushLinePrefix ("> ");
                WriteBlock (block.FirstChild);
                writer.PopLinePrefix ();
                break;

            case BlockTag.Paragraph:
                WriteInline (block.InlineContent);
                break;

            case BlockTag.AtxHeading:
                writer.WriteLiteral ('#', block.Heading.Level);
                writer.WriteLiteral (' ');
                WriteInline (block.InlineContent);
                break;

            case BlockTag.SetextHeading:
                var startPosition = writer.Position;
                WriteInline (block.InlineContent);
                var inlineLength = writer.Position - startPosition;
                var underlineLength = (int)block.Heading.SetextUnderlineLength;
                if (underlineLength < 1)
                    underlineLength = inlineLength;
                writer.WriteLineLiteral ();
                writer.WriteLiteral (block.Heading.Level == 1 ? '=' : '-', underlineLength);
                break;

            case BlockTag.ThematicBreak:
                var breakChar = settings.ThematicBreakChar;
                var listData = block.Parent?.ListData;
                if (listData != null && listData.BulletChar == breakChar) {
                    if (breakChar == '*')
                        breakChar = '-';
                    else if (breakChar == '-')
                        breakChar = '*';
                }
                writer.WriteLiteral (breakChar, settings.ActualThematicBreakWidth);
                break;

            case BlockTag.FencedCode:
            case BlockTag.YamlBlock:
                var content = block.StringContent.ToString ();
                var fenceOffset = block.FencedCodeData.FenceOffset;
                var fenceChar = block.FencedCodeData.FenceChar;
                var fenceSize = Math.Max (3, MaxConsecutiveCharCount (content, fenceChar) + 1);

                writer.WriteLiteral (' ', fenceOffset);
                writer.WriteLiteral (fenceChar, fenceSize);
                if (!string.IsNullOrEmpty (block.FencedCodeData.Info))
                    writer.WriteLiteral (block.FencedCodeData.Info);
                writer.WriteLineLiteral ();

                if (fenceOffset > 0)
                    writer.PushLinePrefix (new string (' ', block.FencedCodeData.FenceOffset));

                writer.WriteLiteral (content);

                if (fenceOffset > 0)
                    writer.PopLinePrefix ();

                writer.WriteLiteral (' ', fenceOffset);
                writer.WriteLiteral (fenceChar, fenceSize);
                break;

            case BlockTag.IndentedCode:
                writer.PushLinePrefix ("    ");
                // FIXME: RemoveTrailingBlankLines appears to be broken.
                // TrimEnd works, but that's not exactly what we want.
                // Workaround is to convert to a string first, which is
                // is a bit of a perf hit.
                //
                // block.StringContent.RemoveTrailingBlankLines ();
                // block.StringContent.WriteTo (writer);
                writer.WriteLiteral (block.StringContent.ToString ().TrimEnd ('\n', '\r'));
                writer.PopLinePrefix ();
                break;

            case BlockTag.HtmlBlock:
                // FIXME: see comment for IndentedCode case
                writer.WriteLiteral (block.StringContent.ToString ().TrimEnd ('\n', '\r'));
                break;

            case BlockTag.List:
                WriteBlock (block.FirstChild);
                break;

            case BlockTag.ListItem:
                // FIXME: we could compute the ordered list information in the
                // BlockTag.List case above and pass via WriteBlock, but I wanted
                // to keep it simple. Could be an ever-so-slight perf improvement.
                var orderedIndex = block.ListData.Start;
                char orderedDelimiter;
                switch (block.ListData.Delimiter) {
                case ListDelimiter.Period:
                    orderedDelimiter = '.';
                    break;
                case ListDelimiter.Parenthesis:
                    orderedDelimiter = ')';
                    break;
                default:
                    throw new NotImplementedException (
                        $"{nameof (ListDelimiter)}.{block.ListData.Delimiter}");
                }

                string marker;
                switch (block.ListData.ListType) {
                case ListType.Bullet:
                    marker = block.ListData.BulletChar.ToString ();
                    break;
                case ListType.Ordered:
                    marker = (orderedIndex++).ToString (CultureInfo.InvariantCulture)
                        + orderedDelimiter;
                    break;
                default:
                    throw new NotImplementedException (
                        $"{nameof (ListType)}.{block.ListData.ListType}");
                }

                writer.WriteLiteral (' ', block.ListData.MarkerOffset);
                writer.WriteLiteral (marker);
                writer.WriteLiteral (' ', block.ListData.Padding - marker.Length);

                var padding = block.ListData.Padding + block.ListData.MarkerOffset;
                if (padding > 0)
                    writer.PushLinePrefix (new string (' ', padding), false);

                WriteBlock (block.FirstChild);

                if (padding > 0)
                    writer.PopLinePrefix ();
                break;

            default:
                throw new NotImplementedException ($"{block.Tag}");
            }
        }