public String getExpectedText(PsiBuilder builder) { int position = builder.rawTokenIndex(); StringBuilder sb = new StringBuilder(); if (addExpected(sb, position, true)) { sb.append(" expected, "); } return sb.toString(); }
public String getExpectedText(PsiBuilder builder_) { int offset = builder_.getCurrentOffset(); StringBuilder sb = new StringBuilder(); if (addExpected(sb, offset, true)) { sb.append(" expected, "); } else if (addExpected(sb, offset, false)) sb.append(" unexpected, "); return sb.toString(); }
private boolean addExpected(StringBuilder sb, int position, boolean expected) { MyList<Variant> list = expected ? variants : unexpected; String[] strings = new String[list.size()]; long[] hashes = new long[strings.length]; Arrays.fill(strings, ""); int count = 0; loop: for (Variant variant : list) { if (position == variant.position) { String text = variant.object.toString(); long hash = StringHash.calc(text); for (int i = 0; i < count; i++) { if (hashes[i] == hash) continue loop; } hashes[count] = hash; strings[count] = text; count++; } } Arrays.sort(strings); count = 0; for (String s : strings) { if (s.length() == 0) continue; if (count++ > 0) { if (count > MAX_VARIANTS_TO_DISPLAY) { sb.append(" and ..."); break; } else { sb.append(", "); } } char c = s.charAt(0); String displayText = c == '<' || StringUtil.isJavaIdentifierStart(c) ? s : '\'' + s + '\''; sb.append(displayText); } if (count > 1 && count < MAX_VARIANTS_TO_DISPLAY) { int idx = sb.lastIndexOf(", "); sb.replace(idx, idx + 1, " or"); } return count > 0; }
@NotNull @Override public PsiTypeParameter createTypeParameter(String name, PsiClassType[] superTypes) { @NonNls StringBuilder builder = new StringBuilder(); builder.append("public <").append(name); if (superTypes.length > 1 || superTypes.length == 1 && !superTypes[0].equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) { builder.append(" extends "); for (PsiClassType type : superTypes) { if (type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) continue; builder.append(type.getCanonicalText()).append('&'); } builder.delete(builder.length() - 1, builder.length()); } builder.append("> void foo(){}"); try { return createMethodFromText(builder.toString(), null).getTypeParameters()[0]; } catch (RuntimeException e) { throw new IncorrectOperationException("type parameter text: " + builder.toString()); } }
@NotNull @Override public PsiDocTag createParamTag( @NotNull final String parameterName, @NonNls final String description) throws IncorrectOperationException { @NonNls final StringBuilder builder = new StringBuilder(); builder.append(" * @param "); builder.append(parameterName); builder.append(" "); final String[] strings = description.split("\\n"); for (int i = 0; i < strings.length; i++) { if (i > 0) builder.append("\n * "); builder.append(strings[i]); } return createDocTagFromText(builder.toString()); }
@NotNull @Override public PsiReferenceList createReferenceList( @NotNull final PsiJavaCodeReferenceElement[] references) throws IncorrectOperationException { @NonNls final StringBuilder builder = new StringBuilder(); builder.append("void method()"); if (references.length > 0) { builder.append(" throws "); for (int i = 0; i < references.length; i++) { if (i > 0) builder.append(", "); builder.append(references[i].getCanonicalText()); } } builder.append(';'); return createMethodFromText(builder.toString(), null).getThrowsList(); }
@NotNull @Override public PsiParameterList createParameterList( @NotNull final String[] names, @NotNull final PsiType[] types) throws IncorrectOperationException { @NonNls StringBuilder builder = new StringBuilder(); builder.append("void method("); for (int i = 0; i < names.length; i++) { if (i > 0) builder.append(", "); builder.append(types[i].getCanonicalText()).append(' ').append(names[i]); } builder.append(");"); return createMethodFromText(builder.toString(), null).getParameterList(); }
/** * Generates a comment if possible. * * <p>It's assumed that this method {@link PsiDocumentManager#commitDocument(Document) syncs} all * PSI-document changes during the processing. * * @param anchor target element for which a comment should be generated * @param editor target editor * @param commenter commenter to use * @param project current project */ private static void generateComment( @NotNull PsiElement anchor, @NotNull Editor editor, @NotNull CodeDocumentationProvider documentationProvider, @NotNull CodeDocumentationAwareCommenter commenter, @NotNull Project project) { Document document = editor.getDocument(); int commentStartOffset = anchor.getTextRange().getStartOffset(); int lineStartOffset = document.getLineStartOffset(document.getLineNumber(commentStartOffset)); if (lineStartOffset > 0 && lineStartOffset < commentStartOffset) { // Example: // void test1() { // } // void test2() { // <offset> // } // We want to insert the comment at the start of the line where 'test2()' is declared. int nonWhiteSpaceOffset = CharArrayUtil.shiftBackward(document.getCharsSequence(), commentStartOffset - 1, " \t"); commentStartOffset = Math.max(nonWhiteSpaceOffset, lineStartOffset); } int commentBodyRelativeOffset = 0; int caretOffsetToSet = -1; StringBuilder buffer = new StringBuilder(); String commentPrefix = commenter.getDocumentationCommentPrefix(); if (commentPrefix != null) { buffer.append(commentPrefix).append("\n"); commentBodyRelativeOffset += commentPrefix.length() + 1; } String linePrefix = commenter.getDocumentationCommentLinePrefix(); if (linePrefix != null) { buffer.append(linePrefix); commentBodyRelativeOffset += linePrefix.length(); caretOffsetToSet = commentStartOffset + commentBodyRelativeOffset; } buffer.append("\n"); commentBodyRelativeOffset++; String commentSuffix = commenter.getDocumentationCommentSuffix(); if (commentSuffix != null) { buffer.append(commentSuffix).append("\n"); } if (buffer.length() <= 0) { return; } document.insertString(commentStartOffset, buffer); PsiDocumentManager docManager = PsiDocumentManager.getInstance(project); docManager.commitDocument(document); Pair<PsiElement, PsiComment> pair = documentationProvider.parseContext(anchor); if (pair == null || pair.second == null) { return; } String stub = documentationProvider.generateDocumentationContentStub(pair.second); CaretModel caretModel = editor.getCaretModel(); if (stub != null) { int insertionOffset = commentStartOffset + commentBodyRelativeOffset; // if (CodeStyleSettingsManager.getSettings(project).JD_ADD_BLANK_AFTER_DESCRIPTION) { // buffer.setLength(0); // if (linePrefix != null) { // buffer.append(linePrefix); // } // buffer.append("\n"); // buffer.append(stub); // stub = buffer.toString(); // } document.insertString(insertionOffset, stub); docManager.commitDocument(document); pair = documentationProvider.parseContext(anchor); } if (caretOffsetToSet >= 0) { caretModel.moveToOffset(caretOffsetToSet); } if (pair == null || pair.second == null) { return; } int start = Math.min(calcStartReformatOffset(pair.first), calcStartReformatOffset(pair.second)); int end = pair.second.getTextRange().getEndOffset(); CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); codeStyleManager.reformatText(anchor.getContainingFile(), start, end); int caretOffset = caretModel.getOffset(); if (caretOffset > 0 && caretOffset <= document.getTextLength()) { char c = document.getCharsSequence().charAt(caretOffset - 1); if (!StringUtil.isWhiteSpace(c)) { document.insertString(caretOffset, " "); caretModel.moveToOffset(caretOffset + 1); } } }
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(); }