sanitizeForDisplay function
Returns a copy of input with every unsafe rune (see isUnsafeRune)
replaced by replacementCharacter.
Escape-led terminal control sequences are collapsed as a unit rather than replacing only the ESC byte. That prevents active payloads such as OSC 52 clipboard writes, OSC 8 hyperlinks, Sixel/DCS data, or Kitty/APC image data from leaking into displayed text after the leading control byte is removed.
This is the single safety boundary between strings produced by widget code (which may contain arbitrary, possibly hostile content) and the renderer's cell buffer. Application code should never bypass it.
Implementation
String sanitizeForDisplay(String input) {
// Fast path: scan once for any unsafe rune; if none, return the input
// unchanged. Common case for app strings is "no controls at all."
if (isSanitizedForDisplay(input)) return input;
final buffer = StringBuffer();
var index = 0;
while (index < input.length) {
final unit = input.codeUnitAt(index);
if (unit == _esc) {
buffer.write(replacementCharacter);
index = _escapeSequenceEnd(input, index);
continue;
}
if (unit == _csi) {
buffer.write(replacementCharacter);
index = _csiSequenceEnd(input, index + 1);
continue;
}
if (unit == _osc) {
buffer.write(replacementCharacter);
index = _terminatedControlStringEnd(input, index + 1, allowBel: true);
continue;
}
if (_isC1StringControl(unit)) {
buffer.write(replacementCharacter);
index = _terminatedControlStringEnd(input, index + 1);
continue;
}
if (isUnsafeRune(unit)) {
buffer.write(replacementCharacter);
index += 1;
continue;
}
if (_isHighSurrogate(unit) &&
index + 1 < input.length &&
_isLowSurrogate(input.codeUnitAt(index + 1))) {
buffer.write(input.substring(index, index + 2));
index += 2;
} else {
// A lone surrogate half is written as-is (it is not a control byte),
// but it must not carry the NEXT unit with it: that unit could be an
// ESC, and the text model now rests on this function's output being
// canonical.
buffer.writeCharCode(unit);
index += 1;
}
}
return buffer.toString();
}