getTextTruncatedWidth function
({bool ellipsed, int index, bool truncated, num width})
getTextTruncatedWidth(
- String input, {
- num limit = double.infinity,
- String ellipsis = '',
- num? ellipsisWidth,
- num controlWidth = 0,
- num tabWidth = 8,
- num emojiWidth = 2,
- num regularWidth = 1,
- num? wideWidth,
})
Implementation
({num width, int index, bool truncated, bool ellipsed}) getTextTruncatedWidth(
String input, {
/*------------- Truncation ----------------*/
num limit = double.infinity,
String ellipsis = '',
num? ellipsisWidth,
/*------------- Special Width ----------------*/
num controlWidth = 0,
num tabWidth = 8,
/*------------- Other Width ----------------*/
num emojiWidth = 2,
num regularWidth = 1,
num? wideWidth,
}) {
ellipsisWidth ??= ellipsis.isNotEmpty
? getTextTruncatedWidth(
ellipsis,
controlWidth: controlWidth,
tabWidth: tabWidth,
emojiWidth: emojiWidth,
regularWidth: regularWidth,
wideWidth: wideWidth,
).width
: 0;
const ansiWidth = 0, fullWideWidth = 2;
wideWidth ??= fullWideWidth;
final blocks = [
(_latinPattern, regularWidth),
(_ansiPattern, ansiWidth),
(_controlPattern, controlWidth),
(_tabPattern, tabWidth),
(_emojiPattern, emojiWidth),
(_cjktWidePattern, wideWidth),
];
int indexPrev = 0,
index = 0,
length = input.length,
lengthExtra = 0,
unmatchedStart = 0,
unmatchedEnd = 0,
truncationIndex = length;
num truncationLimit = math.max(0, limit - ellipsisWidth),
width = 0,
widthExtra = 0;
bool truncationEnabled = false;
parser:
while (true) {
if (unmatchedEnd > unmatchedStart ||
(index >= length && index > indexPrev)) {
String unmatched = input.safeSubstring(unmatchedStart, unmatchedEnd);
if (unmatched.isEmpty) unmatched = input.safeSubstring(indexPrev, index);
lengthExtra = 0;
for (final char in unmatched.replaceAll(_modifierPattern, '').split('')) {
final charCode = char.safeCodeUnitAt(0);
// dart format off
// ignore: curly_braces_in_flow_control_structures
if (_isFullWidth(charCode)) widthExtra = fullWideWidth;
// ignore: curly_braces_in_flow_control_structures
else if (_isWideNotCjktNoEmmoji(charCode)) widthExtra = wideWidth;
// ignore: curly_braces_in_flow_control_structures
else widthExtra = regularWidth;
// dart format on
if ((width + widthExtra) > truncationLimit) {
truncationIndex = math.min(
truncationIndex,
math.max(unmatchedStart, indexPrev) + lengthExtra,
);
}
if ((width + widthExtra) > limit) {
truncationEnabled = true;
break parser;
}
lengthExtra += char.length;
width += widthExtra;
}
unmatchedStart = unmatchedEnd = 0;
}
if (index >= length) break parser;
for (final (blockPattern, blockWidth) in blocks) {
if (blockPattern.matchAsPrefix(input, index) case final Match match) {
lengthExtra = blockPattern == _cjktWidePattern
? _getCodePointLength(input.safeSubstring(index, match.end))
: blockPattern == _emojiPattern
? 1
: match.end - index;
widthExtra = lengthExtra * blockWidth;
if ((width + widthExtra) > truncationLimit) {
truncationIndex = math.min(
truncationIndex,
index + ((truncationLimit - width) / blockWidth).safeFloor(),
);
}
if ((width + widthExtra) > limit) {
truncationEnabled = true;
break parser;
}
width += widthExtra;
unmatchedStart = indexPrev;
unmatchedEnd = index;
index = indexPrev = match.end;
continue parser;
}
}
index += 1;
}
return (
width: (truncationEnabled ? truncationLimit : width),
index: truncationEnabled ? truncationIndex : length,
truncated: truncationEnabled,
ellipsed: truncationEnabled && limit >= ellipsisWidth,
);
}