fromAnsi static method

Buffer fromAnsi(
  1. String ansiText
)

Parses an ANSI sequence string (supporting 24-bit SGR color codes) into a Buffer.

Implementation

static Buffer fromAnsi(String ansiText) {
  final cells = <List<({String char, int fg, int bg})>>[];
  var currentRow = <({String char, int fg, int bg})>[];

  int currentFg = 0xFFFFFFFF;
  int currentBg = 0xFF000000;

  int idx = 0;
  final len = ansiText.length;

  while (idx < len) {
    switch (ansiText.codeUnitAt(idx)) {
      case 0x1B:
        idx++;
        if (idx < len && ansiText.codeUnitAt(idx) == 0x5B) {
          idx++;
          int start = idx;
          while (idx < len && ansiText.codeUnitAt(idx) != 0x6D) {
            idx++;
          }
          if (idx < len) {
            final paramsStr = ansiText.substring(start, idx);
            idx++;

            if (paramsStr.isEmpty || paramsStr == '0') {
              currentFg = 0xFFFFFFFF;
              currentBg = 0xFF000000;
            } else {
              int pIdx = 0;
              int nextSemi(int from) {
                int s = paramsStr.indexOf(';', from);
                return s == -1 ? paramsStr.length : s;
              }

              while (pIdx < paramsStr.length) {
                int semi = nextSemi(pIdx);
                int code = int.tryParse(paramsStr.substring(pIdx, semi)) ?? 0;

                switch (code) {
                  case 0:
                    currentFg = 0xFFFFFFFF;
                    currentBg = 0xFF000000;
                    pIdx = semi + 1;
                  case 38:
                    int s2 = nextSemi(semi + 1);
                    int type =
                        int.tryParse(paramsStr.substring(semi + 1, s2)) ?? 0;
                    if (type == 2) {
                      int s3 = nextSemi(s2 + 1);
                      int r =
                          int.tryParse(paramsStr.substring(s2 + 1, s3)) ?? 0;
                      int s4 = nextSemi(s3 + 1);
                      int g =
                          int.tryParse(paramsStr.substring(s3 + 1, s4)) ?? 0;
                      int s5 = nextSemi(s4 + 1);
                      int b =
                          int.tryParse(paramsStr.substring(s4 + 1, s5)) ?? 0;
                      currentFg = (0xFF << 24) | (r << 16) | (g << 8) | b;
                      pIdx = s5 + 1;
                    } else {
                      pIdx = s2 + 1;
                    }
                  case 48:
                    int s2 = nextSemi(semi + 1);
                    int type =
                        int.tryParse(paramsStr.substring(semi + 1, s2)) ?? 0;
                    if (type == 2) {
                      int s3 = nextSemi(s2 + 1);
                      int r =
                          int.tryParse(paramsStr.substring(s2 + 1, s3)) ?? 0;
                      int s4 = nextSemi(s3 + 1);
                      int g =
                          int.tryParse(paramsStr.substring(s3 + 1, s4)) ?? 0;
                      int s5 = nextSemi(s4 + 1);
                      int b =
                          int.tryParse(paramsStr.substring(s4 + 1, s5)) ?? 0;
                      currentBg = (0xFF << 24) | (r << 16) | (g << 8) | b;
                      pIdx = s5 + 1;
                    } else {
                      pIdx = s2 + 1;
                    }
                  default:
                    pIdx = semi + 1;
                }
              }
            }
          }
        }
      case 0x0A:
        cells.add(currentRow);
        currentRow = <({String char, int fg, int bg})>[];
        idx++;
      case final cu:
        String char;
        if (cu < 128 && cu != 0x0D) {
          char = String.fromCharCode(cu);
          idx++;
        } else {
          final remain = ansiText.substring(idx);
          if (remain.isEmpty) {
            idx = len;
            continue;
          }
          char = remain.characters.first;
          idx += char.length;
        }
        if (char != '\r') {
          currentRow.add((char: char, fg: currentFg, bg: currentBg));
        }
    }
  }

  if (currentRow.isNotEmpty ||
      (ansiText.isNotEmpty &&
          ansiText.codeUnitAt(ansiText.length - 1) != 0x0A)) {
    cells.add(currentRow);
  }

  int maxCols = 0;
  for (final row in cells) {
    if (row.length > maxCols) maxCols = row.length;
  }

  final buffer = Buffer.blank(maxCols, cells.length);
  final charsArray = buffer.characters;
  final attrsArray = buffer.attributes;

  for (int y = 0; y < cells.length; y++) {
    final row = cells[y];
    final rowOffset = y * maxCols;
    for (int x = 0; x < row.length; x++) {
      final cell = row[x];
      final idx = rowOffset + x;
      charsArray[idx] = cell.char;
      final attrIdx = idx * 3;
      attrsArray[attrIdx + 0] = cell.fg;
      attrsArray[attrIdx + 1] = cell.bg;
    }
  }

  return buffer;
}