render method
Renders the view to the terminal.
view is the string representation of the current UI state,
or a View object containing metadata.
Implementation
@override
void render(Object view) {
_metrics.beginFrame();
if (!_initialized) {
initialize();
}
final String content = switch (view) {
String s => s,
View v => v.content,
_ => view.toString(),
};
// A terminal resize reflows whatever is on screen, so the last rendered
// frame no longer matches the terminal's actual content — a diff against
// it would leave reflowed fragments in every skipped span. Clear and drop
// the baseline so this frame paints in full. (Never rate-limit a resize:
// the clear must be followed by its redraw in the same render.)
final size = terminal.size;
final resized = _lastSize != null && size != _lastSize;
// Frame rate limiting using Stopwatch (immune to clock adjustments)
if (!resized && _frameStopwatch.isRunning) {
if (_frameStopwatch.elapsed < _options.frameTime) {
// Skip this frame
_metrics.endFrame(skipped: true);
return;
}
}
if (resized) {
terminal.clearScreen();
_lastView = null;
_lastFrame = null;
}
// Skip if view hasn't changed
if (content == _lastView) {
_metrics.endFrame(skipped: true);
return;
}
final output = _options.ansiCompress ? compressAnsi(content) : content;
// A frame taller than the terminal cannot be diffed or drawn in full
// without scrolling the screen, which would shift everything under the
// diff's absolute row addressing. This is a transient mid-resize state
// (the app has not rebuilt its view for the new size yet): draw it
// clipped and keep the baseline invalid, so the first frame that fits
// repaints in full.
final parsedFrame = TerminalRenderFrame.parse(output);
final oversize =
_lineCount(content) > size.height ||
parsedFrame.lines.any(
(line) => renderedLineDisplayWidth(line) > size.width,
);
if (!terminal.supportsAnsi || _lastFrame == null || oversize) {
_renderFullRedraw(output, clearBefore: oversize);
_lastFrame = oversize ? null : TerminalRenderFrame.parse(output);
} else {
_renderDiffFrame(_lastFrame!, parsedFrame);
_lastFrame = parsedFrame;
}
_lastView = oversize ? null : content;
_lastSize = size;
// Reset and start the stopwatch for next frame timing
_frameStopwatch.reset();
_frameStopwatch.start();
_metrics.endFrame();
}