settledSplitOffset function

int settledSplitOffset(
  1. String source
)

The offset of the last blank line that is safe to split at, or 0 when the whole document has to stay together.

Everything before the split is settled: it can be rendered once and cached, because appending to the end of a document cannot change it. Everything after is the live tail, and is the only part re-rendered as text arrives. That is what keeps the per-token cost proportional to the tail rather than to the whole reply.

A blank line inside a fenced code block or block LaTeX is not a safe split: cutting there would leave the prefix holding an unterminated

a visible flicker mid-stream. Those regions are skipped.

The last construct is never settled either, even when it is followed by a
blank line, because the next token may still extend it — a list gaining
another item, a paragraph another sentence.

Implementation

int settledSplitOffset(String source) {
  var inFence = false;
  var inLatex = false;

  // Offsets of blank lines outside fences and block maths.
  final candidates = <int>[];

  var lineStart = 0;
  var index = 0;
  while (index <= source.length) {
    final atEnd = index == source.length;
    if (!atEnd && source.codeUnitAt(index) != 0x0A) {
      index++;
      continue;
    }

    final line = source.substring(lineStart, index);
    final trimmed = line.trimLeft();

    if (inFence) {
      if (trimmed.startsWith('```') || trimmed.startsWith('~~~')) {
        inFence = false;
      }
    } else if (inLatex) {
      if (trimmed.contains(r'\]')) {
        inLatex = false;
      }
    } else if (trimmed.startsWith('```') || trimmed.startsWith('~~~')) {
      inFence = true;
    } else if (trimmed.startsWith(r'\[') && !trimmed.contains(r'\]')) {
      inLatex = true;
    } else if (trimmed.isEmpty && lineStart > 0) {
      // The split goes after the blank line, so the tail starts on real
      // content rather than with leading whitespace.
      candidates.add(index + 1);
    }

    if (atEnd) {
      break;
    }
    index++;
    lineStart = index;
  }

  // Never settle the final construct: the next token may extend it.
  if (candidates.length < 2) {
    return 0;
  }
  return candidates[candidates.length - 2];
}