internal string MakeUniqueHeaderID(string strHeaderText, int startOffset, int length) { if (!AutoHeadingIDs) { return(null); } // Extract a pandoc style cleaned header id from the header text var strBase = SpanFormatter.MakeID(strHeaderText, startOffset, length); // If nothing left, use "section" if (string.IsNullOrEmpty(strBase)) { strBase = "section"; } // Make sure it's unique by append -n counter var strWithSuffix = strBase; var counter = 1; while (_mUsedHeaderIDs.ContainsKey(strWithSuffix)) { strWithSuffix = strBase + "-" + counter; counter++; } // Store it _mUsedHeaderIDs.Add(strWithSuffix, true); // Return it return(strWithSuffix); }
public void RenderLink(Markdown m, StringBuilder sb) { var sf = new SpanFormatter(m); sf.DisableLinks = true; this.Definition.RenderLink(m, sb, sf.Format(this.LinkText), this.SpecialAttributes); }
// Constructor public Markdown() { HtmlClassFootnotes = "footnotes"; m_StringBuilder = new StringBuilder(); m_StringScanner = new StringScanner(); m_SpanFormatter = new SpanFormatter(this); m_LinkDefinitions = new Dictionary <string, LinkDefinition>(StringComparer.CurrentCultureIgnoreCase); m_Footnotes = new Dictionary <string, Block>(); m_UsedFootnotes = new List <Block>(); m_UsedHeaderIDs = new Dictionary <string, bool>(); }
// Constructor public Markdown() { HtmlClassFootnotes = "footnotes"; m_StringBuilder = new StringBuilder(); m_StringScanner = new StringScanner(); m_SpanFormatter = new SpanFormatter(this); m_LinkDefinitions = new Dictionary<string, LinkDefinition>(StringComparer.CurrentCultureIgnoreCase); m_Footnotes = new Dictionary<string, Block>(); m_UsedFootnotes = new List<Block>(); m_UsedHeaderIDs = new Dictionary<string, bool>(); }
// Constructor public Markdown() { HtmlClassFootnotes = "footnotes"; m_StringBuilder = new StringBuilder(); m_StringBuilderFinal = new StringBuilder(); m_StringScanner = new StringScanner(); m_SpanFormatter = new SpanFormatter(this); m_LinkDefinitions = new Dictionary<string, LinkDefinition>(StringComparer.CurrentCultureIgnoreCase); m_Footnotes = new Dictionary<string, Block>(); m_UsedFootnotes = new List<Block>(); m_UsedHeaderIDs = new Dictionary<string, bool>(); this.CreatedH2IdCollector = new List<Tuple<string, string>>(); _tabIdCounter = 0; }
// Constructor public Markdown() { HtmlClassFootnotes = "footnotes"; m_StringBuilder = new StringBuilder(); m_StringBuilderFinal = new StringBuilder(); m_StringScanner = new StringScanner(); m_SpanFormatter = new SpanFormatter(this); m_LinkDefinitions = new Dictionary <string, LinkDefinition>(StringComparer.CurrentCultureIgnoreCase); m_Footnotes = new Dictionary <string, Block>(); m_UsedFootnotes = new List <Block>(); m_UsedHeaderIDs = new Dictionary <string, bool>(); this.CreatedH2IdCollector = new List <Tuple <string, string> >(); _tabIdCounter = 0; }
// Constructor public Markdown() { HtmlClassFootnotes = "footnotes"; m_StringBuilder = new StringBuilder(); m_StringBuilderFinal = new StringBuilder(); m_StringScanner = new StringScanner(); m_SpanFormatter = new SpanFormatter(this); m_LinkDefinitions = new Dictionary <string, LinkDefinition>(StringComparer.CurrentCultureIgnoreCase); m_Footnotes = new Dictionary <string, Block>(); m_UsedFootnotes = new List <Block>(); m_UsedHeaderIDs = new Dictionary <string, bool>(); m_FoundLinks = new List <ILinkInfo>(); EncodeUnsafeHtml = true; ActiveRenderer = new Formats.RenderToHtml(); }
public void SetUp() { m = new Markdown(); s = new SpanFormatter(m); }
// 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) { 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); // @kamranayub: Nested images SpanFormatter nestedFormatter = new SpanFormatter(this.m_Markdown); if (link_text.Length > 2 && link_text.IndexOf('!') == 0 && link_text.IndexOf('[') == 1) { link_text = nestedFormatter.Format(link_text); } // 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 return(CreateToken(token_type, new LinkInfo(link_def, link_text))); } // 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 return(CreateToken(token_type, new LinkInfo(def, link_text))); }
public void SetUp() { f = new SpanFormatter(new Markdown()); }
// 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; 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); } }
public void combined_18() { var fExtra = new SpanFormatter(new Markdown() { ExtraMode = true }); Assert.AreEqual("<em>Emphasis</em>, trailing", fExtra.Format("_Emphasis_, trailing")); }
public void combined_17() { var fExtra = new SpanFormatter(new Markdown() { ExtraMode = true }); Assert.AreEqual("<strong>Bold</strong> <em>Italic</em>", fExtra.Format("__Bold__ _Italic_")); }
// 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) 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); // @kamranayub: Nested images SpanFormatter nestedFormatter = new SpanFormatter(this.m_Markdown); if (link_text.Length > 2 && link_text.IndexOf('!') == 0 && link_text.IndexOf('[') == 1) { link_text = nestedFormatter.Format(link_text); } // 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 return CreateToken(token_type, new LinkInfo(link_def, link_text)); } // 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 return CreateToken(token_type, new LinkInfo(def, link_text)); }
// 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; 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); } }
// 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() + ">"); } }
public void InlineLinkWithoutTitleWithSpecialAttributes() { var m = GetSetupMarkdown(); m.ExtraMode = true; var s = new SpanFormatter(m); Assert.AreEqual("pre <a href=\"url.com\" id=\"foo\" class=\"a b cl\" lang=\"nl\">link text</a> post", s.Format("pre [link text](url.com){#foo .a .b .cl lang=nl} post")); }
public void SetUp() { _formatter = new SpanFormatter(GetSetupMarkdown()); }
public void InlineImgWithoutTitleWithSpecialAttributes() { var m = GetSetupMarkdown(); m.ExtraMode = true; var s = new SpanFormatter(m); Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" id=\"foo\" class=\"a b cl\" lang=\"nl\" /> post", s.Format("pre ![alt text](url.com/image.png){#foo .a .b .cl lang=nl} post")); }
public void SetUp() { m = new Markdown(); m.AddLinkDefinition(new LinkDefinition("link1", "url.com", "title")); m.AddLinkDefinition(new LinkDefinition("link2", "url.com")); m.AddLinkDefinition(new LinkDefinition("img1", "url.com/image.png", "title")); m.AddLinkDefinition(new LinkDefinition("img2", "url.com/image.png")); s = new SpanFormatter(m); }
// Render a list of tokens to a destination string builder. private void Render(StringBuilder sb, string str) { foreach (var t in _mTokens) { switch (t.Type) { case TokenType.Text: // Append encoded text _mMarkdown.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>"); _mMarkdown.HtmlEncode(sb, str, t.StartOffset, t.Length); sb.Append("</code>"); break; case TokenType.link: { var li = (LinkInfo)t.Data; var sf = new SpanFormatter(_mMarkdown) { DisableLinks = true }; li.Def.RenderLink(_mMarkdown, sb, sf.Format(li.LinkText)); break; } case TokenType.img: { var li = (LinkInfo)t.Data; li.Def.RenderImg(_mMarkdown, sb, li.LinkText); break; } case TokenType.footnote: { var r = (FootnoteReference)t.Data; // ReSharper disable once StringLiteralTypo 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: { var a = (Abbreviation)t.Data; sb.Append("<abbr"); if (!string.IsNullOrEmpty(a.Title)) { sb.Append(" title=\""); _mMarkdown.HtmlEncode(sb, a.Title, 0, a.Title.Length); sb.Append("\""); } sb.Append(">"); _mMarkdown.HtmlEncode(sb, a.Abbr, 0, a.Abbr.Length); sb.Append("</abbr>"); break; } } FreeToken(t); } }