copyAttributionRegion method

AttributedSpans copyAttributionRegion(
  1. int startOffset, [
  2. int? endOffset
])

Returns of a copy of this AttributedSpans between startOffset and endOffset.

If no endOffset is provided, a copy is made from startOffset to the offset of the last marker in this AttributedSpans.

Implementation

AttributedSpans copyAttributionRegion(int startOffset, [int? endOffset]) {
  endOffset = endOffset ?? _markers.lastOrNull?.offset ?? 0;
  _log.fine('start: $startOffset, end: $endOffset');

  final List<SpanMarker> cutAttributions = [];

  _log.fine('inspecting existing markers in full AttributedSpans');
  final Map<Attribution, int> foundStartMarkers = {};
  final Map<Attribution, int> foundEndMarkers = {};

  // Analyze all markers that appear before the start of
  // the copy range so that we can insert any appropriate
  // `start` markers at the beginning of the copy range.
  _markers //
      .where((marker) => marker.offset < startOffset) //
      .forEach((marker) {
    _log.fine('marker before the copy region: $marker');
    // Track any markers that begin before the `startOffset`
    // and continue beyond `startOffset`.
    if (marker.isStart) {
      _log.fine('remembering this marker to insert in copied region');
      foundStartMarkers.putIfAbsent(marker.attribution, () => 0);
      foundStartMarkers[marker.attribution] = foundStartMarkers[marker.attribution]! + 1;
    } else {
      _log.fine(
          'this marker counters an earlier one we found. We will not re-insert this marker in the copied region');
      foundStartMarkers.putIfAbsent(marker.attribution, () => 0);
      foundStartMarkers[marker.attribution] = foundStartMarkers[marker.attribution]! - 1;
    }
  });

  // Insert any `start` markers at the start of the copy region
  // so that we maintain attribution symmetry.
  foundStartMarkers.forEach((markerAttribution, count) {
    if (count == 1) {
      // Found an unmatched `start` marker. Replace it.
      _log.fine('inserting "$markerAttribution" marker at start of copy region to maintain symmetry.');
      cutAttributions.add(SpanMarker(
        attribution: markerAttribution,
        offset: 0,
        markerType: SpanMarkerType.start,
      ));
    } else if (count < 0 || count > 1) {
      throw Exception(
          'Found an unbalanced number of `start` and `end` markers before offset: $startOffset - $_markers');
    }
  });

  // Directly copy every marker that appears within the cut
  // region.
  _markers //
      .where((marker) => startOffset <= marker.offset && marker.offset <= endOffset!) //
      .forEach((marker) {
    _log.fine('copying "${marker.attribution}" at ${marker.offset} from original AttributionSpans to copy region.');
    cutAttributions.add(marker.copyWith(
      offset: marker.offset - startOffset,
    ));
  });

  // Analyze all markers that appear after the end of
  // the copy range so that we can insert any appropriate
  // `end` markers at the end of the copy range.
  _markers //
      .reversed //
      .where((marker) => marker.offset > endOffset!) //
      .forEach((marker) {
    _log.fine('marker after the copy region: $marker');
    // Track any markers that end after the `endOffset`
    // and start before `endOffset`.
    if (marker.isEnd) {
      _log.fine('remembering this marker to insert in copied region');
      foundEndMarkers.putIfAbsent(marker.attribution, () => 0);
      foundEndMarkers[marker.attribution] = foundEndMarkers[marker.attribution]! + 1;
    } else {
      _log.fine(
          'this marker counters an earlier one we found. We will not re-insert this marker in the copied region');
      foundEndMarkers.putIfAbsent(marker.attribution, () => 0);
      foundEndMarkers[marker.attribution] = foundEndMarkers[marker.attribution]! - 1;
    }
  });

  // Insert any `end` markers at the end of the copy region
  // so that we maintain attribution symmetry.
  foundEndMarkers.forEach((markerAttribution, count) {
    if (count == 1) {
      // Found an unmatched `end` marker. Replace it.
      _log.fine('inserting "$markerAttribution" marker at end of copy region to maintain symmetry.');
      cutAttributions.add(SpanMarker(
        attribution: markerAttribution,
        offset: endOffset! - startOffset,
        markerType: SpanMarkerType.end,
      ));
    } else if (count < 0 || count > 1) {
      throw Exception('Found an unbalanced number of `start` and `end` markers after offset: $endOffset - $_markers');
    }
  });

  _log.fine('copied attributions:');
  for (final attribution in cutAttributions) {
    _log.fine('   - $attribution');
  }

  return AttributedSpans(attributions: cutAttributions);
}