fromAnsi static method
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;
}