public void uncommentRange(TextRange range, String commentPrefix, String commentSuffix, Commenter commenter) {
    if (commenter instanceof SelfManagingCommenter selfManagingCommenter) {
      selfManagingCommenter.uncommentBlockComment(
        range.getStartOffset(),
        range.getEndOffset(),
        myDocument,
        mySelfManagedCommenterData
      );
      return;
    }

    String text = myDocument.getCharsSequence().subSequence(range.getStartOffset(), range.getEndOffset()).toString();
    int startOffset = range.getStartOffset();
    //boolean endsProperly = CharArrayUtil.regionMatches(chars, range.getEndOffset() - commentSuffix.length(), commentSuffix);
    List<Couple<TextRange>> ranges = new ArrayList<>();


    if (commenter instanceof CustomUncommenter customUncommenter) {
      /*
        In case of custom uncommenter, we need to ask it for list of [commentOpen-start,commentOpen-end], [commentClose-start,commentClose-end]
        and shift if according to current offset
       */
      for (Couple<TextRange> coupleFromCommenter : customUncommenter.getCommentRangesToDelete(text)) {
        TextRange openComment = coupleFromCommenter.first.shiftRight(startOffset);
        TextRange closeComment = coupleFromCommenter.second.shiftRight(startOffset);
        ranges.add(Couple.of(openComment, closeComment));
      }
    }
    else {
      // If commenter is not custom, we need to get this list by our selves
      int position = 0;
      while (true) {
        int start = getNearest(text, commentPrefix, position);
        if (start == text.length()) {
          break;
        }
        position = start;
        int end = getNearest(text, commentSuffix, position + commentPrefix.length()) + commentSuffix.length();
        position = end;
        Couple<TextRange> pair =
          findCommentBlock(new TextRange(start + startOffset, end + startOffset), commentPrefix, commentSuffix);
        ranges.add(pair);
      }
    }

    RangeMarker marker = myDocument.createRangeMarker(range);
    try {
      for (int i = ranges.size() - 1; i >= 0; i--) {
        Couple<TextRange> toDelete = ranges.get(i);
        myDocument.deleteString(toDelete.first.getStartOffset(), toDelete.first.getEndOffset());
        int shift = toDelete.first.getEndOffset() - toDelete.first.getStartOffset();
        myDocument.deleteString(toDelete.second.getStartOffset() - shift, toDelete.second.getEndOffset() - shift);
        if (commenter.getCommentedBlockCommentPrefix() != null) {
          commentNestedComments(myDocument, new TextRange(toDelete.first.getEndOffset() - shift, toDelete.second.getStartOffset() - shift),
                                commenter);
        }
      }

      processDocument(myDocument, marker, commenter, false);
    }
    finally {
      marker.dispose();
    }
  }
public void uncommentRange(TextRange range, String commentPrefix, String commentSuffix, Commenter commenter)