/// <summary> /// This function can be called by any element parsing. Given a start and stopping point this will /// parse all found elements out of the range. /// </summary> /// <param name="markdown"></param> /// <param name="startingPos"></param> /// <param name="maxEndingPos"></param> protected void ParseInlineChildren(ref string markdown, int startingPos, int maxEndingPos) { int currentParsePosition = startingPos; while (currentParsePosition < maxEndingPos) { int nextElemntStart = 0; int nextElementEnd = 0; // Find the next element MarkdownInline element = Common.FindNextInlineElement(ref markdown, currentParsePosition, maxEndingPos, ref nextElemntStart, ref nextElementEnd); // If the element we found doesn't start at the position we are looking for there is text between the element and // the start. We need to wrap it into a Text Run if (nextElemntStart != currentParsePosition) { TextRunInline textRun = new TextRunInline(); textRun.Parse(ref markdown, currentParsePosition, nextElemntStart); Children.Add(textRun); } // Ask it to parse, it will return us the ending pos of itself. currentParsePosition = element.Parse(ref markdown, nextElemntStart, nextElementEnd); // Add it the the children Children.Add(element); } }
/// <summary> /// This function can be called by any element parsing. Given a start and stopping point this will /// parse all found elements out of the range. /// </summary> /// <returns> A list of parsed inlines. </returns> public static List <MarkdownInline> ParseInlineChildren(string markdown, int startingPos, int maxEndingPos, bool ignoreLinks = false) { int currentParsePosition = startingPos; var inlines = new List <MarkdownInline>(); while (currentParsePosition < maxEndingPos) { // Find the next inline element. var parseResult = FindNextInlineElement(markdown, currentParsePosition, maxEndingPos, ignoreLinks); // If the element we found doesn't start at the position we are looking for there // is text between the element and the start of the parsed element. We need to wrap // it into a text run. if (parseResult.Start != currentParsePosition) { var textRun = TextRunInline.Parse(markdown, currentParsePosition, parseResult.Start); inlines.Add(textRun); } // Add the parsed element. inlines.Add(parseResult.ParsedElement); // Update the current position. currentParsePosition = parseResult.End; } return(inlines); }
private void RenderTextRun(TextRunInline inline, InlineCollection inlineCollection) { Run run = new Run { Text = inline.Text }; inlineCollection.Add(run); }
/// <summary> /// Renders a text run element. /// </summary> /// <param name="inlineCollection"> The list to add to. </param> /// <param name="element"> The parsed inline element to render. </param> /// <param name="parent"> The container element. </param> /// <param name="context"> Persistent state. </param> private void RenderTextRun(InlineCollection inlineCollection, TextRunInline element, TextElement parent, RenderContext context) { // Create the text run Run textRun = new Run(); textRun.Text = CollapseWhitespace(context, element.Text); // Add it inlineCollection.Add(textRun); }
/// <summary> /// Renders a text run element. /// </summary> /// <param name="inlineCollection"> The list to add to. </param> /// <param name="element"> The parsed inline element to render. </param> /// <param name="context"> Persistent state. </param> /// <returns><see cref="Run"/></returns> private Run RenderTextRun(InlineCollection inlineCollection, TextRunInline element, RenderContext context) { // Create the text run Run textRun = new Run { Text = CollapseWhitespace(context, element.Text) }; // Add it inlineCollection.Add(textRun); return(textRun); }
/// <summary> /// Renders a text run element. /// </summary> /// <param name="inlineCollection"> The list to add to. </param> /// <param name="element"> The parsed inline element to render. </param> /// <param name="context"> Persistent state. </param> private void RenderTextRun(InlineCollection inlineCollection, TextRunInline element, RenderContext context, bool large) { // Create the text run Run textRun = new Run { Text = element.Text, }; if (large) { textRun.FontSize = 28; } // Add it inlineCollection.Add(textRun); }
private Run InternalRenderTextRun(TextRunInline element, IRenderContext context) { if (!(context is InlineRenderContext localContext)) { throw new RenderContextIncorrectException(); } var inlineCollection = localContext.InlineCollection; Run textRun = new Run { Text = CollapseWhitespace(context, element.Text) }; inlineCollection.Add(textRun); return(textRun); }
/// <summary> /// Renders a text run element. /// </summary> /// <param name="element"></param> /// <param name="currentInlines"></param> /// <param name="trimTextStart">If true this element should trin the start of the text and set to fales.</param> private void RenderTextRun(TextRunInline element, InlineCollection currentInlines, ref bool trimTextStart) { // Create the text run Run textRun = new Run(); textRun.Text = element.Text; // Check if we should trim the starting text. This allows us to trim the text starting a block // but nothing else. If we do a trim set it to false so no one else does. if (trimTextStart) { trimTextStart = false; textRun.Text = textRun.Text.TrimStart(); } // Add it currentInlines.Add(textRun); }
protected override void RenderTextRun(TextRunInline element, IRenderContext context) { if (context.Parent is FormattedString fs) { var span = new Span { Text = element.Text.Replace("\n\r", Environment.NewLine) }; if (_headerLevel > 0) { span.Style = _headerStyles[_headerLevel]; } RenderInlineSpan(span); fs.Spans.Add(span); } }
protected override void RenderTextRun(TextRunInline element, IRenderContext context) { // Fetch the paragraph to add the text content to var renderContext = context as RenderContext; var paragraph = context.Parent as XElement; // Fetch the content of the inline element var text = element.Text; // Check if we need to trim leading white space if (renderContext.TrimLeadingWhitespace) { text = text.TrimStart(); renderContext.TrimLeadingWhitespace = false; } // No content, nothing to do if (string.IsNullOrWhiteSpace(text)) { return; } // Add a bold italic xml tag if (renderContext.SetBoldRun && renderContext.SetItalicRun) { paragraph.Add(new XElement("bi", text)); return; } // Add a bold xml tag if (renderContext.SetBoldRun) { paragraph.Add(new XElement("b", text)); return; } // Add a italic xml tag if (renderContext.SetItalicRun) { paragraph.Add(new XElement("i", text)); return; } // Add a normal xml tag paragraph.Add(new XElement("n", text)); }
private Run InternalRenderTextRun(TextRunInline element, IRenderContext context) { var localContext = context as InlineRenderContext; if (localContext == null) { throw new RenderContextIncorrectException(); } var inlineCollection = localContext.InlineCollection; // Create the text run Run textRun = new Run { Text = CollapseWhitespace(context, element.Text) }; // Add it inlineCollection.Add(textRun); return(textRun); }
/// <summary> /// Attempts to parse a reference e.g. "[example]: http://www.reddit.com 'title'". /// </summary> /// <param name="markdown"> The markdown text. </param> /// <param name="start"> The location to start parsing. </param> /// <param name="end"> The location to stop parsing. </param> /// <returns> A parsed markdown link, or <c>null</c> if this is not a markdown link. </returns> internal static LinkReferenceBlock Parse(string markdown, int start, int end) { // Expect a '[' character. if (start >= end || markdown[start] != '[') { return(null); } // Find the ']' character int pos = start + 1; while (pos < end) { if (markdown[pos] == ']') { break; } pos++; } if (pos == end) { return(null); } // Extract the ID. string id = markdown.Substring(start + 1, pos - (start + 1)); // Expect the ':' character. pos++; if (pos == end || markdown[pos] != ':') { return(null); } // Skip whitespace pos++; while (pos < end && ParseHelpers.IsMarkdownWhiteSpace(markdown[pos])) { pos++; } if (pos == end) { return(null); } // Extract the URL. int urlStart = pos; while (pos < end && !ParseHelpers.IsMarkdownWhiteSpace(markdown[pos])) { pos++; } string url = TextRunInline.ResolveEscapeSequences(markdown, urlStart, pos); // Ignore leading '<' and trailing '>'. url = url.TrimStart('<').TrimEnd('>'); // Skip whitespace. pos++; while (pos < end && ParseHelpers.IsMarkdownWhiteSpace(markdown[pos])) { pos++; } string tooltip = null; if (pos < end) { // Extract the tooltip. char tooltipEndChar; switch (markdown[pos]) { case '(': tooltipEndChar = ')'; break; case '"': case '\'': tooltipEndChar = markdown[pos]; break; default: return(null); } pos++; int tooltipStart = pos; while (pos < end && markdown[pos] != tooltipEndChar) { pos++; } if (pos == end) { return(null); // No end character. } tooltip = markdown.Substring(tooltipStart, pos - tooltipStart); // Check there isn't any trailing text. pos++; while (pos < end && ParseHelpers.IsMarkdownWhiteSpace(markdown[pos])) { pos++; } if (pos < end) { return(null); } } // We found something! var result = new LinkReferenceBlock(); result.Id = id; result.Url = url; result.Tooltip = tooltip; return(result); }
/// <summary> /// Renders a text run element. /// </summary> /// <param name="element"> The parsed inline element to render. </param> /// <param name="context"> Persistent state. </param> protected override void RenderTextRun(TextRunInline element, IRenderContext context) { InternalRenderTextRun(element, context); }
/// <summary> /// Finds the next inline element by matching trip chars and verifying the match. /// </summary> /// <param name="markdown"> The markdown text to parse. </param> /// <param name="start"> The position to start parsing. </param> /// <param name="end"> The position to stop parsing. </param> /// <param name="ignoreLinks"> Indicates whether to parse links. </param> /// <returns>Returns the next element</returns> private static InlineParseResult FindNextInlineElement(string markdown, int start, int end, bool ignoreLinks) { // Search for the next inline sequence. for (int pos = start; pos < end; pos++) { // IndexOfAny should be the fastest way to skip characters we don't care about. pos = markdown.IndexOfAny(_tripCharacters, pos, end - pos); if (pos < 0) { break; } // Find the trigger(s) that matched. char currentChar = markdown[pos]; foreach (InlineTripCharHelper currentTripChar in _triggerList) { // Check if our current char matches the suffix char. if (currentChar == currentTripChar.FirstChar) { // Don't match if the previous character was a backslash. if (pos > start && markdown[pos - 1] == '\\') { continue; } // If we are here we have a possible match. Call into the inline class to verify. InlineParseResult parseResult = null; switch (currentTripChar.Method) { case InlineParseMethod.BoldItalic: parseResult = BoldItalicTextInline.Parse(markdown, pos, end); break; case InlineParseMethod.Comment: parseResult = CommentInline.Parse(markdown, pos, end); break; case InlineParseMethod.LinkReference: parseResult = LinkAnchorInline.Parse(markdown, pos, end); break; case InlineParseMethod.Bold: parseResult = BoldTextInline.Parse(markdown, pos, end); break; case InlineParseMethod.Italic: parseResult = ItalicTextInline.Parse(markdown, pos, end); break; case InlineParseMethod.MarkdownLink: if (!ignoreLinks) { parseResult = MarkdownLinkInline.Parse(markdown, pos, end); } break; case InlineParseMethod.AngleBracketLink: if (!ignoreLinks) { parseResult = HyperlinkInline.ParseAngleBracketLink(markdown, pos, end); } break; case InlineParseMethod.Url: if (!ignoreLinks) { parseResult = HyperlinkInline.ParseUrl(markdown, pos, end); } break; case InlineParseMethod.RedditLink: if (!ignoreLinks) { parseResult = HyperlinkInline.ParseRedditLink(markdown, pos, end); } break; case InlineParseMethod.PartialLink: if (!ignoreLinks) { parseResult = HyperlinkInline.ParsePartialLink(markdown, pos, end); } break; case InlineParseMethod.Email: if (!ignoreLinks) { parseResult = HyperlinkInline.ParseEmailAddress(markdown, start, pos, end); } break; case InlineParseMethod.Strikethrough: parseResult = StrikethroughTextInline.Parse(markdown, pos, end); break; case InlineParseMethod.Superscript: parseResult = SuperscriptTextInline.Parse(markdown, pos, end); break; case InlineParseMethod.Subscript: parseResult = SubscriptTextInline.Parse(markdown, pos, end); break; case InlineParseMethod.Code: parseResult = CodeInline.Parse(markdown, pos, end); break; case InlineParseMethod.Image: parseResult = ImageInline.Parse(markdown, pos, end); break; case InlineParseMethod.Emoji: parseResult = EmojiInline.Parse(markdown, pos, end); break; } if (parseResult != null) { return(parseResult); } } } } // If we didn't find any elements we have a normal text block. // Let us consume the entire range. return(new InlineParseResult(TextRunInline.Parse(markdown, start, end), start, end)); }
/// <summary> /// Renders a text run element. /// </summary> /// <param name="element"> The parsed inline element to render. </param> /// <param name="context"> Persistent state. </param> protected abstract void RenderTextRun(TextRunInline element, IRenderContext context);