public override bool Match(InlineProcessor processor, ref StringSlice slice) { var match = slice.CurrentChar; var pc = slice.PeekCharExtra(-1); if (pc == match) { return(false); } var startPosition = slice.Start; // Match the opened $ or $$ int openDollars = 1; // we have at least a $ var c = slice.NextChar(); if (c == match) { openDollars++; c = slice.NextChar(); } bool openPrevIsPunctuation; bool openPrevIsWhiteSpace; pc.CheckUnicodeCategory(out openPrevIsWhiteSpace, out openPrevIsPunctuation); // Check that opening $/$$ is correct, using the different heuristics than for emphasis delimiters // If a $/$$ is not preceded by a whitespace or punctuation, or followed by a digit // this is a not a math block if (!openPrevIsWhiteSpace && !openPrevIsPunctuation) { return(false); } bool isMatching = false; int closeDollars = 0; // Eat any leading spaces while (c.IsSpaceOrTab()) { c = slice.NextChar(); } var start = slice.Start; var end = 0; pc = match; var lastWhiteSpace = -1; while (c != '\0') { // Don't allow newline in an inline math expression if (c == '\r' || c == '\n') { return(false); } // Don't process sticks if we have a '\' as a previous char if (pc != '\\') { // Record continuous whitespaces at the end if (c.IsSpaceOrTab()) { if (lastWhiteSpace < 0) { lastWhiteSpace = slice.Start; } } else { bool hasClosingDollars = c == match; if (hasClosingDollars) { while (c == match) { closeDollars++; c = slice.NextChar(); } } if (closeDollars >= openDollars) { break; } lastWhiteSpace = -1; if (hasClosingDollars) { pc = match; continue; } } } if (closeDollars > 0) { closeDollars = 0; } else { pc = c; c = slice.NextChar(); } } if (closeDollars >= openDollars) { c.CheckUnicodeCategory(out bool closeNextIsWhiteSpace, out bool closeNextIsPunctuation); // A closing $/$$ should be followed by at least a punctuation or a whitespace // and if the character after an opening $/$$ was a whitespace, it should be // a whitespace as well for the character preceding the closing of $/$$ if (!closeNextIsPunctuation && !closeNextIsWhiteSpace) { return(false); } end = slice.Start - 1; // Create a new MathInline int line; int column; var inline = new MathInline() { Span = new SourceSpan(processor.GetSourcePosition(startPosition, out line, out column), processor.GetSourcePosition(slice.End)), Line = line, Column = column, Delimiter = match, DelimiterCount = openDollars, Content = slice }; inline.Content.Start = start; // We substract the end to the number of opening $ to keep inside the block the additionals $ inline.Content.End = end - openDollars; // Add the default class if necessary if (DefaultClass != null) { inline.GetAttributes().AddClass(DefaultClass); } processor.Inline = inline; isMatching = true; } return(isMatching); }
public override bool Match(InlineProcessor processor, ref StringSlice slice) { var match = slice.CurrentChar; var pc = slice.PeekCharExtra(-1); if (pc == match) { return(false); } var startPosition = slice.Start; // Match the opened $ or $$ int openDollars = 1; // we have at least a $ var c = slice.NextChar(); if (c == match) { openDollars++; c = slice.NextChar(); } bool canOpen; bool canClose; // Check that opening $/$$ is correct, using the same heuristics than for emphasis delimiters CharHelper.CheckOpenCloseDelimiter(pc, c, false, out canOpen, out canClose); if (!canOpen) { return(false); } bool isMatching = false; int closeDollars = 0; var start = slice.Start; pc = match; while (c != '\0') { // Don't process sticks if we have a '\' as a previous char if (pc != '\\') { while (c == match) { closeDollars++; c = slice.NextChar(); } if (closeDollars >= openDollars) { break; } pc = match; } if (closeDollars > 0) { closeDollars = 0; } else { pc = c; c = slice.NextChar(); } } if (closeDollars >= openDollars) { // Check that closing $/$$ is correct CharHelper.CheckOpenCloseDelimiter(pc, c, false, out canOpen, out canClose); if (!canClose || c.IsDigit()) { return(false); } // Create a new MathInline int line; int column; var inline = new MathInline() { Span = new SourceSpan(processor.GetSourcePosition(startPosition, out line, out column), processor.GetSourcePosition(slice.End)), Line = line, Column = column, Delimiter = match, DelimiterCount = openDollars, Content = slice }; inline.Content.Start = start; // We substract the end to the number of opening $ to keep inside the block the additionals $ inline.Content.End = inline.Content.End - openDollars; // Add the default class if necessary if (DefaultClass != null) { inline.GetAttributes().AddClass(DefaultClass); } processor.Inline = inline; isMatching = true; } return(isMatching); }