public static String getNewText(PsiElement elt) { Project project = elt.getProject(); PsiFile psiFile = getContainingFile(elt); final Document doc = PsiDocumentManager.getInstance(project).getDocument(psiFile); if (doc == null) return null; final ImplementationTextSelectioner implementationTextSelectioner = LanguageImplementationTextSelectioner.INSTANCE.forLanguage(elt.getLanguage()); int start = implementationTextSelectioner.getTextStartOffset(elt); final int end = implementationTextSelectioner.getTextEndOffset(elt); final int lineStart = doc.getLineStartOffset(doc.getLineNumber(start)); final int lineEnd = end < doc.getTextLength() ? doc.getLineEndOffset(doc.getLineNumber(end)) : doc.getTextLength(); return doc.getCharsSequence().subSequence(lineStart, lineEnd).toString(); }
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; }
@Override public void run() { CaretModel caretModel = myEditor.getCaretModel(); try { final CharSequence chars = myDocument.getCharsSequence(); int i = CharArrayUtil.shiftBackwardUntil(chars, myOffset - 1, LINE_SEPARATOR) - 1; i = CharArrayUtil.shiftBackwardUntil(chars, i, LINE_SEPARATOR) + 1; if (i < 0) i = 0; int lineStart = CharArrayUtil.shiftForward(chars, i, " \t"); CodeDocumentationUtil.CommentContext commentContext = CodeDocumentationUtil.tryParseCommentContext(myFile, chars, myOffset, lineStart); PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(getProject()); if (commentContext.docStart) { PsiElement element = myFile.findElementAt(commentContext.lineStart); final String text = element.getText(); final PsiElement parent = element.getParent(); if (text.equals(commentContext.commenter.getDocumentationCommentPrefix()) && isDocComment(parent, commentContext.commenter) || text.startsWith(commentContext.commenter.getDocumentationCommentPrefix()) && element instanceof PsiComment) { PsiComment comment = isDocComment(parent, commentContext.commenter) ? (PsiComment) parent : (PsiComment) element; int commentEnd = comment.getTextRange().getEndOffset(); if (myOffset >= commentEnd) { commentContext.docStart = false; } else { if (isCommentComplete(comment, commentContext.commenter, myEditor)) { if (myOffset >= commentEnd) { commentContext.docAsterisk = false; commentContext.docStart = false; } else { commentContext.docAsterisk = true; commentContext.docStart = false; } } else { generateJavadoc(commentContext.commenter); } } } else { commentContext.docStart = false; } } else if (commentContext.cStyleStart) { PsiElement element = myFile.findElementAt(commentContext.lineStart); if (element instanceof PsiComment && commentContext.commenter.getBlockCommentTokenType() == ((PsiComment) element).getTokenType()) { final PsiComment comment = (PsiComment) element; int commentEnd = comment.getTextRange().getEndOffset(); if (myOffset >= commentEnd && myOffset < myFile.getTextRange().getEndOffset()) { commentContext.docStart = false; } else { if (isCommentComplete(comment, commentContext.commenter, myEditor)) { if (myOffset >= commentEnd) { commentContext.docAsterisk = false; commentContext.docStart = false; } else { commentContext.docAsterisk = true; commentContext.docStart = false; } } else { final int currentEndOfLine = CharArrayUtil.shiftForwardUntil(chars, myOffset, "\n"); myDocument.insertString( currentEndOfLine, " " + commentContext.commenter.getBlockCommentSuffix()); int lstart = CharArrayUtil.shiftBackwardUntil(chars, myOffset, "\n"); myDocument.insertString(currentEndOfLine, chars.subSequence(lstart, myOffset)); psiDocumentManager.commitDocument(myDocument); } } } else { commentContext.docStart = false; } } String indentInsideJavadoc = null; if (myOffset < myDocument.getTextLength()) { final int line = myDocument.getLineNumber(myOffset); if (line > 0 && (commentContext.docAsterisk || commentContext.docStart)) { indentInsideJavadoc = CodeDocumentationUtil.getIndentInsideJavadoc( myDocument, myDocument.getLineStartOffset(line - 1)); } } if (commentContext.docAsterisk) { commentContext.docAsterisk = insertDocAsterisk( commentContext.lineStart, commentContext.docAsterisk, !StringUtil.isEmpty(indentInsideJavadoc), commentContext.commenter); } boolean docIndentApplied = false; CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); if (codeInsightSettings.SMART_INDENT_ON_ENTER || myForceIndent || commentContext.docStart || commentContext.docAsterisk || commentContext.slashSlash) { final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(getProject()); myOffset = codeStyleManager.adjustLineIndent(myFile, myOffset); psiDocumentManager.commitAllDocuments(); if (!StringUtil.isEmpty(indentInsideJavadoc) && myOffset < myDocument.getTextLength()) { myDocument.insertString(myOffset + 1, indentInsideJavadoc); myOffset += indentInsideJavadoc.length(); docIndentApplied = true; } if (myForceIndent && indentInsideJavadoc != null) { int indentSize = CodeStyleSettingsManager.getSettings(myProject).getIndentSize(myFile.getFileType()); myDocument.insertString(myOffset + 1, StringUtil.repeatSymbol(' ', indentSize)); myCaretAdvance += indentSize; } } if ((commentContext.docAsterisk || commentContext.docStart || commentContext.slashSlash) && !docIndentApplied) { if (myInsertSpace) { if (myOffset == myDocument.getTextLength()) { myDocument.insertString(myOffset, " "); } myDocument.insertString(myOffset + 1, " "); } final char c = myDocument.getCharsSequence().charAt(myOffset); if (c != '\n') { myOffset += 1; } } if ((commentContext.docAsterisk || commentContext.slashSlash) && !commentContext.docStart) { myCaretAdvance += commentContext.slashSlash ? commentContext.commenter.getLineCommentPrefix().length() : 1; } } catch (IncorrectOperationException e) { LOG.error(e); } myOffset = Math.min(myOffset, myDocument.getTextLength()); caretModel.moveToOffset(myOffset); myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); myEditor.getSelectionModel().removeSelection(); if (myCaretAdvance != 0) { LogicalPosition caretPosition = caretModel.getLogicalPosition(); LogicalPosition pos = new LogicalPosition(caretPosition.line, caretPosition.column + myCaretAdvance); caretModel.moveToLogicalPosition(pos); } }
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(); }
@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()); } } }