wrapTextAsLines function
Wraps a block of text into lines no longer than length
,
starting at the start
column, and returns the result as a list of strings.
Tries to split at whitespace, but if that's not good enough to keep it under the limit, then splits in the middle of a word. Preserves embedded newlines, but not indentation (it trims whitespace from each line).
If length
is not specified, then no wrapping occurs, and the original
text
is returned after splitting it on newlines. Whitespace is not trimmed
in this case.
Implementation
List<String> wrapTextAsLines(String text, {int start = 0, int? length}) {
assert(start >= 0);
/// Returns true if the code unit at [index] in [text] is a whitespace
/// character.
///
/// Based on: https://en.wikipedia.org/wiki/Whitespace_character#Unicode
bool isWhitespace(String text, int index) {
var rune = text.codeUnitAt(index);
return rune >= 0x0009 && rune <= 0x000D ||
rune == 0x0020 ||
rune == 0x0085 ||
rune == 0x1680 ||
rune == 0x180E ||
rune >= 0x2000 && rune <= 0x200A ||
rune == 0x2028 ||
rune == 0x2029 ||
rune == 0x202F ||
rune == 0x205F ||
rune == 0x3000 ||
rune == 0xFEFF;
}
if (length == null) return text.split('\n');
var result = <String>[];
var effectiveLength = math.max(length - start, 10);
for (var line in text.split('\n')) {
line = line.trim();
if (line.length <= effectiveLength) {
result.add(line);
continue;
}
var currentLineStart = 0;
int? lastWhitespace;
for (var i = 0; i < line.length; ++i) {
if (isWhitespace(line, i)) lastWhitespace = i;
if (i - currentLineStart >= effectiveLength) {
// Back up to the last whitespace, unless there wasn't any, in which
// case we just split where we are.
if (lastWhitespace != null) i = lastWhitespace;
result.add(line.substring(currentLineStart, i).trim());
// Skip any intervening whitespace.
while (isWhitespace(line, i) && i < line.length) {
i++;
}
currentLineStart = i;
lastWhitespace = null;
}
}
result.add(line.substring(currentLineStart).trim());
}
return result;
}