writeString method
Writes styled text to the buffer starting at (x, y).
Newlines (\n) will wrap to y + 1 at the starting column x.
Any characters that fall out of bounds are clipped.
Implementation
void writeString(int x, int y, String text, Style style) {
final startX = x;
var currentX = x;
var currentY = y;
if (text.runes.length == text.length) {
final len = text.length;
final fg = style.foreground?.argb ?? 0;
final bg = style.background?.argb ?? 0;
final modifiers = style.modifiers;
final hasFg = style.foreground != null;
final hasBg = style.background != null;
for (var i = 0; i < len; i++) {
final codeUnit = text.codeUnitAt(i);
if (codeUnit == 10) {
// '\n'
currentX = startX;
currentY++;
continue;
}
if (currentX >= 0 &&
currentX < width &&
currentY >= 0 &&
currentY < height) {
final idx = currentY * width + currentX;
final char = String.fromCharCode(codeUnit);
// Clear potential wide char we are about to overwrite
if (characters[idx] == '') {
if (currentX - 1 >= 0) {
final prevIdx = idx - 1;
if (isWideGrapheme(characters[prevIdx])) {
characters[prevIdx] = ' ';
}
}
} else if (isWideGrapheme(characters[idx])) {
if (currentX + 1 < width) {
final nextIdx = idx + 1;
if (characters[nextIdx] == '') {
characters[nextIdx] = ' ';
}
}
}
final isWide = isWideCodePoint(codeUnit);
if (isWide && currentX == width - 1) {
characters[idx] = ' ';
final attrIdx = idx * 3;
attributes[attrIdx + 0] = hasFg ? fg : 0;
if (hasBg) attributes[attrIdx + 1] = bg;
attributes[attrIdx + 2] = modifiers;
currentX += 1;
} else {
characters[idx] = char;
final attrIdx = idx * 3;
attributes[attrIdx + 0] = hasFg ? fg : 0;
if (hasBg) attributes[attrIdx + 1] = bg;
attributes[attrIdx + 2] = modifiers;
if (isWide) {
if (currentX + 1 < width) {
final nextIdx = idx + 1;
// Clear potential wide char we are overwriting in the next cell
if (isWideGrapheme(characters[nextIdx]) &&
currentX + 2 < width) {
final nextNextIdx = idx + 2;
if (characters[nextNextIdx] == '') {
characters[nextNextIdx] = ' ';
}
}
characters[nextIdx] = '';
final nextAttrIdx = nextIdx * 3;
attributes[nextAttrIdx + 0] = hasFg ? fg : 0;
if (hasBg) attributes[nextAttrIdx + 1] = bg;
attributes[nextAttrIdx + 2] = modifiers;
}
currentX += 2;
} else {
currentX += 1;
}
}
} else {
currentX += 1;
}
}
return;
}
final chars = text.characters;
final fg = style.foreground?.argb ?? 0;
final bg = style.background?.argb ?? 0;
final modifiers = style.modifiers;
final hasFg = style.foreground != null;
final hasBg = style.background != null;
for (final char in chars) {
if (char == '\n') {
currentX = startX;
currentY++;
continue;
}
if (currentX >= 0 &&
currentX < width &&
currentY >= 0 &&
currentY < height) {
final idx = currentY * width + currentX;
// Clear potential wide char we are about to overwrite
if (characters[idx] == '') {
if (currentX - 1 >= 0) {
final prevIdx = idx - 1;
if (isWideGrapheme(characters[prevIdx])) {
characters[prevIdx] = ' ';
}
}
} else if (isWideGrapheme(characters[idx])) {
if (currentX + 1 < width) {
final nextIdx = idx + 1;
if (characters[nextIdx] == '') {
characters[nextIdx] = ' ';
}
}
}
final isWide = isWideGrapheme(char);
if (isWide && currentX == width - 1) {
// Can't fit wide character in the last column, write a space instead
characters[idx] = ' ';
final attrIdx = idx * 3;
attributes[attrIdx + 0] = hasFg ? fg : 0;
if (hasBg) attributes[attrIdx + 1] = bg;
attributes[attrIdx + 2] = modifiers;
currentX += 1;
} else {
characters[idx] = char;
final attrIdx = idx * 3;
attributes[attrIdx + 0] = hasFg ? fg : 0;
if (hasBg) attributes[attrIdx + 1] = bg;
attributes[attrIdx + 2] = modifiers;
if (isWide) {
if (currentX + 1 < width) {
final nextIdx = idx + 1;
// Clear potential wide char we are overwriting in the next cell
if (isWideGrapheme(characters[nextIdx]) && currentX + 2 < width) {
final nextNextIdx = idx + 2;
if (characters[nextNextIdx] == '') {
characters[nextNextIdx] = ' ';
}
}
characters[nextIdx] = '';
final nextAttrIdx = nextIdx * 3;
attributes[nextAttrIdx + 0] = hasFg ? fg : 0;
if (hasBg) attributes[nextAttrIdx + 1] = bg;
attributes[nextAttrIdx + 2] = modifiers;
}
currentX += 2;
} else {
currentX += 1;
}
}
} else {
currentX += 1;
}
}
}