private void appendChange(@NotNull Range range, @NotNull ChangedLines<T> newChange) {
    ChangedLines<T> lastItem = ContainerUtil.getLastItem(myBlock.changes);
    if (lastItem != null && lastItem.y2 < newChange.y1) {
      finishBlock();
    }

    List<ChangedLines<T>> changes = myBlock.changes;
    List<Range> ranges = myBlock.ranges;

    if (ContainerUtil.getLastItem(ranges) != range) {
      ranges.add(range);
    }

    if (changes.isEmpty()) {
      changes.add(newChange);
      return;
    }

    ChangedLines<T> lastChange = changes.remove(changes.size() - 1);

    if (lastChange.y1 == lastChange.y2 &&
        newChange.y1 == newChange.y2) {
      assert lastChange.y1 == newChange.y1;
      byte type = mergeTypes(lastChange, newChange);
      T flags = myFlagsProvider.mergeFlags(lastChange.flags, newChange.flags);
      changes.add(new ChangedLines<>(lastChange.y1, lastChange.y2, type, flags));
    }
    else if (lastChange.y1 == lastChange.y2 && newChange.type == Range.EQUAL ||
             newChange.y1 == newChange.y2 && lastChange.type == Range.EQUAL) {
      changes.add(lastChange);
      changes.add(newChange);
    }
    else if (lastChange.type == newChange.type &&
             Objects.equals(lastChange.flags, newChange.flags)) {
      int union1 = Math.min(lastChange.y1, newChange.y1);
      int union2 = Math.max(lastChange.y2, newChange.y2);
      changes.add(new ChangedLines<>(union1, union2, lastChange.type, lastChange.flags));
    }
    else {
      int intersection1 = Math.max(lastChange.y1, newChange.y1);
      int intersection2 = Math.min(lastChange.y2, newChange.y2);

      if (lastChange.y1 != intersection1) {
        changes.add(new ChangedLines<>(lastChange.y1, intersection1, lastChange.type, lastChange.flags));
      }

      if (intersection1 != intersection2) {
        byte type = mergeTypes(lastChange, newChange);
        T flags = myFlagsProvider.mergeFlags(lastChange.flags, newChange.flags);
        changes.add(new ChangedLines<>(intersection1, intersection2, type, flags));
      }

      if (newChange.y2 != intersection2) {
        changes.add(new ChangedLines<>(intersection2, newChange.y2, newChange.type, newChange.flags));
      }
    }
  }
private void appendChange(@NotNull Range range, @NotNull ChangedLines<T> newChange)