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(); } }