protected void moveCaretInsideBracesIfAny(
      @NotNull final Editor editor, @NotNull final PsiFile file)
      throws IncorrectOperationException {
    int caretOffset = editor.getCaretModel().getOffset();
    final CharSequence chars = editor.getDocument().getCharsSequence();

    if (CharArrayUtil.regionMatches(chars, caretOffset, "{}")) {
      caretOffset += 2;
    } else if (CharArrayUtil.regionMatches(chars, caretOffset, "{\n}")) {
      caretOffset += 3;
    }

    caretOffset = CharArrayUtil.shiftBackward(chars, caretOffset - 1, " \t") + 1;

    if (CharArrayUtil.regionMatches(chars, caretOffset - "{}".length(), "{}")
        || CharArrayUtil.regionMatches(chars, caretOffset - "{\n}".length(), "{\n}")) {
      commit(editor);
      final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(file.getProject());
      final boolean old = settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE;
      settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = false;
      PsiElement elt =
          PsiTreeUtil.getParentOfType(file.findElementAt(caretOffset - 1), PsiCodeBlock.class);
      reformat(elt);
      settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = old;
      editor.getCaretModel().moveToOffset(caretOffset - 1);
    }
  }
 @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;
 }
  private boolean isLineCommented(
      final int line, final CharSequence chars, final Commenter commenter) {
    boolean commented;
    int lineEndForBlockCommenting = -1;
    int lineStart = myDocument.getLineStartOffset(line);
    lineStart = CharArrayUtil.shiftForward(chars, lineStart, " \t");

    if (commenter instanceof SelfManagingCommenter) {
      final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter) commenter;
      commented =
          selfManagingCommenter.isLineCommented(
              line, lineStart, myDocument, myCommenterStateMap.get(selfManagingCommenter));
    } else {
      String prefix = commenter.getLineCommentPrefix();

      if (prefix != null) {
        commented =
            CharArrayUtil.regionMatches(chars, lineStart, prefix)
                || prefix.endsWith(" ")
                    && CharArrayUtil.regionMatches(chars, lineStart, prefix.trim() + "\n");
      } else {
        prefix = commenter.getBlockCommentPrefix();
        String suffix = commenter.getBlockCommentSuffix();
        final int textLength = myDocument.getTextLength();
        lineEndForBlockCommenting = myDocument.getLineEndOffset(line);
        if (lineEndForBlockCommenting == textLength) {
          final int shifted = CharArrayUtil.shiftBackward(chars, textLength - 1, " \t");
          if (shifted < textLength - 1) lineEndForBlockCommenting = shifted;
        } else {
          lineEndForBlockCommenting =
              CharArrayUtil.shiftBackward(chars, lineEndForBlockCommenting, " \t");
        }
        commented =
            lineStart == lineEndForBlockCommenting && myStartLine != myEndLine
                || CharArrayUtil.regionMatches(chars, lineStart, prefix)
                    && CharArrayUtil.regionMatches(
                        chars, lineEndForBlockCommenting - suffix.length(), suffix);
      }
    }

    if (commented) {
      myStartOffsets[line - myStartLine] = lineStart;
      myEndOffsets[line - myStartLine] = lineEndForBlockCommenting;
    }

    return commented;
  }
 private int getCommentStart(int line) {
   int offset = myDocument.getLineStartOffset(line);
   CharSequence chars = myDocument.getCharsSequence();
   offset = CharArrayUtil.shiftForward(chars, offset, " \t");
   final Commenter commenter = findCommenter(line);
   if (commenter == null) return -1;
   String prefix = commenter.getLineCommentPrefix();
   if (prefix == null) prefix = commenter.getBlockCommentPrefix();
   if (prefix == null) return -1;
   return CharArrayUtil.regionMatches(chars, offset, prefix) ? offset : -1;
 }
  private Couple<TextRange> findCommentBlock(
      TextRange range, String commentPrefix, String commentSuffix) {
    CharSequence chars = myDocument.getCharsSequence();
    int startOffset = range.getStartOffset();
    boolean endsProperly =
        CharArrayUtil.regionMatches(
            chars, range.getEndOffset() - commentSuffix.length(), commentSuffix);

    TextRange start = expandRange(startOffset, startOffset + commentPrefix.length());
    TextRange end;
    if (endsProperly) {
      end = expandRange(range.getEndOffset() - commentSuffix.length(), range.getEndOffset());
    } else {
      end = new TextRange(range.getEndOffset(), range.getEndOffset());
    }

    return Couple.of(start, end);
  }
 private void uncommentRange(int startOffset, int endOffset, @NotNull Commenter commenter) {
   final String commentedSuffix = commenter.getCommentedBlockCommentSuffix();
   final String commentedPrefix = commenter.getCommentedBlockCommentPrefix();
   final String prefix = commenter.getBlockCommentPrefix();
   final String suffix = commenter.getBlockCommentSuffix();
   if (prefix == null || suffix == null) {
     return;
   }
   if (endOffset >= suffix.length()
       && CharArrayUtil.regionMatches(
           myDocument.getCharsSequence(), endOffset - suffix.length(), suffix)) {
     myDocument.deleteString(endOffset - suffix.length(), endOffset);
   }
   if (commentedPrefix != null && commentedSuffix != null) {
     CommentByBlockCommentHandler.commentNestedComments(
         myDocument, new TextRange(startOffset, endOffset), commenter);
   }
   myDocument.deleteString(startOffset, startOffset + prefix.length());
 }
  @Override
  public PsiDocTag findTagByName(String name) {
    if (getFirstChildNode().getElementType() == JavaDocElementType.DOC_COMMENT) {
      if (getFirstChildNode().getText().indexOf(name) < 0) return null;
    }

    for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) {
      if (child.getElementType() == DOC_TAG) {
        PsiDocTag tag = (PsiDocTag) SourceTreeToPsiMap.treeElementToPsi(child);
        final CharSequence nameText = ((LeafElement) tag.getNameElement()).getChars();

        if (nameText.length() > 0
            && nameText.charAt(0) == '@'
            && CharArrayUtil.regionMatches(nameText, 1, name)) {
          return tag;
        }
      }
    }

    return null;
  }
    private boolean insertDocAsterisk(
        int lineStart,
        boolean docAsterisk,
        boolean previousLineIndentUsed,
        CodeDocumentationAwareCommenter commenter) {
      PsiElement atLineStart = myFile.findElementAt(lineStart);
      if (atLineStart == null) return false;

      final String linePrefix = commenter.getDocumentationCommentLinePrefix();
      final String docPrefix = commenter.getDocumentationCommentPrefix();

      final String text = atLineStart.getText();
      final TextRange textRange = atLineStart.getTextRange();

      if (text.equals(linePrefix)
          || text.equals(docPrefix)
          || docPrefix != null
              && text.regionMatches(
                  lineStart - textRange.getStartOffset(), docPrefix, 0, docPrefix.length())
          || linePrefix != null
              && text.regionMatches(
                  lineStart - textRange.getStartOffset(), linePrefix, 0, linePrefix.length())) {
        PsiElement element = myFile.findElementAt(myOffset);
        if (element == null) return false;

        PsiComment comment =
            element instanceof PsiComment
                ? (PsiComment) element
                : PsiTreeUtil.getParentOfType(element, PsiComment.class, false);
        if (comment != null) {
          int commentEnd = comment.getTextRange().getEndOffset();
          if (myOffset >= commentEnd) {
            docAsterisk = false;
          } else {
            removeTrailingSpaces(myDocument, myOffset);
            String toInsert =
                previousLineIndentUsed
                    ? "*"
                    : CodeDocumentationUtil.createDocCommentLine("", getProject(), commenter);
            myDocument.insertString(myOffset, toInsert);
            PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
          }
        } else {
          docAsterisk = false;
        }
      } else if (linePrefix != null
          && atLineStart instanceof PsiComment
          && ((PsiComment) atLineStart).getTokenType() == commenter.getBlockCommentTokenType()) {
        // Check if C-Style comment already uses asterisks.
        boolean usesAstersk = false;
        int commentLine = myDocument.getLineNumber(textRange.getStartOffset());
        if (commentLine < myDocument.getLineCount() - 1 && textRange.getEndOffset() >= myOffset) {
          int nextLineOffset = myDocument.getLineStartOffset(commentLine + 1);
          if (nextLineOffset < textRange.getEndOffset()) {
            final CharSequence chars = myDocument.getCharsSequence();
            nextLineOffset = CharArrayUtil.shiftForward(chars, nextLineOffset, " \t");
            usesAstersk = CharArrayUtil.regionMatches(chars, nextLineOffset, linePrefix);
          }
        }
        if (usesAstersk) {
          removeTrailingSpaces(myDocument, myOffset);
          myDocument.insertString(myOffset, linePrefix + " ");
          PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
        }
        docAsterisk = usesAstersk;
      } else {
        docAsterisk = false;
      }
      return docAsterisk;
    }
    private void generateJavadoc(CodeDocumentationAwareCommenter commenter)
        throws IncorrectOperationException {
      CodeInsightSettings settings = CodeInsightSettings.getInstance();
      StringBuilder buffer = new StringBuilder();
      final String docCommentLinePrefix = commenter.getDocumentationCommentLinePrefix();
      if (docCommentLinePrefix == null) {
        return;
      }

      // There are at least two approaches for completing javadoc in case there is a text between
      // current caret position and line end:
      //     1. Move that tail text below the javadoc. Use-case:
      //         Before:
      //             /**<caret>public void foo() {}
      //         After:
      //             /**
      //              */
      //             public void foo() {}
      //     2. Move the tail text inside the javadoc. Use-case:
      //          Before:
      //             /**This is <caret>javadoc description
      //          After:
      //             /** This is
      //              * javadoc description
      //              */
      // The later is most relevant when we have 'auto wrap when typing reaches right margin' option
      // set, i.e. user starts javadoc
      // and types until right margin is reached. We want the wrapped text tail to be located inside
      // javadoc and continue typing
      // inside it. So, we have a control flow branch below that does the trick.
      buffer.append(docCommentLinePrefix);
      if (DataManager.getInstance()
              .loadFromDataContext(
                  myDataContext, AutoHardWrapHandler.AUTO_WRAP_LINE_IN_PROGRESS_KEY)
          == Boolean.TRUE) {
        myDocument.insertString(myOffset, buffer);

        // We create new buffer here because the one referenced by current 'buffer' variable value
        // may be already referenced at another
        // place (e.g. 'undo' processing stuff).
        buffer =
            new StringBuilder(LINE_SEPARATOR).append(commenter.getDocumentationCommentSuffix());
        int line = myDocument.getLineNumber(myOffset);
        myOffset = myDocument.getLineEndOffset(line);
      } else {
        buffer.append(LINE_SEPARATOR);
        buffer.append(commenter.getDocumentationCommentSuffix());
      }

      PsiComment comment = createComment(buffer, settings);
      if (comment == null) {
        return;
      }

      myOffset = comment.getTextRange().getStartOffset();
      CharSequence text = myDocument.getCharsSequence();
      myOffset = CharArrayUtil.shiftForwardUntil(text, myOffset, LINE_SEPARATOR);
      myOffset = CharArrayUtil.shiftForward(text, myOffset, LINE_SEPARATOR);
      myOffset = CharArrayUtil.shiftForwardUntil(text, myOffset, docCommentLinePrefix) + 1;
      removeTrailingSpaces(myDocument, myOffset);

      if (!CodeStyleSettingsManager.getSettings(getProject()).JD_LEADING_ASTERISKS_ARE_ENABLED) {
        LOG.assertTrue(
            CharArrayUtil.regionMatches(
                myDocument.getCharsSequence(),
                myOffset - docCommentLinePrefix.length(),
                docCommentLinePrefix));
        myDocument.deleteString(myOffset - docCommentLinePrefix.length(), myOffset);
        myOffset--;
      } else {
        myDocument.insertString(myOffset, " ");
        myOffset++;
      }

      PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
    }
  private void commentLine(int line, int offset, @Nullable Commenter commenter) {
    if (commenter == null) commenter = findCommenter(line);
    if (commenter == null) return;
    if (commenter instanceof SelfManagingCommenter) {
      final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter) commenter;
      selfManagingCommenter.commentLine(
          line, offset, myDocument, myCommenterStateMap.get(selfManagingCommenter));
      return;
    }

    String prefix = commenter.getLineCommentPrefix();
    if (prefix != null) {
      if (commenter instanceof CommenterWithLineSuffix) {
        int endOffset = myDocument.getLineEndOffset(line);
        endOffset = CharArrayUtil.shiftBackward(myDocument.getCharsSequence(), endOffset, " \t");
        int shiftedStartOffset =
            CharArrayUtil.shiftForward(myDocument.getCharsSequence(), offset, " \t");
        String lineSuffix = ((CommenterWithLineSuffix) commenter).getLineCommentSuffix();
        if (!CharArrayUtil.regionMatches(
            myDocument.getCharsSequence(), shiftedStartOffset, prefix)) {
          if (!CharArrayUtil.regionMatches(
              myDocument.getCharsSequence(), endOffset - lineSuffix.length(), lineSuffix)) {
            myDocument.insertString(endOffset, lineSuffix);
          }
          myDocument.insertString(offset, prefix);
        }
      } else {
        myDocument.insertString(offset, prefix);
      }
    } else {
      prefix = commenter.getBlockCommentPrefix();
      String suffix = commenter.getBlockCommentSuffix();
      if (prefix == null || suffix == null) return;
      int endOffset = myDocument.getLineEndOffset(line);
      if (endOffset == offset && myStartLine != myEndLine) return;
      final int textLength = myDocument.getTextLength();
      final CharSequence chars = myDocument.getCharsSequence();
      offset = CharArrayUtil.shiftForward(chars, offset, " \t");
      if (endOffset == textLength) {
        final int shifted = CharArrayUtil.shiftBackward(chars, textLength - 1, " \t");
        if (shifted < textLength - 1) endOffset = shifted;
      } else {
        endOffset = CharArrayUtil.shiftBackward(chars, endOffset, " \t");
      }
      if (endOffset < offset || offset == textLength - 1 && line != myDocument.getLineCount() - 1) {
        return;
      }
      final String text = chars.subSequence(offset, endOffset).toString();
      final IntArrayList prefixes = new IntArrayList();
      final IntArrayList suffixes = new IntArrayList();
      final String commentedSuffix = commenter.getCommentedBlockCommentSuffix();
      final String commentedPrefix = commenter.getCommentedBlockCommentPrefix();
      for (int position = 0; position < text.length(); ) {
        int nearestPrefix = text.indexOf(prefix, position);
        if (nearestPrefix == -1) {
          nearestPrefix = text.length();
        }
        int nearestSuffix = text.indexOf(suffix, position);
        if (nearestSuffix == -1) {
          nearestSuffix = text.length();
        }
        if (Math.min(nearestPrefix, nearestSuffix) == text.length()) {
          break;
        }
        if (nearestPrefix < nearestSuffix) {
          prefixes.add(nearestPrefix);
          position = nearestPrefix + prefix.length();
        } else {
          suffixes.add(nearestSuffix);
          position = nearestSuffix + suffix.length();
        }
      }
      if (!(commentedSuffix == null
          && !suffixes.isEmpty()
          && offset + suffixes.get(suffixes.size() - 1) + suffix.length() >= endOffset)) {
        myDocument.insertString(endOffset, suffix);
      }
      int nearestPrefix = prefixes.size() - 1;
      int nearestSuffix = suffixes.size() - 1;
      while (nearestPrefix >= 0 || nearestSuffix >= 0) {
        if (nearestSuffix == -1
            || nearestPrefix != -1 && prefixes.get(nearestPrefix) > suffixes.get(nearestSuffix)) {
          final int position = prefixes.get(nearestPrefix);
          nearestPrefix--;
          if (commentedPrefix != null) {
            myDocument.replaceString(
                offset + position, offset + position + prefix.length(), commentedPrefix);
          } else if (position != 0) {
            myDocument.insertString(offset + position, suffix);
          }
        } else {
          final int position = suffixes.get(nearestSuffix);
          nearestSuffix--;
          if (commentedSuffix != null) {
            myDocument.replaceString(
                offset + position, offset + position + suffix.length(), commentedSuffix);
          } else if (offset + position + suffix.length() < endOffset) {
            myDocument.insertString(offset + position + suffix.length(), prefix);
          }
        }
      }
      if (!(commentedPrefix == null && !prefixes.isEmpty() && prefixes.get(0) == 0)) {
        myDocument.insertString(offset, prefix);
      }
    }
  }
  private void uncommentLine(int line) {
    Commenter commenter = myCommenters[line - myStartLine];
    if (commenter == null) commenter = findCommenter(line);
    if (commenter == null) return;

    final int startOffset = myStartOffsets[line - myStartLine];

    if (commenter instanceof SelfManagingCommenter) {
      final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter) commenter;
      selfManagingCommenter.uncommentLine(
          line, startOffset, myDocument, myCommenterStateMap.get(selfManagingCommenter));
      return;
    }

    final int endOffset = myEndOffsets[line - myStartLine];
    if (startOffset == endOffset) {
      return;
    }
    String prefix = commenter.getLineCommentPrefix();
    if (prefix != null) {
      CharSequence chars = myDocument.getCharsSequence();

      if (commenter instanceof CommenterWithLineSuffix) {
        CommenterWithLineSuffix commenterWithLineSuffix = (CommenterWithLineSuffix) commenter;
        String suffix = commenterWithLineSuffix.getLineCommentSuffix();

        int theEnd = endOffset > 0 ? endOffset : myDocument.getLineEndOffset(line);
        while (theEnd > startOffset && Character.isWhitespace(chars.charAt(theEnd - 1))) {
          theEnd--;
        }

        String lineText = myDocument.getText(new TextRange(startOffset, theEnd));
        if (lineText.indexOf(suffix) != -1) {
          int start = startOffset + lineText.indexOf(suffix);
          myDocument.deleteString(start, start + suffix.length());
        }
      }

      boolean skipNewLine = false;
      boolean commented =
          CharArrayUtil.regionMatches(chars, startOffset, prefix)
              || (skipNewLine =
                  prefix.endsWith(" ")
                      && CharArrayUtil.regionMatches(chars, startOffset, prefix.trim() + "\n"));
      assert commented;

      int charsToDelete = skipNewLine ? prefix.trim().length() : prefix.length();
      int theEnd = endOffset > 0 ? endOffset : chars.length();
      // if there's exactly one space after line comment prefix and before the text that follows in
      // the same line, delete the space too
      if (startOffset + charsToDelete < theEnd - 1
          && chars.charAt(startOffset + charsToDelete) == ' ') {
        if (startOffset + charsToDelete == theEnd - 2
            || chars.charAt(startOffset + charsToDelete + 1) != ' ') {
          charsToDelete++;
        }
      }
      myDocument.deleteString(startOffset, startOffset + charsToDelete);
      return;
    }
    String text = myDocument.getCharsSequence().subSequence(startOffset, endOffset).toString();

    prefix = commenter.getBlockCommentPrefix();
    final String suffix = commenter.getBlockCommentSuffix();
    if (prefix == null || suffix == null) {
      return;
    }

    IntArrayList prefixes = new IntArrayList();
    IntArrayList suffixes = new IntArrayList();
    for (int position = 0; position < text.length(); ) {
      int prefixPos = text.indexOf(prefix, position);
      if (prefixPos == -1) {
        break;
      }
      prefixes.add(prefixPos);
      position = prefixPos + prefix.length();
      int suffixPos = text.indexOf(suffix, position);
      if (suffixPos == -1) {
        suffixPos = text.length() - suffix.length();
      }
      suffixes.add(suffixPos);
      position = suffixPos + suffix.length();
    }

    assert prefixes.size() == suffixes.size();

    for (int i = prefixes.size() - 1; i >= 0; i--) {
      uncommentRange(
          startOffset + prefixes.get(i),
          Math.min(startOffset + suffixes.get(i) + suffix.length(), endOffset),
          commenter);
    }
  }
  private TextRange insertNestedComments(
      int startOffset,
      int endOffset,
      String commentPrefix,
      String commentSuffix,
      Commenter commenter) {
    if (commenter instanceof SelfManagingCommenter) {
      final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter) commenter;
      return selfManagingCommenter.insertBlockComment(
          startOffset, endOffset, myDocument, mySelfManagedCommenterData);
    }

    String normalizedPrefix = commentPrefix.trim();
    String normalizedSuffix = commentSuffix.trim();
    IntArrayList nestedCommentPrefixes = new IntArrayList();
    IntArrayList nestedCommentSuffixes = new IntArrayList();
    String commentedPrefix = commenter.getCommentedBlockCommentPrefix();
    String commentedSuffix = commenter.getCommentedBlockCommentSuffix();
    CharSequence chars = myDocument.getCharsSequence();
    for (int i = startOffset; i < endOffset; ++i) {
      if (CharArrayUtil.regionMatches(chars, i, normalizedPrefix)) {
        nestedCommentPrefixes.add(i);
      } else {
        if (CharArrayUtil.regionMatches(chars, i, normalizedSuffix)) {
          nestedCommentSuffixes.add(i);
        }
      }
    }
    int shift = 0;
    if (!(commentedSuffix == null
        && !nestedCommentSuffixes.isEmpty()
        && nestedCommentSuffixes.get(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.get(i);
      final int suffixIndex = nestedCommentSuffixes.get(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.get(i);
      shift +=
          doBoundCommentingAndGetShift(
              prefixIndex,
              commentedPrefix,
              normalizedPrefix.length(),
              commentSuffix,
              false,
              selection);
      --i;
    }
    while (j >= 0) {
      final int suffixIndex = nestedCommentSuffixes.get(j);
      shift +=
          doBoundCommentingAndGetShift(
              suffixIndex,
              commentedSuffix,
              normalizedSuffix.length(),
              commentPrefix,
              true,
              selection);
      --j;
    }
    if (!(commentedPrefix == null
        && !nestedCommentPrefixes.isEmpty()
        && nestedCommentPrefixes.get(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();
    }
  }