texBreak method

BreakResult<EquationRowNode> texBreak({
  1. int relPenalty = 500,
  2. int binOpPenalty = 700,
  3. bool enforceNoBreak = true,
})

Line breaking results using standard TeX-style line breaking.

This function will return a list of EquationRowNode along with a list of line breaking penalties.

This function will break the equation into pieces according to TeX spec as much as possible (some exceptions exist when enforceNoBreak: true ). Then, you can assemble the pieces in whatever way you like. The most simple way is to put the parts inside a Wrap.

If you wish to implement a custom line breaking policy to manage the penalties, you can access the penalties in BreakResult.penalties. The values in BreakResult.penalties represent the line-breaking penalty generated at the right end of each BreakResult.parts. Note that \nobreak or \penalty<number>=10000> are left unbroken by default, you need to supply enforceNoBreak: false into Math.texBreak to expose those break points and their penalties.

Implementation

BreakResult<EquationRowNode> texBreak({
  int relPenalty = 500,
  int binOpPenalty = 700,
  bool enforceNoBreak = true,
}) {
  final breakIndices = <int>[];
  final penalties = <int>[];
  for (var i = 0; i < flattenedChildList.length; i++) {
    final child = flattenedChildList[i];

    // Peek ahead to see if the next child is a no-break
    if (i < flattenedChildList.length - 1) {
      final nextChild = flattenedChildList[i + 1];
      if (nextChild is SpaceNode &&
          nextChild.breakPenalty != null &&
          nextChild.breakPenalty! >= 10000) {
        if (!enforceNoBreak) {
          // The break point should be moved to the next child, which is a \nobreak.
          continue;
        } else {
          // In enforced mode, we should cancel the break point all together.
          i++;
          continue;
        }
      }
    }

    if (child.rightType == AtomType.bin) {
      breakIndices.add(i);
      penalties.add(binOpPenalty);
    } else if (child.rightType == AtomType.rel) {
      breakIndices.add(i);
      penalties.add(relPenalty);
    } else if (child is SpaceNode && child.breakPenalty != null) {
      breakIndices.add(i);
      penalties.add(child.breakPenalty!);
    }
  }

  final res = <EquationRowNode>[];
  var pos = 1;
  for (var i = 0; i < breakIndices.length; i++) {
    final breakEnd = caretPositions[breakIndices[i] + 1];
    res.add(this.clipChildrenBetween(pos, breakEnd).wrapWithEquationRow());
    pos = breakEnd;
  }
  if (pos != caretPositions.last) {
    res.add(this
        .clipChildrenBetween(pos, caretPositions.last)
        .wrapWithEquationRow());
    penalties.add(10000);
  }
  return BreakResult<EquationRowNode>(
    parts: res,
    penalties: penalties,
  );
}