예제 #1
0
        void WriteSingleInline(ref Inline inline, char [] escapeChars)
        {
            switch (inline.Tag)
            {
            case InlineTag.Emphasis:
            case InlineTag.Strong:
                var delimeterChar = inline.Emphasis.DelimiterCharacter;
                if (delimeterChar == char.MinValue)
                {
                    delimeterChar = '_';
                }
                var delimeter = new string (
                    delimeterChar,
                    inline.Tag == InlineTag.Emphasis ? 1 : 2);
                writer.WriteLiteral(delimeter);
                WriteInline(inline.FirstChild);
                writer.WriteLiteral(delimeter);
                break;

            case InlineTag.Strikethrough:
                writer.WriteLiteral("~~");
                WriteInline(inline.FirstChild);
                writer.WriteLiteral("~~");
                break;

            case InlineTag.Placeholder:
                writer.WriteLiteral('[');
                writer.WriteEscaped(inline.TargetUrl);
                writer.WriteLiteral(']');
                break;

            case InlineTag.Link:
            case InlineTag.Image:
                // for writing out autolinks, we use this potentially stripped
                // URL so we can round-trip email address autolinks.
                var targetUrl = inline.TargetUrl;
                if (targetUrl.StartsWith("mailto:", StringComparison.Ordinal))
                {
                    targetUrl = targetUrl.Substring(7);
                }

                // translate links where the target URL and the content are
                // the same (and no title is specified) into <autolinks>
                if (inline.Tag == InlineTag.Link &&
                    string.IsNullOrEmpty(inline.LiteralContent) &&
                    inline.FirstChild != null &&
                    inline.FirstChild.Tag == InlineTag.String &&
                    inline.FirstChild.NextSibling == null &&
                    inline.FirstChild.LiteralContent == targetUrl)
                {
                    writer.WriteLiteral('<');
                    writer.WriteEscaped(targetUrl);
                    writer.WriteLiteral('>');
                    break;
                }

                // the only difference between a link and an image is ^!
                if (inline.Tag == InlineTag.Image)
                {
                    writer.WriteLiteral('!');
                }

                writer.WriteLiteral('[');
                WriteInline(inline.FirstChild, '[', ']');
                writer.WriteLiteral(']');
                writer.WriteLiteral('(');
                writer.WriteEscaped(inline.TargetUrl, '(', ')');
                if (!string.IsNullOrEmpty(inline.LiteralContent))
                {
                    writer.WriteLiteral(" \"");
                    writer.WriteEscaped(inline.LiteralContent, '"', '(', ')');
                    writer.WriteLiteral('"');
                }
                writer.WriteLiteral(')');
                break;

            case InlineTag.Code:
                if (string.IsNullOrEmpty(inline.LiteralContent))
                {
                    writer.WriteLiteral("` `");
                    break;
                }

                var contentLength = inline.LiteralContent.Length;
                var wrapSize      = MaxConsecutiveCharCount(inline.LiteralContent, '`') + 1;

                writer.WriteLiteral('`', wrapSize);

                if (contentLength > 0 && inline.LiteralContent [0] == '`')
                {
                    writer.WriteLiteral(' ');
                }

                writer.WriteLiteral(inline.LiteralContent);

                if (contentLength > 0 && inline.LiteralContent [contentLength - 1] == '`')
                {
                    writer.WriteLiteral(' ');
                }

                writer.WriteLiteral('`', wrapSize);
                break;

            case InlineTag.RawHtml:
                writer.WriteLiteral(inline.LiteralContent);
                break;

            case InlineTag.LineBreak:
                writer.WriteLiteral('\\');
                writer.WriteLineLiteral();
                break;

            case InlineTag.SoftBreak:
                writer.WriteLineLiteral();
                var next = inline.NextSibling;
                if (next != null &&
                    next.Tag == InlineTag.String &&
                    !string.IsNullOrEmpty(next.LiteralContent))
                {
                    switch (next.LiteralContent [0])
                    {
                    case '#':
                    case '-':
                    case '>':
                    case '*':
                    case '=':
                        writer.WriteLiteral(' ', 4);
                        break;
                    }
                }
                break;

            case InlineTag.String:
                var content = inline.LiteralContent;
                if (string.IsNullOrEmpty(content))
                {
                    break;
                }

                // CommonMark.NET and the CommonMark JS reference parser appear
                // to yield single-character string inlines for characters that
                // need escaping. Therefore, we only attempt to escape these
                // strings, and not the first character on a string of an arbitray
                // length.
                switch (content)
                {
                case "*":
                case "_":
                case ">":
                case "-":
                case "#":
                case "\\":
                case "[":
                case "`":
                case "<":
                    writer.WriteEscaped(content [0]);
                    break;

                case "!":
                    if (inline.NextSibling != null &&
                        inline.NextSibling.Tag == InlineTag.Link)
                    {
                        writer.WriteEscaped('!');
                    }
                    else
                    {
                        writer.WriteLiteral('!');
                    }
                    break;

                default:
                    // match this inline and a next for escaped ordered list
                    // syntax: ^\d+[\.\)]$ - if the two sibling inlines match,
                    // we want to escape the list delimeter.
                    if (inline.NextSibling != null && content.Length < 9 && (
                            inline.NextSibling.LiteralContent == "." ||
                            inline.NextSibling.LiteralContent == ")"))
                    {
                        var allDigits = true;

                        for (int i = 0; i < content.Length; i++)
                        {
                            if (!char.IsDigit(content [i]))
                            {
                                allDigits = false;
                                break;
                            }
                        }

                        if (allDigits)
                        {
                            writer.WriteLiteral(content);
                            // this will skip over the delimeter inline on the
                            // next outer loop iteration since we're handling it
                            // here (escaping it).
                            inline = inline.NextSibling;
                            writer.WriteEscaped(inline.LiteralContent [0]);
                            break;
                        }
                    }

                    writer.WriteEscaped(content, escapeChars);
                    break;
                }
                break;

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