collectStyle method
Returns style for specified text range.
Only attributes applied to all characters within this range are included in the result. Inline and line level attributes are handled separately, e.g.:
- line attribute X is included in the result only if it exists for every line within this range (partially included lines are counted).
- inline attribute X is included in the result only if it exists for every character within this range (line-break characters excluded).
In essence, it is INTERSECTION of each individual segment's styles
Implementation
Style collectStyle(int offset, int len) {
final local = math.min(length - offset, len);
var result = const Style();
final excluded = <Attribute>{};
void handle(Style style) {
for (final attr in result.values) {
if (!style.containsKey(attr.key) ||
(style.attributes[attr.key]?.value != attr.value)) {
excluded.add(attr);
}
}
result = result.removeAll(excluded);
}
final data = queryChild(offset, true);
var node = data.node as Leaf?;
if (node != null) {
result = node.style;
var pos = node.length - data.offset;
while (!node!.isLast && pos < local) {
node = node.next as Leaf;
handle(node.style);
pos += node.length;
}
}
/// Blank lines do not have style and must get the active style from prior line
if (isEmpty) {
var prevLine = previous;
while (prevLine is Block && prevLine.isNotEmpty) {
prevLine = prevLine.children.last;
}
if (prevLine is Line) {
result = result.mergeAll(prevLine.collectStyle(prevLine.length - 1, 1));
}
} else {
result = result.mergeAll(style);
}
if (parent is Block) {
final block = parent as Block;
result = result.mergeAll(block.style);
}
var remaining = len - local;
var nxt = nextLine;
/// Skip over empty lines that have no attributes
while (remaining > 0 && nxt != null && nxt.isEmpty) {
remaining--;
nxt = nxt.nextLine;
}
if (remaining > 0 && nxt != null) {
final rest = nxt.collectStyle(0, remaining);
handle(rest);
}
return result;
}