in lib/src/highlighter.dart [128:185]
static List<_Line> _collateLines(List<_Highlight> highlights) {
// Assign spans without URLs opaque Objects as keys. Each such Object will
// be different, but they can then be used later on to determine which lines
// came from the same span even if they'd all otherwise have `null` URLs.
final highlightsByUrl = groupBy<_Highlight, Object>(
highlights, (highlight) => highlight.span.sourceUrl ?? Object());
for (var list in highlightsByUrl.values) {
list.sort((highlight1, highlight2) =>
highlight1.span.compareTo(highlight2.span));
}
return highlightsByUrl.entries.expand((entry) {
final url = entry.key;
final highlightsForFile = entry.value;
// First, create a list of all the lines in the current file that we have
// context for along with their line numbers.
final lines = <_Line>[];
for (var highlight in highlightsForFile) {
final context = highlight.span.context;
// If [highlight.span.context] contains lines prior to the one
// [highlight.span.text] appears on, write those first.
final lineStart = findLineStart(
context, highlight.span.text, highlight.span.start.column)!;
final linesBeforeSpan =
'\n'.allMatches(context.substring(0, lineStart)).length;
var lineNumber = highlight.span.start.line - linesBeforeSpan;
for (var line in context.split('\n')) {
// Only add a line if it hasn't already been added for a previous span.
if (lines.isEmpty || lineNumber > lines.last.number) {
lines.add(_Line(line, lineNumber, url));
}
lineNumber++;
}
}
// Next, associate each line with each highlights that covers it.
final activeHighlights = <_Highlight>[];
var highlightIndex = 0;
for (var line in lines) {
activeHighlights
.removeWhere((highlight) => highlight.span.end.line < line.number);
final oldHighlightLength = activeHighlights.length;
for (var highlight in highlightsForFile.skip(highlightIndex)) {
if (highlight.span.start.line > line.number) break;
activeHighlights.add(highlight);
}
highlightIndex += activeHighlights.length - oldHighlightLength;
line.highlights.addAll(activeHighlights);
}
return lines;
}).toList();
}