Пример #1
0
        // Process '*', '**' or '_', '__'
        // This is horrible and probably much better done through regex, but I'm stubborn.
        // For normal cases this routine works as expected.  For unusual cases (eg: overlapped
        // strong and emphasis blocks), the behaviour is probably not the same as the original
        // markdown scanner.

        /*
         * public Token ProcessEmphasisOld(ref Token prev_single, ref Token prev_double)
         * {
         *      // Check whitespace before/after
         *      bool bSpaceBefore = !bof && IsLineSpace(CharAtOffset(-1));
         *      bool bSpaceAfter = IsLineSpace(CharAtOffset(1));
         *
         *      // Ignore if surrounded by whitespace
         *      if (bSpaceBefore && bSpaceAfter)
         *      {
         *              return null;
         *      }
         *
         *      // Save the current character and skip it
         *      char ch = current;
         *      Skip(1);
         *
         *      // Do we have a previous matching single star?
         *      if (!bSpaceBefore && prev_single != null)
         *      {
         *              // Yes, match them...
         *              prev_single.type = TokenType.open_em;
         *              prev_single = null;
         *              return CreateToken(TokenType.close_em, position - 1, 1);
         *      }
         *
         *      // Is this a double star/under
         *      if (current == ch)
         *      {
         *              // Skip second character
         *              Skip(1);
         *
         *              // Space after?
         *              bSpaceAfter = IsLineSpace(current);
         *
         *              // Space both sides?
         *              if (bSpaceBefore && bSpaceAfter)
         *              {
         *                      // Ignore it
         *                      return CreateToken(TokenType.Text, position - 2, 2);
         *              }
         *
         *              // Do we have a previous matching double
         *              if (!bSpaceBefore && prev_double != null)
         *              {
         *                      // Yes, match them
         *                      prev_double.type = TokenType.open_strong;
         *                      prev_double = null;
         *                      return CreateToken(TokenType.close_strong, position - 2, 2);
         *              }
         *
         *              if (!bSpaceAfter)
         *              {
         *                      // Opening double star
         *                      prev_double = CreateToken(TokenType.Text, position - 2, 2);
         *                      return prev_double;
         *              }
         *
         *              // Ignore it
         *              return CreateToken(TokenType.Text, position - 2, 2);
         *      }
         *
         *      // If there's a space before, we can open em
         *      if (!bSpaceAfter)
         *      {
         *              // Opening single star
         *              prev_single = CreateToken(TokenType.Text, position - 1, 1);
         *              return prev_single;
         *      }
         *
         *      // Ignore
         *      Skip(-1);
         *      return null;
         * }
         */

        // Process auto links eg: <google.com>
        Token ProcessAutoLink()
        {
            if (DisableLinks)
            {
                return(null);
            }

            // Skip the angle bracket and remember the start
            SkipForward(1);
            Mark();

            bool ExtraMode = m_Markdown.ExtraMode;

            // Allow anything up to the closing angle, watch for escapable characters
            while (!eof)
            {
                char ch = current;

                // No whitespace allowed
                if (char.IsWhiteSpace(ch))
                {
                    break;
                }

                // End found?
                if (ch == '>')
                {
                    string url = Utils.UnescapeString(Extract(), ExtraMode);

                    LinkInfo li = null;
                    if (Utils.IsEmailAddress(url))
                    {
                        string link_text;
                        if (url.StartsWith("mailto:"))
                        {
                            link_text = url.Substring(7);
                        }
                        else
                        {
                            link_text = url;
                            url       = "mailto:" + url;
                        }

                        li = new LinkInfo(new LinkDefinition("auto", url, null), link_text);
                    }
                    else if (Utils.IsWebAddress(url))
                    {
                        li = new LinkInfo(new LinkDefinition("auto", url, null), url);
                    }

                    if (li != null)
                    {
                        SkipForward(1);
                        return(CreateToken(TokenType.link, li));
                    }

                    return(null);
                }

                this.SkipEscapableChar(ExtraMode);
            }

            // Didn't work
            return(null);
        }
Пример #2
0
        // Process auto links eg: <google.com>
        Token ProcessAutoLink()
        {
            if (DisableLinks)
                return null;

            // Skip the angle bracket and remember the start
            SkipForward(1);
            Mark();

            bool ExtraMode = m_Markdown.ExtraMode;

            // Allow anything up to the closing angle, watch for escapable characters
            while (!eof)
            {
                char ch = current;

                // No whitespace allowed
                if (char.IsWhiteSpace(ch))
                    break;

                // End found?
                if (ch == '>')
                {
                    string url = Utils.UnescapeString(Extract(), ExtraMode);

                    LinkInfo li = null;
                    if (Utils.IsEmailAddress(url))
                    {
                        string link_text;
                        if (url.StartsWith("mailto:"))
                        {
                            link_text = url.Substring(7);
                        }
                        else
                        {
                            link_text = url;
                            url = "mailto:" + url;
                        }

                        li = new LinkInfo(new LinkDefinition("auto", url, null), link_text);
                    }
                    else if (Utils.IsWebAddress(url))
                    {
                        li=new LinkInfo(new LinkDefinition("auto", url, null), url);
                    }

                    if (li!=null)
                    {
                        SkipForward(1);
                        return CreateToken(TokenType.link, li);
                    }

                    return null;
                }

                this.SkipEscapableChar(ExtraMode);
            }

            // Didn't work
            return null;
        }
Пример #3
0
        internal string MakeID(string str, int start, int len)
        {
            // Parse the string into a list of tokens
            Tokenize(str, start, len);

            StringBuilder sb = new StringBuilder();

            foreach (var t in m_Tokens)
            {
                switch (t.type)
                {
                case TokenType.Text:
                    sb.Append(str, t.startOffset, t.length);
                    break;

                case TokenType.link:
                    LinkInfo li = (LinkInfo)t.data;
                    sb.Append(li.link_text);
                    break;
                }

                FreeToken(t);
            }

            // Now clean it using the same rules as pandoc
            base.Reset(sb.ToString());

            // Skip everything up to the first letter
            while (!eof)
            {
                if (Char.IsLetter(current))
                {
                    break;
                }
                SkipForward(1);
            }

            // Process all characters
            sb.Length = 0;
            while (!eof)
            {
                char ch = current;
                if (char.IsLetterOrDigit(ch) || ch == '_' || ch == '-' || ch == '.')
                {
                    sb.Append(Char.ToLower(ch));
                }
                else if (ch == ' ')
                {
                    sb.Append("-");
                }
                else if (IsLineEnd(ch))
                {
                    sb.Append("-");
                    SkipEol();
                    continue;
                }

                SkipForward(1);
            }

            return(sb.ToString());
        }
Пример #4
0
        // Render a list of tokens to a destinatino string builder.
        private void Render(StringBuilder sb, string str)
        {
            foreach (Token t in m_Tokens)
            {
                switch (t.type)
                {
                case TokenType.Text:
                    // Append encoded text
                    m_Markdown.HtmlEncode(sb, str, t.startOffset, t.length);
                    break;

                case TokenType.HtmlTag:
                    // Append html as is
                    Utils.SmartHtmlEncodeAmps(sb, str, t.startOffset, t.length);
                    break;

                case TokenType.Html:
                case TokenType.opening_mark:
                case TokenType.closing_mark:
                case TokenType.internal_mark:
                    // Append html as is
                    sb.Append(str, t.startOffset, t.length);
                    break;

                case TokenType.br:
                    sb.Append("<br />\n");
                    break;

                case TokenType.open_em:
                    sb.Append("<em>");
                    break;

                case TokenType.close_em:
                    sb.Append("</em>");
                    break;

                case TokenType.open_strong:
                    sb.Append("<strong>");
                    break;

                case TokenType.close_strong:
                    sb.Append("</strong>");
                    break;

                case TokenType.code_span:
                    if (m_Markdown.FormatCodeSpan != null)
                    {
                        var encoded = new StringBuilder();
                        m_Markdown.HtmlEncode(encoded, str, t.startOffset, t.length);

                        sb.Append(m_Markdown.FormatCodeSpan(m_Markdown, encoded.ToString()));
                    }
                    else
                    {
                        sb.Append("<code>");
                        m_Markdown.HtmlEncode(sb, str, t.startOffset, t.length);
                        sb.Append("</code>");
                    }
                    break;

                case TokenType.link:
                {
                    LinkInfo li = (LinkInfo)t.data;
                    var      sf = new SpanFormatter(m_Markdown);
                    sf.DisableLinks = true;

                    li.def.RenderLink(m_Markdown, sb, sf.Format(li.link_text));
                    break;
                }

                case TokenType.img:
                {
                    LinkInfo li = (LinkInfo)t.data;
                    li.def.RenderImg(m_Markdown, sb, li.link_text);
                    break;
                }

                case TokenType.footnote:
                {
                    FootnoteReference r = (FootnoteReference)t.data;
                    sb.Append("<sup id=\"fnref:");
                    sb.Append(r.id);
                    sb.Append("\"><a href=\"#fn:");
                    sb.Append(r.id);
                    sb.Append("\" rel=\"footnote\">");
                    sb.Append(r.index + 1);
                    sb.Append("</a></sup>");
                    break;
                }

                case TokenType.abbreviation:
                {
                    Abbreviation a = (Abbreviation)t.data;
                    sb.Append("<abbr");
                    if (!String.IsNullOrEmpty(a.Title))
                    {
                        sb.Append(" title=\"");
                        m_Markdown.HtmlEncode(sb, a.Title, 0, a.Title.Length);
                        sb.Append("\"");
                    }
                    sb.Append(">");
                    m_Markdown.HtmlEncode(sb, a.Abbr, 0, a.Abbr.Length);
                    sb.Append("</abbr>");
                    break;
                }
                }

                FreeToken(t);
            }
        }
Пример #5
0
        // Process [link] and ![image] directives
        Token ProcessLinkOrImageOrFootnote()
        {
            // Link or image?
            TokenType token_type = SkipChar('!') ? TokenType.img : TokenType.link;

            // Opening '['
            if (!SkipChar('['))
            {
                return(null);
            }

            // Is it a foonote?
            var savepos = position;

            if (m_Markdown.ExtraMode && token_type == TokenType.link && SkipChar('^'))
            {
                SkipLinespace();

                // Parse it
                string id;
                if (SkipFootnoteID(out id) && SkipChar(']'))
                {
                    // Look it up and create footnote reference token
                    int footnote_index = m_Markdown.ClaimFootnote(id);
                    if (footnote_index >= 0)
                    {
                        // Yes it's a footnote
                        return(CreateToken(TokenType.footnote, new FootnoteReference(footnote_index, id)));
                    }
                }

                // Rewind
                position = savepos;
            }

            if (DisableLinks && token_type == TokenType.link)
            {
                return(null);
            }

            bool ExtraMode = m_Markdown.ExtraMode;

            // Find the closing square bracket, allowing for nesting, watching for
            // escapable characters
            Mark();
            int depth = 1;

            while (!eof)
            {
                char ch = current;
                if (ch == '[')
                {
                    depth++;
                }
                else if (ch == ']')
                {
                    depth--;
                    if (depth == 0)
                    {
                        break;
                    }
                }

                this.SkipEscapableChar(ExtraMode);
            }

            // Quit if end
            if (eof)
            {
                return(null);
            }

            // Get the link text and unescape it
            string link_text = Utils.UnescapeString(Extract(), ExtraMode);

            // The closing ']'
            SkipForward(1);

            // Save position in case we need to rewind
            savepos = position;

            // Inline links must follow immediately
            if (SkipChar('('))
            {
                // Extract the url and title
                var link_def = LinkDefinition.ParseLinkTarget(this, null, m_Markdown.ExtraMode);
                if (link_def == null)
                {
                    return(null);
                }

                // Closing ')'
                SkipWhitespace();
                if (!SkipChar(')'))
                {
                    return(null);
                }

                // Create the token
                var li = new LinkInfo(link_def, link_text);
                m_Markdown.AddLinkInfo(li);
                return(CreateToken(token_type, li));
            }

            // Optional space or tab
            if (!SkipChar(' '))
            {
                SkipChar('\t');
            }

            // If there's line end, we're allow it and as must line space as we want
            // before the link id.
            if (eol)
            {
                SkipEol();
                SkipLinespace();
            }

            // Reference link?
            string link_id = null;

            if (current == '[')
            {
                // Skip the opening '['
                SkipForward(1);

                // Find the start/end of the id
                Mark();
                if (!Find(']'))
                {
                    return(null);
                }

                // Extract the id
                link_id = Extract();

                // Skip closing ']'
                SkipForward(1);
            }
            else
            {
                // Rewind to just after the closing ']'
                position = savepos;
            }

            // Link id not specified?
            if (string.IsNullOrEmpty(link_id))
            {
                // Use the link text (implicit reference link)
                link_id = Utils.NormalizeLineEnds(link_text);

                // If the link text has carriage returns, normalize
                // to spaces
                if (!object.ReferenceEquals(link_id, link_text))
                {
                    while (link_id.Contains(" \n"))
                    {
                        link_id = link_id.Replace(" \n", "\n");
                    }
                    link_id = link_id.Replace("\n", " ");
                }
            }

            // Find the link definition abort if not defined
            var def = m_Markdown.GetLinkDefinition(link_id);

            if (def == null)
            {
                return(null);
            }

            // Create a token
            var newLink = new LinkInfo(def, link_text);

            m_Markdown.AddLinkInfo(newLink);
            return(CreateToken(token_type, newLink));
        }
Пример #6
0
        // Render a list of tokens to a destinatino string builder.
        private void Render(StringBuilder sb, string str)
        {
            var reg  = new Regex("<([^ >]+)");
            var tags = new Stack <String>();

            foreach (Token t in m_Tokens)
            {
                switch (t.type)
                {
                case TokenType.Text:
                    // Append encoded text
                    m_Markdown.HtmlEncode(sb, str, t.startOffset, t.length);
                    break;

                case TokenType.HtmlTag:
                    // Append html as is
                    var tag    = str.Substring(t.startOffset, t.length);
                    var mtag   = reg.Match(tag).Groups[1].Value;
                    var mtag_l = mtag.ToLower();
                    if (mtag.StartsWith("/"))
                    {
                        while (tags.Count() > 0)
                        {
                            var ptag = tags.Pop();
                            if (ptag.ToLower() == mtag_l)
                            {
                                Utils.SmartHtmlEncodeAmps(sb, str, t.startOffset, t.length);
                                break;
                            }
                            else
                            {
                                sb.Append("<" + ptag + ">");
                            }
                        }
                    }
                    else
                    {
                        tags.Push("/" + mtag);
                        Utils.SmartHtmlEncodeAmps(sb, str, t.startOffset, t.length);
                    }
                    break;

                case TokenType.Html:
                case TokenType.opening_mark:
                case TokenType.closing_mark:
                case TokenType.internal_mark:
                    // Append html as is
                    sb.Append(str, t.startOffset, t.length);
                    break;

                case TokenType.br:
                    sb.Append("<br />\n");
                    break;

                case TokenType.open_em:
                    sb.Append("<em>");
                    break;

                case TokenType.close_em:
                    sb.Append("</em>");
                    break;

                case TokenType.open_strong:
                    sb.Append("<strong>");
                    break;

                case TokenType.close_strong:
                    sb.Append("</strong>");
                    break;

                case TokenType.code_span:
                    sb.Append("<code>");
                    m_Markdown.HtmlEncode(sb, str, t.startOffset, t.length);
                    sb.Append("</code>");
                    break;

                case TokenType.link:
                {
                    LinkInfo li = (LinkInfo)t.data;
                    var      sf = new SpanFormatter(m_Markdown);
                    sf.DisableLinks = true;

                    li.def.RenderLink(m_Markdown, sb, sf.Format(li.link_text));
                    break;
                }

                case TokenType.img:
                {
                    LinkInfo li = (LinkInfo)t.data;
                    li.def.RenderImg(m_Markdown, sb, li.link_text);
                    break;
                }

                case TokenType.footnote:
                {
                    FootnoteReference r = (FootnoteReference)t.data;
                    sb.Append("<sup id=\"fnref:");
                    sb.Append(r.id);
                    sb.Append("\"><a href=\"#fn:");
                    sb.Append(r.id);
                    sb.Append("\" rel=\"footnote\">");
                    sb.Append(r.index + 1);
                    sb.Append("</a></sup>");
                    break;
                }

                case TokenType.abbreviation:
                {
                    Abbreviation a = (Abbreviation)t.data;
                    sb.Append("<abbr");
                    if (!String.IsNullOrEmpty(a.Title))
                    {
                        sb.Append(" title=\"");
                        m_Markdown.HtmlEncode(sb, a.Title, 0, a.Title.Length);
                        sb.Append("\"");
                    }
                    sb.Append(">");
                    m_Markdown.HtmlEncode(sb, a.Abbr, 0, a.Abbr.Length);
                    sb.Append("</abbr>");
                    break;
                }
                }

                FreeToken(t);
            }

            while (tags.Count() > 0)
            {
                sb.Append("<" + tags.Pop() + ">");
            }
        }
Пример #7
0
        // Render a list of tokens to a destinatino string builder.
        private void Render(StringBuilder sb, string str)
        {
            foreach (Token t in m_Tokens)
            {
                switch (t.type)
                {
                case TokenType.Text:
                    // Append encoded text
                    m_Markdown.HtmlEncode(sb, str, t.startOffset, t.length);
                    break;

                case TokenType.HtmlTag:
                    // Append html as is
                    Utils.SmartHtmlEncodeAmps(sb, str, t.startOffset, t.length);
                    break;

                case TokenType.Html:
                case TokenType.opening_mark:
                case TokenType.closing_mark:
                case TokenType.internal_mark:
                    // Append html as is
                    sb.Append(str, t.startOffset, t.length);
                    break;

                case TokenType.br:
                    sb.Append("<br />\n");
                    break;

                case TokenType.open_em:
                    sb.Append("<em>");
                    break;

                case TokenType.close_em:
                    sb.Append("</em>");
                    break;

                case TokenType.open_strong:
                    sb.Append("<strong>");
                    break;

                case TokenType.close_strong:
                    sb.Append("</strong>");
                    break;

                case TokenType.code_span:
                    sb.Append("<code>");
                    m_Markdown.HtmlEncode(sb, str, t.startOffset, t.length);
                    sb.Append("</code>");
                    break;

                case TokenType.link:
                {
                    LinkInfo li = (LinkInfo)t.data;
                    li.RenderLink(m_Markdown, sb);
                    break;
                }

                case TokenType.img:
                {
                    LinkInfo li = (LinkInfo)t.data;
                    li.RenderImage(m_Markdown, sb);
                    break;
                }

                case TokenType.footnote:
                {
                    FootnoteReference r = (FootnoteReference)t.data;
                    sb.Append("<sup id=\"fnref:");
                    sb.Append(r.id);
                    sb.Append("\"><a href=\"#fn:");
                    sb.Append(r.id);
                    sb.Append("\" rel=\"footnote\">");
                    sb.Append(r.index + 1);
                    sb.Append("</a></sup>");
                    break;
                }

                case TokenType.abbreviation:
                {
                    Abbreviation a = (Abbreviation)t.data;
                    sb.Append("<abbr");
                    if (!String.IsNullOrEmpty(a.Title))
                    {
                        sb.Append(" title=\"");
                        m_Markdown.HtmlEncode(sb, a.Title, 0, a.Title.Length);
                        sb.Append("\"");
                    }
                    sb.Append(">");
                    m_Markdown.HtmlEncode(sb, a.Abbr, 0, a.Abbr.Length);
                    sb.Append("</abbr>");
                    break;
                }

                // DocNet Extensions
                case TokenType.font_awesome:
                    sb.Append("<i class=\"fas fa-");
                    m_Markdown.HtmlEncode(sb, str, t.startOffset, t.length);
                    sb.Append("\"></i>");
                    break;

                // HnD Extensions
                case TokenType.strikethrough_span:
                    sb.Append("<s>");
                    m_Markdown.HtmlEncode(sb, str, t.startOffset, t.length);
                    sb.Append("</s>");
                    break;

                case TokenType.emoji:
                    var emojiFilename = string.Empty;
                    var emojiName     = t.data as string ?? string.Empty;
                    if (m_Markdown.EmojiFilePerName != null)
                    {
                        m_Markdown.EmojiFilePerName.TryGetValue(emojiName, out emojiFilename);
                    }
                    if (string.IsNullOrWhiteSpace(emojiFilename))
                    {
                        sb.Append(":");
                        m_Markdown.HtmlEncode(sb, emojiName, 0, emojiName.Length);
                        sb.Append(":");
                    }
                    else
                    {
                        sb.Append("<img src=\"");
                        sb.Append(emojiFilename);
                        sb.Append("\" class=\"emoji\" alt=\"");
                        sb.Append(emojiName);
                        sb.Append("\"/>");
                    }
                    break;
                }

                FreeToken(t);
            }
        }
Пример #8
0
 internal void AddLinkInfo(LinkInfo link)
 {
     m_FoundLinks.Add(link);
 }
Пример #9
0
        // Process [link] and ![image] directives
        Token ProcessLinkOrImageOrFootnote()
        {
            // Link or image?
            TokenType token_type = SkipChar('!') ? TokenType.img : TokenType.link;

            // Opening '['
            if (!SkipChar('['))
                return null;

            // Is it a foonote?
            var savepos=position;
            if (m_Markdown.ExtraMode && token_type==TokenType.link && SkipChar('^'))
            {
                SkipLinespace();

                // Parse it
                string id;
                if (SkipFootnoteID(out id) && SkipChar(']'))
                {
                    // Look it up and create footnote reference token
                    int footnote_index = m_Markdown.ClaimFootnote(id);
                    if (footnote_index >= 0)
                    {
                        // Yes it's a footnote
                        return CreateToken(TokenType.footnote, new FootnoteReference(footnote_index, id));
                    }
                }

                // Rewind
                position = savepos;
            }

            if (DisableLinks && token_type==TokenType.link)
                return null;

            bool ExtraMode = m_Markdown.ExtraMode;

            // Find the closing square bracket, allowing for nesting, watching for
            // escapable characters
            Mark();
            int depth = 1;
            while (!eof)
            {
                char ch = current;
                if (ch == '[')
                {
                    depth++;
                }
                else if (ch == ']')
                {
                    depth--;
                    if (depth == 0)
                        break;
                }

                this.SkipEscapableChar(ExtraMode);
            }

            // Quit if end
            if (eof)
                return null;

            // Get the link text and unescape it
            string link_text = Utils.UnescapeString(Extract(), ExtraMode);

            // The closing ']'
            SkipForward(1);

            // Save position in case we need to rewind
            savepos = position;

            // Inline links must follow immediately
            if (SkipChar('('))
            {
                // Extract the url and title
                var link_def = LinkDefinition.ParseLinkTarget(this, null, m_Markdown.ExtraMode);
                if (link_def==null)
                    return null;

                // Closing ')'
                SkipWhitespace();
                if (!SkipChar(')'))
                    return null;

                // Create the token
                var li = new LinkInfo(link_def, link_text);
                m_Markdown.AddLinkInfo(li);
                return CreateToken(token_type, li);
            }

            // Optional space or tab
            if (!SkipChar(' '))
                SkipChar('\t');

            // If there's line end, we're allow it and as must line space as we want
            // before the link id.
            if (eol)
            {
                SkipEol();
                SkipLinespace();
            }

            // Reference link?
            string link_id = null;
            if (current == '[')
            {
                // Skip the opening '['
                SkipForward(1);

                // Find the start/end of the id
                Mark();
                if (!Find(']'))
                    return null;

                // Extract the id
                link_id = Extract();

                // Skip closing ']'
                SkipForward(1);
            }
            else
            {
                // Rewind to just after the closing ']'
                position = savepos;
            }

            // Link id not specified?
            if (string.IsNullOrEmpty(link_id))
            {
                // Use the link text (implicit reference link)
                link_id = Utils.NormalizeLineEnds(link_text);

                // If the link text has carriage returns, normalize
                // to spaces
                if (!object.ReferenceEquals(link_id, link_text))
                {
                    while (link_id.Contains(" \n"))
                        link_id = link_id.Replace(" \n", "\n");
                    link_id = link_id.Replace("\n", " ");
                }
            }

            // Find the link definition abort if not defined
            var def = m_Markdown.GetLinkDefinition(link_id);
            if (def == null)
                return null;

            // Create a token
            var newLink = new LinkInfo(def, link_text);
            m_Markdown.AddLinkInfo(newLink);
            return CreateToken(token_type, newLink);
        }
Пример #10
0
 internal void AddLinkInfo(LinkInfo link)
 {
     m_FoundLinks.Add(link);
 }
Пример #11
0
        // Render a list of tokens to a destinatino string builder.
        private void Render(StringBuilder sb, string str)
        {
            foreach (Token t in m_Tokens)
            {
                switch (t.type)
                {
                case TokenType.Text:
                    // Append encoded text
                    m_Markdown.HtmlEncode(sb, str, t.startOffset, t.length);
                    break;

                case TokenType.HtmlTag:
                    // Append html as is
                    Utils.SmartHtmlEncodeAmps(sb, str, t.startOffset, t.length);
                    break;

                case TokenType.Html:
                case TokenType.opening_mark:
                case TokenType.closing_mark:
                case TokenType.internal_mark:
                    // Append html as is
                    sb.Append(str, t.startOffset, t.length);
                    break;

                case TokenType.br:
                    sb.Append("<br />\n");
                    break;

                case TokenType.open_em:
                    sb.Append("<em>");
                    break;

                case TokenType.close_em:
                    sb.Append("</em>");
                    break;

                case TokenType.open_strong:
                    sb.Append("<strong>");
                    break;

                case TokenType.close_strong:
                    sb.Append("</strong>");
                    break;

                case TokenType.code_span:
                    sb.Append("<code>");
                    m_Markdown.HtmlEncode(sb, str, t.startOffset, t.length);
                    sb.Append("</code>");
                    break;

                case TokenType.link:
                {
                    LinkInfo li = (LinkInfo)t.data;
                    li.RenderLink(m_Markdown, sb);
                    break;
                }

                case TokenType.img:
                {
                    LinkInfo li = (LinkInfo)t.data;
                    li.RenderImage(m_Markdown, sb);
                    break;
                }

                case TokenType.footnote:
                {
                    FootnoteReference r = (FootnoteReference)t.data;
                    sb.Append("<sup id=\"fnref:");
                    sb.Append(r.id);
                    sb.Append("\"><a href=\"#fn:");
                    sb.Append(r.id);
                    sb.Append("\" rel=\"footnote\">");
                    sb.Append(r.index + 1);
                    sb.Append("</a></sup>");
                    break;
                }

                case TokenType.abbreviation:
                {
                    Abbreviation a = (Abbreviation)t.data;
                    sb.Append("<abbr");
                    if (!String.IsNullOrEmpty(a.Title))
                    {
                        sb.Append(" title=\"");
                        m_Markdown.HtmlEncode(sb, a.Title, 0, a.Title.Length);
                        sb.Append("\"");
                    }
                    sb.Append(">");
                    m_Markdown.HtmlEncode(sb, a.Abbr, 0, a.Abbr.Length);
                    sb.Append("</abbr>");
                    break;
                }

                case TokenType.font_awesome:
                    sb.Append("<i class=\"fa fa-");
                    sb.Append(str, t.startOffset, t.length);
                    sb.Append("\"></i>");
                    break;
                }

                FreeToken(t);
            }
        }