@Nullable
 private TextRange getSelectedComments(CharSequence text, String prefix, String suffix) {
   TextRange commentedRange = null;
   if (myCaret.hasSelection()) {
     int selectionStart = myCaret.getSelectionStart();
     selectionStart = CharArrayUtil.shiftForward(text, selectionStart, " \t\n");
     int selectionEnd = myCaret.getSelectionEnd() - 1;
     selectionEnd = CharArrayUtil.shiftBackward(text, selectionEnd, " \t\n") + 1;
     if (selectionEnd - selectionStart >= prefix.length() + suffix.length()
         && CharArrayUtil.regionMatches(text, selectionStart, prefix)
         && CharArrayUtil.regionMatches(text, selectionEnd - suffix.length(), suffix)) {
       commentedRange = new TextRange(selectionStart, selectionEnd);
     }
   }
   return commentedRange;
 }
  @Nullable
  private PsiElement findCommentAtCaret() {
    int offset = myCaret.getOffset();
    TextRange range = new TextRange(myCaret.getSelectionStart(), myCaret.getSelectionEnd());
    if (offset == range.getEndOffset()) {
      offset--;
    }
    if (offset <= range.getStartOffset()) {
      offset++;
    }
    PsiElement elt = myFile.getViewProvider().findElementAt(offset);
    if (elt == null) return null;
    PsiElement comment = PsiTreeUtil.getParentOfType(elt, PsiComment.class, false);
    if (comment == null || myCaret.hasSelection() && !range.contains(comment.getTextRange())) {
      return null;
    }

    return comment;
  }
 private boolean testSelectionForNonComments() {
   if (!myCaret.hasSelection()) {
     return true;
   }
   TextRange range = new TextRange(myCaret.getSelectionStart(), myCaret.getSelectionEnd() - 1);
   for (PsiElement element = myFile.findElementAt(range.getStartOffset());
       element != null && range.intersects(element.getTextRange());
       element = element.getNextSibling()) {
     if (element instanceof OuterLanguageElement) {
       if (!isInjectedWhiteSpace(range, (OuterLanguageElement) element)) {
         return false;
       }
     } else {
       if (!isWhiteSpaceOrComment(element, range)) {
         return false;
       }
     }
   }
   return true;
 }
  @Override
  public void invoke(
      @NotNull Project project,
      @NotNull Editor editor,
      @NotNull Caret caret,
      @NotNull PsiFile file) {
    if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return;
    myProject = project;
    myEditor = editor;
    myCaret = caret;
    myFile = file;

    myDocument = editor.getDocument();

    if (!FileDocumentManager.getInstance().requestWriting(myDocument, project)) {
      return;
    }
    FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.comment.block");
    final Commenter commenter = findCommenter(myFile, myEditor, caret);
    if (commenter == null) return;

    final String prefix;
    final String suffix;

    if (commenter instanceof SelfManagingCommenter) {
      final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter) commenter;
      mySelfManagedCommenterData =
          selfManagingCommenter.createBlockCommentingState(
              caret.getSelectionStart(), caret.getSelectionEnd(), myDocument, myFile);

      if (mySelfManagedCommenterData == null) {
        mySelfManagedCommenterData = SelfManagingCommenter.EMPTY_STATE;
      }

      prefix =
          selfManagingCommenter.getBlockCommentPrefix(
              caret.getSelectionStart(), myDocument, mySelfManagedCommenterData);
      suffix =
          selfManagingCommenter.getBlockCommentSuffix(
              caret.getSelectionEnd(), myDocument, mySelfManagedCommenterData);
    } else {
      prefix = commenter.getBlockCommentPrefix();
      suffix = commenter.getBlockCommentSuffix();
    }

    if (prefix == null || suffix == null) return;

    TextRange commentedRange = findCommentedRange(commenter);
    if (commentedRange != null) {
      final int commentStart = commentedRange.getStartOffset();
      final int commentEnd = commentedRange.getEndOffset();
      int selectionStart = commentStart;
      int selectionEnd = commentEnd;
      if (myCaret.hasSelection()) {
        selectionStart = myCaret.getSelectionStart();
        selectionEnd = myCaret.getSelectionEnd();
      }
      if ((commentStart < selectionStart || commentStart >= selectionEnd)
          && (commentEnd <= selectionStart || commentEnd > selectionEnd)) {
        commentRange(selectionStart, selectionEnd, prefix, suffix, commenter);
      } else {
        uncommentRange(commentedRange, trim(prefix), trim(suffix), commenter);
      }
    } else {
      if (myCaret.hasSelection()) {
        int selectionStart = myCaret.getSelectionStart();
        int selectionEnd = myCaret.getSelectionEnd();
        if (commenter instanceof IndentedCommenter) {
          final Boolean value = ((IndentedCommenter) commenter).forceIndentedLineComment();
          if (value != null && value == Boolean.TRUE) {
            selectionStart =
                myDocument.getLineStartOffset(myDocument.getLineNumber(selectionStart));
            selectionEnd = myDocument.getLineEndOffset(myDocument.getLineNumber(selectionEnd));
          }
        }
        commentRange(selectionStart, selectionEnd, prefix, suffix, commenter);
      } else {
        EditorUtil.fillVirtualSpaceUntilCaret(editor);
        int caretOffset = myCaret.getOffset();
        if (commenter instanceof IndentedCommenter) {
          final Boolean value = ((IndentedCommenter) commenter).forceIndentedLineComment();
          if (value != null && value == Boolean.TRUE) {
            final int lineNumber = myDocument.getLineNumber(caretOffset);
            final int start = myDocument.getLineStartOffset(lineNumber);
            final int end = myDocument.getLineEndOffset(lineNumber);
            commentRange(start, end, prefix, suffix, commenter);
            return;
          }
        }
        myDocument.insertString(caretOffset, prefix + suffix);
        myCaret.moveToOffset(caretOffset + prefix.length());
      }
    }
  }