private @Nullable TextRange insertNestedComments(int startOffset,
                                                   int endOffset,
                                                   String commentPrefix,
                                                   String commentSuffix,
                                                   Commenter commenter) {
    if (commenter instanceof SelfManagingCommenter selfManagingCommenter) {
      return selfManagingCommenter.insertBlockComment(
        startOffset,
        endOffset,
        myDocument,
        mySelfManagedCommenterData
      );
    }

    String normalizedPrefix = commentPrefix.trim();
    String normalizedSuffix = commentSuffix.trim();
    IntList nestedCommentPrefixes = new IntArrayList();
    IntList nestedCommentSuffixes = new IntArrayList();
    String commentedPrefix = commenter.getCommentedBlockCommentPrefix();
    String commentedSuffix = commenter.getCommentedBlockCommentSuffix();
    CharSequence chars = myDocument.getCharsSequence();
    boolean canDetectBlockComments = canDetectBlockComments();
    boolean warnAboutNestedComments = false;
    for (int i = startOffset; i < endOffset; ++i) {
      if (CharArrayUtil.regionMatches(chars, i, normalizedPrefix)) {
        if (commentedPrefix == null && canDetectBlockComments) {
          TextRange commentRange = getBlockCommentAt(i);
          // skipping prefixes outside of comments (e.g. in string literals) and inside comments
          if (commentRange == null || commentRange.getStartOffset() != i) {
            continue;
          }
          else {
            warnAboutNestedComments = true;
          }
        }
        nestedCommentPrefixes.add(i);
      }
      else if (CharArrayUtil.regionMatches(chars, i, normalizedSuffix)) {
        if (commentedSuffix == null && canDetectBlockComments) {
          TextRange commentRange = getBlockCommentAt(i);
          if (commentRange == null) {
            myWarning = CodeInsightBundle.message("block.comment.wrapping.suffix");
            myWarningLocation = myDocument.createRangeMarker(i, i);
            return null;
          }
        }
        nestedCommentSuffixes.add(i);
      }
    }
    if (warnAboutNestedComments) {
      myWarning = CodeInsightBundle.message("block.comment.nested.comment", nestedCommentPrefixes.size());
      myWarningLocation = myDocument.createRangeMarker(nestedCommentPrefixes.getInt(0),
                                                       nestedCommentPrefixes.getInt(0) + normalizedPrefix.length());
    }
    int shift = 0;
    if (!(commentedSuffix == null &&
          !nestedCommentSuffixes.isEmpty() &&
          nestedCommentSuffixes.getInt(nestedCommentSuffixes.size() - 1) + commentSuffix.length() == endOffset)) {
      myDocument.insertString(endOffset, commentSuffix);
      shift += commentSuffix.length();
    }

    // process nested comments in back order
    int i = nestedCommentPrefixes.size() - 1;
    int j = nestedCommentSuffixes.size() - 1;
    final TextRange selection = new TextRange(startOffset, endOffset);
    while (i >= 0 && j >= 0) {
      final int prefixIndex = nestedCommentPrefixes.getInt(i);
      final int suffixIndex = nestedCommentSuffixes.getInt(j);
      if (prefixIndex > suffixIndex) {
        shift += doBoundCommentingAndGetShift(prefixIndex, commentedPrefix, normalizedPrefix.length(), commentSuffix, false, selection);
        --i;
      }
      else {
        //if (insertPos < myDocument.getTextLength() && Character.isWhitespace(myDocument.getCharsSequence().charAt(insertPos))) {
        //  insertPos = suffixIndex + commentSuffix.length();
        //}
        shift += doBoundCommentingAndGetShift(suffixIndex, commentedSuffix, normalizedSuffix.length(), commentPrefix, true, selection);
        --j;
      }
    }
    while (i >= 0) {
      final int prefixIndex = nestedCommentPrefixes.getInt(i);
      shift += doBoundCommentingAndGetShift(prefixIndex, commentedPrefix, normalizedPrefix.length(), commentSuffix, false, selection);
      --i;
    }
    while (j >= 0) {
      final int suffixIndex = nestedCommentSuffixes.getInt(j);
      shift += doBoundCommentingAndGetShift(suffixIndex, commentedSuffix, normalizedSuffix.length(), commentPrefix, true, selection);
      --j;
    }
    if (!(commentedPrefix == null && !nestedCommentPrefixes.isEmpty() && nestedCommentPrefixes.getInt(0) == startOffset)) {
      myDocument.insertString(startOffset, commentPrefix);
      shift += commentPrefix.length();
    }

    RangeMarker marker = myDocument.createRangeMarker(startOffset, endOffset + shift);
    try {
      return processDocument(myDocument, marker, commenter, true);
    }
    finally {
      marker.dispose();
    }
  }
private @Nullable TextRange insertNestedComments(int startOffset,
                                                   int endOffset,
                                                   String commentPrefix,
                                                   String commentSuffix,
                                                   Commenter commenter)