bool IPostInlineProcessor.PostProcess(InlineProcessor state, Inline root, Inline lastChild, int postInlineProcessorIndex, bool isFinalProcessing) { // Don't try to process anything if there are no dash var quotePants = state.ParserStates[Index] as ListSmartyPants; if (quotePants == null || !quotePants.HasDash) { return(true); } var child = root; var pendingContainers = new Stack <Inline>(); while (true) { while (child != null) { var next = child.NextSibling; if (child is LiteralInline) { var literal = (LiteralInline)child; var startIndex = 0; var indexOfDash = literal.Content.IndexOf("--", startIndex); if (indexOfDash >= 0) { var type = SmartyPantType.Dash2; if (literal.Content.PeekCharAbsolute(indexOfDash + 2) == '-') { type = SmartyPantType.Dash3; } var nextContent = literal.Content; var originalSpan = literal.Span; literal.Span.End -= literal.Content.End - indexOfDash + 1; literal.Content.End = indexOfDash - 1; nextContent.Start = indexOfDash + (type == SmartyPantType.Dash2 ? 2 : 3); var pant = new SmartyPant() { Span = new SourceSpan(literal.Content.End + 1, nextContent.Start - 1), Line = literal.Line, Column = literal.Column, OpeningCharacter = '-', Type = type }; literal.InsertAfter(pant); var postLiteral = new LiteralInline() { Span = new SourceSpan(pant.Span.End + 1, originalSpan.End), Line = literal.Line, Column = literal.Column, Content = nextContent }; pant.InsertAfter(postLiteral); // Use the pending literal to proceed further next = postLiteral; } } else if (child is ContainerInline) { pendingContainers.Push(((ContainerInline)child).FirstChild); } child = next; } if (pendingContainers.Count > 0) { child = pendingContainers.Pop(); } else { break; } } return(true); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { // We are matching the following characters: // // ' ‘ ’ ‘ ’ 'left-single-quote', 'right-single-quote' // '' “ ” “ ” 'left-double-quote', 'right-double-quote' // " “ ” “ ” 'left-double-quote', 'right-double-quote' // << >> « » « » 'left-angle-quote', 'right-angle-quote' // ... … … 'ellipsis' // Special case: – and — are handle as a PostProcess step to avoid conflicts with pipetables header separator row // -- – – 'ndash' // --- — — 'mdash' var pc = slice.PeekCharExtra(-1); var c = slice.CurrentChar; var openingChar = c; var startingPosition = slice.Start; // undefined first var type = (SmartyPantType)0; switch (c) { case '\'': type = SmartyPantType.Quote; // We will resolve them at the end of parsing all inlines if (slice.PeekChar(1) == '\'') { slice.NextChar(); type = SmartyPantType.DoubleQuote; // We will resolve them at the end of parsing all inlines } break; case '"': type = SmartyPantType.DoubleQuote; break; case '<': if (slice.NextChar() == '<') { type = SmartyPantType.LeftAngleQuote; } break; case '>': if (slice.NextChar() == '>') { type = SmartyPantType.RightAngleQuote; } break; case '.': if (slice.NextChar() == '.' && slice.NextChar() == '.') { type = SmartyPantType.Ellipsis; } break; case '-': if (slice.NextChar() == '-') { var quotePants = GetOrCreateState(processor); quotePants.HasDash = true; return(false); } break; } // If it is not matched, early exit if (type == 0) { return(false); } // Skip char c = slice.NextChar(); bool canOpen; bool canClose; CharHelper.CheckOpenCloseDelimiter(pc, c, false, out canOpen, out canClose); bool postProcess = false; switch (type) { case SmartyPantType.Quote: postProcess = true; if (canOpen && !canClose) { type = SmartyPantType.LeftQuote; } else if (!canOpen && canClose) { type = SmartyPantType.RightQuote; } else { return(false); } break; case SmartyPantType.DoubleQuote: postProcess = true; if (canOpen && !canClose) { type = SmartyPantType.LeftDoubleQuote; } else if (!canOpen && canClose) { type = SmartyPantType.RightDoubleQuote; } else { return(false); } break; case SmartyPantType.LeftAngleQuote: postProcess = true; if (!canOpen || canClose) { return(false); } break; case SmartyPantType.RightAngleQuote: postProcess = true; if (canOpen || !canClose) { return(false); } break; case SmartyPantType.Ellipsis: if (canOpen || !canClose) { return(false); } break; } // Create the SmartyPant inline int line; int column; var pant = new SmartyPant() { Span = { Start = processor.GetSourcePosition(startingPosition, out line, out column) }, Line = line, Column = column, OpeningCharacter = openingChar, Type = type }; pant.Span.End = pant.Span.Start + slice.Start - startingPosition - 1; // We will check in a post-process step for balanced open/close quotes if (postProcess) { var quotePants = GetOrCreateState(processor); // Register only if we don't have yet any quotes if (quotePants.Count == 0) { processor.Block.ProcessInlinesEnd += BlockOnProcessInlinesEnd; } quotePants.Add(pant); } processor.Inline = pant; return(true); }