protected IList <IInlineElement> ProcessInlineElements(string block, InlineElementType elementType = InlineElementType.All) { var elements = new List <IInlineElement>(); if (string.IsNullOrWhiteSpace(block)) { return(elements); } var matches = new List <InlineElementRuleMatch>(); foreach (var rule in PatternMatcher.InlineElementRules.Where(r => elementType.HasFlag(r.ElementType))) { if (rule.Regex.IsMatch(block)) { var currentRule = rule; var outerMatches = matches; block = currentRule.Regex.Replace(block, match => { switch (currentRule.ElementType) { case InlineElementType.Emphasis: case InlineElementType.EmphasisDouble: var emphasis = CreateInlineElement <Emphasis>(match, currentRule.Constraint); if (currentRule.ElementType == InlineElementType.EmphasisDouble) { emphasis.Element.DoubleDelimited = true; } outerMatches.Add(emphasis); break; case InlineElementType.Strong: case InlineElementType.StrongDouble: var strong = CreateContainerInlineElement <Strong>(match, currentRule.Constraint); if (currentRule.ElementType == InlineElementType.StrongDouble) { strong.Element.DoubleDelimited = true; } outerMatches.Add(strong); break; case InlineElementType.Monospace: case InlineElementType.MonospaceDouble: var monospace = CreateContainerInlineElement <Monospace>(match, currentRule.Constraint); if (currentRule.ElementType == InlineElementType.MonospaceDouble) { monospace.Element.DoubleDelimited = true; } outerMatches.Add(monospace); break; case InlineElementType.Subscript: var subscript = CreateInlineElement <Subscript>(match, currentRule.Constraint); outerMatches.Add(subscript); break; case InlineElementType.Superscript: var superscript = CreateInlineElement <Superscript>(match, currentRule.Constraint); outerMatches.Add(superscript); break; case InlineElementType.Quotation: case InlineElementType.QuotationDouble: var quotation = CreateContainerInlineElement <QuotationMark>(match, currentRule.Constraint); if (currentRule.ElementType == InlineElementType.QuotationDouble) { quotation.Element.DoubleDelimited = true; } outerMatches.Add(quotation); break; case InlineElementType.Mark: case InlineElementType.MarkDouble: var mark = CreateContainerInlineElement <Mark>(match, currentRule.Constraint); if (currentRule.ElementType == InlineElementType.MarkDouble) { mark.Element.DoubleDelimited = true; } outerMatches.Add(mark); break; case InlineElementType.InternalAnchor: var internalAnchorParts = match.Groups[1].Value; InternalAnchor anchor; if (internalAnchorParts.IndexOf(",", StringComparison.OrdinalIgnoreCase) > -1) { var parts = internalAnchorParts.Split(','); // TODO: Process inline elements of parts[1] anchor = new InternalAnchor(parts[0], parts[1]); } else { anchor = new InternalAnchor(internalAnchorParts); } outerMatches.Add(new InlineElementRuleMatch(anchor, match.Index, match.Index + match.Length, new string(' ', match.Length))); break; case InlineElementType.InlineAnchor: var inlineAnchorId = match.Groups[1].Value; var xRefLabel = match.Groups[2].Value; // TODO: process inline elements of xRefLabel var inlineAnchor = !string.IsNullOrEmpty(xRefLabel) ? new InlineAnchor(inlineAnchorId, xRefLabel) : new InlineAnchor(inlineAnchorId); outerMatches.Add(new InlineElementRuleMatch(inlineAnchor, match.Index, match.Index + match.Length, new string(' ', match.Length))); break; case InlineElementType.AttributeReference: var text = match.Groups[2].Value; var attributeReference = new AttributeReference(text); outerMatches.Add(new InlineElementRuleMatch(attributeReference, match.Index, match.Index + match.Length, new string(' ', match.Length))); break; case InlineElementType.ImplicitLink: // TODO: split attributes out var attributes = match.Groups["attributes"].Success ? match.Groups["attributes"].Value : null; var href = match.Groups["href"].Value; var link = new Link(href, attributes); outerMatches.Add(new InlineElementRuleMatch(link, match.Index + match.Groups[1].Length, match.Index + match.Length, match.Groups[1].Value + new string(' ', match.Length - match.Groups[1].Length))); break; } // replace any matches with the match replacement value TODO: This could be optimized return(outerMatches[outerMatches.Count - 1].Replacement); }); } } if (matches.Any()) { matches.Sort((match1, match2) => match1.StartIndex.CompareTo(match2.StartIndex)); for (int i = 0; i < matches.Count; i++) { var match = matches[i]; var isLastMatch = i == matches.Count - 1; if (i == 0 && match.StartIndex > 0) { elements.Add(new TextLiteral(block.Substring(0, matches[0].StartIndex))); } elements.Add(match.Element); if (!isLastMatch) { // is there a literal between where this match ends and next one begins var nextMatch = matches[i + 1]; var length = nextMatch.StartIndex - match.EndIndex; if (length > 0) { elements.Add(new TextLiteral(block.Substring(match.EndIndex, length))); } } else { if (match.EndIndex < block.Length) { elements.Add(new TextLiteral(block.Substring(match.EndIndex))); } } } } else { elements.Add(new TextLiteral(block)); } return(elements); }