void _processEmphasis()

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);
  }