/// <summary> /// Writes the inline list to the given writer as plain text (without any HTML tags). /// </summary> /// <seealso href="https://github.com/jgm/CommonMark/issues/145"/> private static void InlinesToPlainText(DocumentationCommentTextWriter writer, Inline inline, Stack <InlineStackEntry> stack) { bool withinLink = false; bool stackWithinLink = false; bool visitChildren; string stackLiteral = null; var origStackCount = stack.Count; while (inline != null) { visitChildren = false; switch (inline.Tag) { case InlineTag.String: case InlineTag.Code: case InlineTag.RawHtml: EscapeHtml(inline.LiteralContent, writer); break; case InlineTag.LineBreak: case InlineTag.SoftBreak: writer.WriteLine(); break; case InlineTag.Link: if (withinLink) { writer.Write('['); stackLiteral = "]"; visitChildren = true; stackWithinLink = withinLink; } else { visitChildren = true; stackWithinLink = true; stackLiteral = string.Empty; } break; case InlineTag.Image: visitChildren = true; stackWithinLink = true; stackLiteral = string.Empty; break; case InlineTag.Strong: case InlineTag.Emphasis: stackLiteral = string.Empty; stackWithinLink = withinLink; visitChildren = true; break; default: throw new CommonMarkException("Inline type " + inline.Tag + " is not supported.", inline); } if (visitChildren) { stack.Push(new InlineStackEntry(stackLiteral, inline.NextSibling, withinLink)); withinLink = stackWithinLink; inline = inline.FirstChild; } else if (inline.NextSibling != null) { inline = inline.NextSibling; } else { inline = null; } while (inline == null && stack.Count > origStackCount) { var entry = stack.Pop(); writer.WriteConstant(entry.Literal); inline = entry.Target; withinLink = entry.IsWithinLink; } } }
/// <summary> /// Writes the inline list to the given writer as HTML code. /// </summary> private static void InlinesToHtml(DocumentationCommentTextWriter writer, Inline inline, CommonMarkSettings settings, ISymbol documentedSymbol, Stack <InlineStackEntry> stack) { var uriResolver = settings.UriResolver; bool withinLink = false; bool stackWithinLink = false; bool visitChildren; string stackLiteral = null; while (inline != null) { visitChildren = false; switch (inline.Tag) { case InlineTag.String: EscapeHtml(inline.LiteralContent, writer); break; case InlineTag.LineBreak: writer.WriteLineConstant("<br />"); break; case InlineTag.SoftBreak: if (settings.RenderSoftLineBreaksAsLineBreaks) { writer.WriteLineConstant("<br />"); } else { writer.WriteLine(); } break; case InlineTag.Code: if (documentedSymbol.HasAnyParameter(inline.LiteralContent, StringComparer.Ordinal)) { writer.WriteConstant("<paramref name=\""); EscapeHtml(inline.LiteralContent, writer); writer.WriteConstant("\"/>"); } else if (documentedSymbol.HasAnyTypeParameter(inline.LiteralContent, StringComparer.Ordinal)) { writer.WriteConstant("<typeparamref name=\""); EscapeHtml(inline.LiteralContent, writer); writer.WriteConstant("\"/>"); } else { writer.WriteConstant("<c>"); EscapeHtml(inline.LiteralContent, writer); writer.WriteConstant("</c>"); } break; case InlineTag.RawHtml: writer.Write(inline.LiteralContent); break; case InlineTag.Link: if (withinLink) { writer.Write('['); stackLiteral = "]"; stackWithinLink = withinLink; visitChildren = true; } else { writer.WriteConstant("<see href=\""); if (uriResolver != null) { EscapeUrl(uriResolver(inline.TargetUrl), writer); } else { EscapeUrl(inline.TargetUrl, writer); } writer.Write('\"'); if (inline.LiteralContent.Length > 0) { writer.WriteConstant(" title=\""); EscapeHtml(inline.LiteralContent, writer); writer.Write('\"'); } writer.Write('>'); visitChildren = true; stackWithinLink = true; stackLiteral = "</see>"; } break; case InlineTag.Image: writer.WriteConstant("<img src=\""); if (uriResolver != null) { EscapeUrl(uriResolver(inline.TargetUrl), writer); } else { EscapeUrl(inline.TargetUrl, writer); } writer.WriteConstant("\" alt=\""); InlinesToPlainText(writer, inline.FirstChild, stack); writer.Write('\"'); if (inline.LiteralContent.Length > 0) { writer.WriteConstant(" title=\""); EscapeHtml(inline.LiteralContent, writer); writer.Write('\"'); } writer.WriteConstant(" />"); break; case InlineTag.Strong: writer.WriteConstant("<strong>"); stackLiteral = "</strong>"; stackWithinLink = withinLink; visitChildren = true; break; case InlineTag.Emphasis: writer.WriteConstant("<em>"); stackLiteral = "</em>"; visitChildren = true; stackWithinLink = withinLink; break; case InlineTag.Strikethrough: writer.WriteConstant("<del>"); stackLiteral = "</del>"; visitChildren = true; stackWithinLink = withinLink; break; default: throw new CommonMarkException("Inline type " + inline.Tag + " is not supported.", inline); } if (visitChildren) { stack.Push(new InlineStackEntry(stackLiteral, inline.NextSibling, withinLink)); withinLink = stackWithinLink; inline = inline.FirstChild; } else if (inline.NextSibling != null) { inline = inline.NextSibling; } else { inline = null; } while (inline == null && stack.Count > 0) { var entry = stack.Pop(); writer.WriteConstant(entry.Literal); inline = entry.Target; withinLink = entry.IsWithinLink; } } }
private static void BlocksToHtmlInner(DocumentationCommentTextWriter writer, Block block, CommonMarkSettings settings, ISymbol documentedSymbol) { var stack = new Stack <BlockStackEntry>(); var inlineStack = new Stack <InlineStackEntry>(); bool visitChildren; string stackLiteral = null; bool stackTight = false; bool tight = false; int x; while (block != null) { visitChildren = false; switch (block.Tag) { case BlockTag.Document: stackLiteral = null; stackTight = false; visitChildren = true; break; case BlockTag.Paragraph: if (tight) { InlinesToHtml(writer, block.InlineContent, settings, documentedSymbol, inlineStack); } else { writer.EnsureLine(); writer.WriteConstant("<para>"); InlinesToHtml(writer, block.InlineContent, settings, documentedSymbol, inlineStack); writer.WriteLineConstant("</para>"); } break; case BlockTag.BlockQuote: writer.EnsureLine(); writer.WriteLineConstant("<note>"); stackLiteral = "</note>"; stackTight = false; visitChildren = true; break; case BlockTag.ListItem: writer.EnsureLine(); writer.WriteConstant("<item><description>"); stackLiteral = "</description></item>"; stackTight = tight; visitChildren = true; break; case BlockTag.List: // make sure a list starts at the beginning of the line: writer.EnsureLine(); var data = block.ListData; writer.WriteConstant(data.ListType == ListType.Bullet ? "<list type=\"bullet\"" : "<list type=\"number\""); if (data.Start != 1) { writer.WriteConstant(" start=\""); writer.WriteConstant(data.Start.ToString(System.Globalization.CultureInfo.InvariantCulture)); writer.Write('\"'); } writer.WriteLineConstant(">"); stackLiteral = "</list>"; stackTight = data.IsTight; visitChildren = true; break; case BlockTag.AtxHeading: case BlockTag.SetextHeading: writer.EnsureLine(); x = block.Heading.Level; writer.WriteConstant(x > 0 && x < 7 ? HeaderOpenerTags[x - 1] : "<h" + x.ToString(CultureInfo.InvariantCulture) + ">"); InlinesToHtml(writer, block.InlineContent, settings, documentedSymbol, inlineStack); writer.WriteLineConstant(x > 0 && x < 7 ? HeaderCloserTags[x - 1] : "</h" + x.ToString(CultureInfo.InvariantCulture) + ">"); break; case BlockTag.IndentedCode: writer.EnsureLine(); writer.WriteConstant("<code>"); EscapeHtml(block.StringContent, writer); writer.WriteLineConstant("</code>"); break; case BlockTag.FencedCode: writer.EnsureLine(); writer.WriteConstant("<code"); var info = block.FencedCodeData.Info; if (info != null && info.Length > 0) { x = info.IndexOf(' '); if (x == -1) { x = info.Length; } writer.WriteConstant(" language=\""); EscapeHtml(info.Substring(0, x), writer); writer.Write('\"'); } writer.Write('>'); writer.WriteLine(); EscapeHtml(block.StringContent, writer); writer.WriteLineConstant("</code>"); break; case BlockTag.HtmlBlock: writer.Write(block.StringContent.ToString(new StringBuilder())); break; case BlockTag.ThematicBreak: writer.WriteLineConstant("<hr />"); break; case BlockTag.ReferenceDefinition: break; default: throw new CommonMarkException("Block type " + block.Tag + " is not supported.", block); } if (visitChildren) { stack.Push(new BlockStackEntry(stackLiteral, block.NextSibling, tight)); tight = stackTight; block = block.FirstChild; } else if (block.NextSibling != null) { block = block.NextSibling; } else { block = null; } while (block == null && stack.Count > 0) { var entry = stack.Pop(); writer.WriteLineConstant(entry.Literal); tight = entry.IsTight; block = entry.Target; } } }