in lib/src/inline_parser.dart [197:286]
void _processEmphasis(int bottomIndex) {
var currentIndex = bottomIndex + 1;
// Track the lowest index where we might find an open delimiter given a
// closing delimiter length modulo 3.
// Each key in this map is an open delimiter character. Each value is a
// 3-element list. Each value in the list is the lowest index for the given
// delimiter length modulo 3 (0, 1, 2).
var openersBottom = <int, List<int>>{};
while (currentIndex < _delimiterStack.length) {
var closer = _delimiterStack[currentIndex];
if (!closer.canClose) {
currentIndex++;
continue;
}
if (closer.char == $lbracket || closer.char == $exclamation) {
currentIndex++;
continue;
}
openersBottom.putIfAbsent(closer.char, () => List.filled(3, bottomIndex));
var openersBottomPerCloserLength = openersBottom[closer.char]!;
var openerBottom = openersBottomPerCloserLength[closer.length % 3];
var openerIndex = _delimiterStack.lastIndexWhere(
(d) =>
d.char == closer.char && d.canOpen && _canFormEmphasis(d, closer),
currentIndex - 1);
if (openerIndex > bottomIndex && openerIndex > openerBottom) {
// Found an opener for [closer].
var opener = _delimiterStack[openerIndex];
var strong = opener.length >= 2 && closer.length >= 2;
var openerTextNode = opener.node;
var openerTextNodeIndex = _tree.indexOf(openerTextNode);
var closerTextNode = closer.node;
var closerTextNodeIndex = _tree.indexOf(closerTextNode);
var node = opener.syntax.close(this, opener, closer,
getChildren: () =>
_tree.sublist(openerTextNodeIndex + 1, closerTextNodeIndex));
// Replace all of the nodes between the opener and the closer (which
// are now the new emphasis node's children) with the emphasis node.
_tree.replaceRange(
openerTextNodeIndex + 1, closerTextNodeIndex, [node!]);
// Slide [closerTextNodeIndex] back accordingly.
closerTextNodeIndex = openerTextNodeIndex + 2;
_delimiterStack.removeRange(openerIndex + 1, currentIndex);
// Slide [currentIndex] back accordingly.
currentIndex = openerIndex + 1;
// Remove delimiter characters, possibly removing nodes from the tree
// and Delimiters from the delimiter stack.
if ((strong && openerTextNode.text.length == 2) ||
(!strong && openerTextNode.text.length == 1)) {
_tree.removeAt(openerTextNodeIndex);
_delimiterStack.removeAt(openerIndex);
// Slide [currentIndex] and [closerTextNodeIndex] back accordingly.
currentIndex--;
closerTextNodeIndex--;
} else {
var newOpenerTextNode =
Text(openerTextNode.text.substring(strong ? 2 : 1));
_tree[openerTextNodeIndex] = newOpenerTextNode;
opener.node = newOpenerTextNode;
}
if ((strong && closerTextNode.text.length == 2) ||
(!strong && closerTextNode.text.length == 1)) {
_tree.removeAt(closerTextNodeIndex);
_delimiterStack.removeAt(currentIndex);
// [currentIndex] has just moved to point at the next delimiter;
// leave it.
} else {
var newCloserTextNode =
Text(closerTextNode.text.substring(strong ? 2 : 1));
_tree[closerTextNodeIndex] = newCloserTextNode;
closer.node = newCloserTextNode;
// [currentIndex] needs to be considered again; leave it.
}
} else {
// No opener is found.
openersBottomPerCloserLength[closer.length % 3] = currentIndex - 1;
if (!closer.canOpen) {
_delimiterStack.removeAt(currentIndex);
// This advances [currentIndex] to the next delimiter.
} else {
currentIndex++;
}
}
}
_delimiterStack.removeRange(bottomIndex + 1, _delimiterStack.length);
}