renderDiff method
Emits the ANSI needed to turn previous into this frame, rewriting only
the cells that changed. When previous is null (or a different size) the
whole frame is drawn.
The returned string positions the cursor as needed and ends with an SGR reset; the caller is responsible for any final cursor placement.
Implementation
String renderDiff(ScreenBuffer? previous) {
final reusable =
previous != null &&
previous.width == width &&
previous.height == height;
final out = StringBuffer();
Style? current; // the SGR currently active in `out`.
for (var y = 0; y < height; y++) {
var x = 0;
while (x < width) {
final cell = _cells[_index(x, y)];
final unchanged = reusable && previous._cells[_index(x, y)] == cell;
if (unchanged) {
x++;
continue;
}
// Start of a changed run: move the cursor here (1-based) and paint
// until the cells match `previous` again (or the row ends).
out.write('\x1b[${y + 1};${x + 1}H');
while (x < width) {
final c = _cells[_index(x, y)];
if (reusable && previous._cells[_index(x, y)] == c) break;
if (current != c.style) {
out.write(c.style.sgr);
current = c.style;
}
out.write(c.char);
x++;
}
}
}
if (current != null) out.write('\x1b[0m');
return out.toString();
}