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) {
// Resolve the previous frame's cells to a nullable local up front rather
// than promoting `previous` through a `reusable` boolean: the Dart AOT
// compiler (≤ 3.13) hoists `previous._cells` out of the loop past that
// guard, dereferencing `null` on the first frame (a SIGSEGV at
// `si_addr=0xf`). VM bug dart-lang/sdk#63413, fixed in 3.14; stable
// cherry-pick requested in dart-lang/sdk#64723.
final prev =
previous != null && previous.width == width && previous.height == height
? previous._cells
: null;
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 = prev != null && prev[_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 (prev != null && prev[_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();
}