completeOpenMath function
The formula left open at the end of source, closed so that it parses.
Returns where its opener starts and the text to render in place of
source.substring(start), or null when every formula in source is
closed. Returns null too when a code span is still open, since its
backticks swallow any \( inside.
\( and \[ are always maths; $$ and $ only when dollarsAreMath.
A $ before a digit is a price, as elsewhere in the streaming hold, and a
$ before whitespace opens nothing (Pandoc's rule, which the final render
follows). Single-dollar maths does not cross a line break: an opener whose
line has ended without a closer is prose.
Implementation
({int start, String completed})? completeOpenMath(
String source, {
required bool dollarsAreMath,
}) {
final n = source.length;
final dollars = DollarMathCloser(source, sameLine: true);
var i = 0;
while (i < n) {
final c = source.codeUnitAt(i);
if (c == 0x60 /* ` */ ) {
final span = codeSpanAt(source, i);
if (span == null) return null;
i = span.close + span.run;
continue;
}
if (c == 0x5C /* \ */ && i + 1 < n) {
final next = source.codeUnitAt(i + 1);
if (next == 0x28 /* ( */ || next == 0x5B /* [ */ ) {
final closer = next == 0x28 ? r'\)' : r'\]';
final end = source.indexOf(closer, i + 2);
if (end == -1) {
return _open(source, i, i + 2, source.substring(i, i + 2), closer);
}
i = end + 2;
continue;
}
// Any other escape, `\$` included, is one unit.
i += 2;
continue;
}
if (dollarsAreMath && c == 0x24 /* $ */ ) {
if (i + 1 < n && source.codeUnitAt(i + 1) == 0x24) {
final end = source.indexOf(r'$$', i + 2);
if (end == -1) return _open(source, i, i + 2, r'\[', r'\]');
i = end + 2;
continue;
}
final next = i + 1 < n ? source.codeUnitAt(i + 1) : -1;
if ((next >= 0x30 && next <= 0x39) ||
(next != -1 && isUnicodeWhitespace(next))) {
i += 1;
continue;
}
final end = dollars.find(i);
if (end == -1) {
// Still open only while its line is the last one.
if (!source.contains('\n', i)) {
return _open(source, i, i + 1, r'\(', r'\)');
}
i += 1;
continue;
}
i = end + 1;
continue;
}
i += 1;
}
return null;
}