@Override
  public TextContent excludeRanges(List<Exclusion> ranges) {
    ProgressManager.checkCanceled();
    if (ranges.isEmpty()) return this;

    if (ranges.get(0).start < 0 || ranges.get(ranges.size() - 1).end > length()) {
      throw new IllegalArgumentException("Text ranges " + ranges + " should be between 0 and " + length());
    }
    for (int i = 1; i < ranges.size(); i++) {
      if (ranges.get(i - 1).end > ranges.get(i).start) {
        throw new IllegalArgumentException("Ranges should be sorted and non-intersecting: " + ranges);
      }
    }

    int[] offsets = getTokenOffsets();
    List<Exclusion>[] affectingExclusions = getAffectingExclusions(ranges, offsets);

    List<TokenInfo> newTokens = new ArrayList<>();
    for (int i = 0; i < tokens.size(); i++) {
      List<Exclusion> affecting = affectingExclusions[i];
      TokenInfo token = tokens.get(i);
      if (affecting == null) {
        newTokens.add(token);
      } else if (token instanceof PsiToken) {
        newTokens.addAll(((PsiToken)token).splitToken(offsets[i], affecting));
      }
    }

    if (newTokens.isEmpty()) {
      PsiToken first = (PsiToken) tokens.get(0);
      TokenKind kind1 = first.kind;
      TokenKind kind2 = ((PsiToken)tokens.get(tokens.size() - 1)).kind;
      TokenKind mostUnknown = kind1.compareTo(kind2) > 0 ? kind1 : kind2;
      newTokens.add(new PsiToken("", first.psi, TextRange.from(first.rangeInPsi.getStartOffset(), 0), mostUnknown));
    }
    
    return new TextContentImpl(domain, newTokens);
  }
@Override
  public TextContent excludeRanges(List<Exclusion> ranges)