CachedData rebuild() {
    List<FoldRegion> visible = new ArrayList<>(myMarkerTree.size());

    SweepProcessor.Generator<FoldRegionImpl> generator = processor -> myMarkerTree.processOverlappingWith(0, Integer.MAX_VALUE, processor);
    SweepProcessor.sweep(generator, new SweepProcessor<>() {
      FoldRegionImpl lastCollapsedRegion;

      @Override
      public boolean process(int offset,
                             @NotNull FoldRegionImpl region,
                             boolean atStart,
                             @NotNull Collection<? extends FoldRegionImpl> overlapping) {
        if (atStart) {
          if (lastCollapsedRegion == null || region.getEndOffset() > lastCollapsedRegion.getEndOffset() ||
              region instanceof CustomFoldRegion &&
              region.getStartOffset() == lastCollapsedRegion.getStartOffset() &&
              region.getEndOffset() == lastCollapsedRegion.getEndOffset()) {
            if (!region.isExpanded()) {
              hideContainedRegions(region);
              lastCollapsedRegion = region;
            }
            visible.add(region);
          }
        }
        return true;
      }

      private void hideContainedRegions(FoldRegion region) {
        for (int i = visible.size() - 1; i >= 0; i--) {
          if (region.getStartOffset() == visible.get(i).getStartOffset()) {
            visible.remove(i);
          }
          else {
            break;
          }
        }
      }
    });

    FoldRegion[] visibleRegions = toFoldArray(visible);

    Arrays.sort(visibleRegions, BY_END_OFFSET_REVERSE);

    return updateCachedAndSortOffsets(visibleRegions, true);
  }
CachedData rebuild()