@Nullable private static String getDocumentationText(final DartComponent dartComponent) { // PSI is not perfect currently, doc comment may be not part of the corresponding DartComponent // element, so docs are searched for in several places: // - direct child of this DartComponent // - previous sibling (or previous sibling of parent element if this element is first child of // its parent DartClassMembers) // Consequent line doc comments (///) are joined // 1. Look for multiline doc comment as direct child final DartDocComment multilineComment = PsiTreeUtil.getChildOfType(dartComponent, DartDocComment.class); if (multilineComment != null) return getMultilineDocCommentText(multilineComment); // 2. Look for single line doc comments as direct children final PsiComment[] childComments = PsiTreeUtil.getChildrenOfType(dartComponent, PsiComment.class); if (childComments != null) { // final String docText = getSingleLineDocCommentsText(childComments); if (docText != null) return docText; } PsiElement anchorElement = dartComponent; final PsiElement parent = dartComponent.getParent(); if (parent instanceof DartClassMembers && parent.getFirstChild() == dartComponent || dartComponent instanceof DartVarAccessDeclaration) { anchorElement = parent; } // 3. Look for multiline doc comment or line doc comments as previous siblings final List<PsiComment> siblingComments = new ArrayList<PsiComment>(); PsiElement previous = anchorElement; while ((previous = UsefulPsiTreeUtil.getPrevSiblingSkipWhiteSpaces(previous, true)) instanceof PsiComment) { if (previous instanceof DartDocComment) { return getMultilineDocCommentText((DartDocComment) previous); } siblingComments.add(0, (PsiComment) previous); } if (!siblingComments.isEmpty()) { return getSingleLineDocCommentsText( siblingComments.toArray(new PsiComment[siblingComments.size()])); } return null; }
public Indent getChildIndent(final ASTNode node) { final IElementType elementType = node.getElementType(); final ASTNode prevSibling = UsefulPsiTreeUtil.getPrevSiblingSkipWhiteSpacesAndComments(node); final IElementType prevSiblingType = prevSibling == null ? null : prevSibling.getElementType(); final ASTNode parent = node.getTreeParent(); final IElementType parentType = parent != null ? parent.getElementType() : null; final ASTNode superParent = parent == null ? null : parent.getTreeParent(); final IElementType superParentType = superParent == null ? null : superParent.getElementType(); final int braceStyle = superParentType == FUNCTION_BODY ? settings.METHOD_BRACE_STYLE : settings.BRACE_STYLE; if (parent == null || parent.getTreeParent() == null || parentType == EMBEDDED_CONTENT) { return Indent.getNoneIndent(); } if (elementType == MULTI_LINE_COMMENT_BODY) { return Indent.getContinuationIndent(); } if (elementType == DOC_COMMENT_LEADING_ASTERISK || elementType == MULTI_LINE_COMMENT_END) { return Indent.getSpaceIndent(1, true); } if (settings.KEEP_FIRST_COLUMN_COMMENT && (elementType == SINGLE_LINE_COMMENT || elementType == MULTI_LINE_COMMENT)) { final ASTNode previousNode = node.getTreePrev(); if (previousNode != null && previousNode.getElementType() == WHITE_SPACE && previousNode.getText().endsWith("\n")) { return Indent.getAbsoluteNoneIndent(); } } if (COMMENTS.contains(elementType) && prevSiblingType == LBRACE && parentType == CLASS_BODY) { return Indent.getNormalIndent(); } if (parentType == ENUM_DEFINITION && isBetweenBraces(node)) { // instead of isBetweenBraces(node) we can parse enum block as a separate ASTNode, or build // formatter blocks not tied to AST. return Indent.getNormalIndent(); } if (parentType == MAP_LITERAL_EXPRESSION || parentType == LIST_LITERAL_EXPRESSION) { if (elementType == LBRACE || elementType == RBRACE || elementType == LBRACKET || elementType == RBRACKET) { return Indent.getNoneIndent(); } if (elementType == TYPE_ARGUMENTS) { return Indent.getNoneIndent(); } // Be careful to preserve typing behavior. if (elementType == MAP_LITERAL_ENTRY || elementType == EXPRESSION_LIST || elementType == COMMA) { return Indent.getNormalIndent(); } if (COMMENTS.contains(elementType)) { return Indent.getNormalIndent(); } return Indent.getNoneIndent(); } if (elementType == LBRACE || elementType == RBRACE) { switch (braceStyle) { case CommonCodeStyleSettings.END_OF_LINE: if (elementType == LBRACE && FormatterUtil.isPrecededBy(parent, SINGLE_LINE_COMMENT, WHITE_SPACE)) { // Use Nystrom style rather than Allman. return Indent.getContinuationIndent(); } // FALL THROUGH case CommonCodeStyleSettings.NEXT_LINE: case CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED: return Indent.getNoneIndent(); case CommonCodeStyleSettings.NEXT_LINE_SHIFTED: case CommonCodeStyleSettings.NEXT_LINE_SHIFTED2: return Indent.getNormalIndent(); default: return Indent.getNoneIndent(); } } if (parentType == PARENTHESIZED_EXPRESSION) { if (elementType == LPAREN || elementType == RPAREN) { return Indent.getNoneIndent(); } return Indent.getContinuationIndent(); } if (elementType == CLASS_MEMBERS) { return Indent.getNormalIndent(); } if (parentType == BLOCK) { final PsiElement psi = node.getPsi(); if (psi.getParent() instanceof PsiFile) { return Indent.getNoneIndent(); } return Indent.getNormalIndent(); } if (parentType == ARGUMENT_LIST) { // TODO In order to handle some dart_style examples we need to set indent for each arg. // The formatter does not appear to honor indent on individual argument expressions // when KEEP_LINE_BREAKS==true. That means two DartFormatterTest tests fail. Those tests // have been changed since the recommended setting for Dart programming is // KEEP_LINE_BREAKS==false. The two tests are testAlignment() and testWrappingMeth(). if (EXPRESSIONS.contains(elementType) && elementType != FUNCTION_EXPRESSION) { return Indent.getContinuationIndent(); } } if (parentType == FORMAL_PARAMETER_LIST) { return Indent.getContinuationIndent(); } if (parentType == FOR_STATEMENT && prevSiblingType == FOR_LOOP_PARTS_IN_BRACES && elementType != BLOCK) { return Indent.getNormalIndent(); } if (parentType == SWITCH_STATEMENT && (elementType == SWITCH_CASE || elementType == DEFAULT_CASE)) { return Indent.getNormalIndent(); } if ((parentType == SWITCH_CASE || parentType == DEFAULT_CASE) && elementType == STATEMENTS) { return Indent.getNormalIndent(); } if (parentType == WHILE_STATEMENT && prevSiblingType == RPAREN && elementType != BLOCK) { return Indent.getNormalIndent(); } if (parentType == DO_WHILE_STATEMENT && prevSiblingType == DO && elementType != BLOCK) { return Indent.getNormalIndent(); } if ((parentType == RETURN_STATEMENT) && prevSiblingType == RETURN && elementType != BLOCK) { return Indent.getNormalIndent(); } if (parentType == IF_STATEMENT && elementType != BLOCK && (prevSiblingType == RPAREN || (prevSiblingType == ELSE && elementType != IF_STATEMENT))) { return Indent.getNormalIndent(); } if (elementType == CASCADE_REFERENCE_EXPRESSION) { return Indent.getNormalIndent(); } if (elementType == OPEN_QUOTE && prevSiblingType == CLOSING_QUOTE && parentType == STRING_LITERAL_EXPRESSION) { return Indent.getContinuationIndent(); } if (BINARY_EXPRESSIONS.contains(parentType) && prevSibling != null) { return Indent.getContinuationIndent(); } if (elementType == COLON || parentType == TERNARY_EXPRESSION && elementType == QUEST) { return Indent.getContinuationIndent(); } if (elementType == NAMED_ARGUMENT) { return Indent.getContinuationIndent(); } if (elementType == HIDE_COMBINATOR || elementType == SHOW_COMBINATOR) { return Indent.getContinuationIndent(); } if (parentType == FUNCTION_BODY) { if (FormatterUtil.isPrecededBy(node, EXPRESSION_BODY_DEF)) { return Indent.getContinuationIndent(); } } if (elementType == CALL_EXPRESSION) { if (FormatterUtil.isPrecededBy(node, EXPRESSION_BODY_DEF)) { return Indent.getContinuationIndent(); } if (FormatterUtil.isPrecededBy(node, ASSIGNMENT_OPERATOR)) { return Indent.getContinuationIndent(); } } if ((elementType == REFERENCE_EXPRESSION || BINARY_EXPRESSIONS.contains(elementType)) && FormatterUtil.isPrecededBy(node, ASSIGNMENT_OPERATOR)) { return Indent.getContinuationIndent(); } if (elementType == VAR_DECLARATION_LIST_PART) { return Indent.getContinuationIndent(); } if (elementType == SUPER_CALL_OR_FIELD_INITIALIZER) { return Indent.getContinuationIndent(); } if (parentType == SUPER_CALL_OR_FIELD_INITIALIZER && elementType != COLON) { return Indent.getNormalIndent(); } if (parentType == CLASS_DEFINITION) { if (elementType == SUPERCLASS || elementType == INTERFACES || elementType == MIXINS) { return Indent.getContinuationIndent(); } } if (parentType == MIXIN_APPLICATION && elementType == MIXINS) { return Indent.getContinuationIndent(); } if (parentType == LIBRARY_NAME_ELEMENT) { return Indent.getContinuationIndent(); } if (elementType == SEMICOLON && FormatterUtil.isPrecededBy(node, SINGLE_LINE_COMMENT, WHITE_SPACE)) { return Indent.getContinuationIndent(); } if (elementType == DOT || elementType == QUEST_DOT) { return Indent.getContinuationIndent(); } if (parentType == TYPE_LIST && elementType == TYPE) { return Indent.getContinuationIndent(); } if (elementType == OPEN_QUOTE && parentType == STRING_LITERAL_EXPRESSION && superParentType == VAR_INIT) { if (node.getText().length() < 3) { return Indent.getContinuationIndent(); } } if (elementType == RAW_SINGLE_QUOTED_STRING && parentType == STRING_LITERAL_EXPRESSION && superParentType == VAR_INIT) { return Indent.getContinuationIndent(); } if (parentType == LONG_TEMPLATE_ENTRY && EXPRESSIONS.contains(elementType)) { return Indent.getContinuationIndent(); } return Indent.getNoneIndent(); }