parseAnsi function

List<AnsiSpan> parseAnsi(
  1. String text
)

Splits text into runs of visible characters, each carrying the SGR state that was in effect when it was written.

Every escape sequence that is not SGR is dropped. A child writes plenty of them — mason_logger's own Progress brackets each frame with ESC[?7l and ESC[2K, and revali dev clears the screen with ESC[2J ESC[0;0H — and they are instructions to a terminal, addressed to a screen the child believes it owns. A pane inside another program's frame is not that screen, so printing them is why [2J[0;0H shows up as characters.

Dropping them is the answer for all but one. kClearScreen says something a pane can act on, and by the time text reaches here it already has: ServiceSession.ingest acts on it and hands this only what survived. So a ESC[2J seen here is one nothing claimed, and dropping it is right.

Adjacent runs with the same state are merged, so a line the child wrapped in a redundant reset does not become two spans that render identically.

Implementation

List<AnsiSpan> parseAnsi(String text) {
  final spans = <AnsiSpan>[];
  final buffer = StringBuffer();

  int? color;
  var bold = false;
  var dim = false;

  void flush() {
    if (buffer.isEmpty) return;

    // Merged rather than appended when the state has not moved: two spans that
    // paint the same are one span that paints the same, and a renderer given
    // the second has to decide all over again what to do with it.
    if (spans.isNotEmpty &&
        spans.last.color == color &&
        spans.last.bold == bold &&
        spans.last.dim == dim) {
      final merged = spans.removeLast();
      spans.add(
        AnsiSpan('${merged.text}$buffer', color: color, bold: bold, dim: dim),
      );
    } else {
      spans.add(AnsiSpan('$buffer', color: color, bold: bold, dim: dim));
    }

    buffer.clear();
  }

  var index = 0;
  while (index < text.length) {
    if (text.codeUnitAt(index) != _esc) {
      buffer.writeCharCode(text.codeUnitAt(index));
      index++;
      continue;
    }

    final sequence = _sequenceAt(text, index);
    if (sequence == null) {
      // A trailing `ESC` with nothing after it: the chunk split mid-sequence.
      // Dropped rather than printed — the rest of it is in the next chunk and
      // a lone escape byte is not a character anyone meant to see.
      break;
    }

    // The state changes *between* runs, so what came before it keeps the old
    // one.
    if (_sgrParameters(text, sequence) case final parameters?) {
      flush();

      for (final parameter in parameters) {
        switch (parameter) {
          case 0:
            color = null;
            bold = false;
            dim = false;
          case 1:
            bold = true;
          case 2:
            dim = true;
          case 22:
            bold = false;
            dim = false;
          case 39:
            color = null;
          case >= 30 && <= 37:
          case >= 90 && <= 97:
            color = parameter;
        }
      }
    }

    index = sequence.end;
  }

  flush();

  return spans;
}