public static Spacing getSpacing( GroovyBlock child1, GroovyBlock child2, CommonCodeStyleSettings settings) { ASTNode leftNode = child1.getNode(); ASTNode rightNode = child2.getNode(); final PsiElement left = leftNode.getPsi(); final PsiElement right = rightNode.getPsi(); IElementType leftType = leftNode.getElementType(); IElementType rightType = rightNode.getElementType(); // Braces Placement // For multi-line strings if (!mirrorsAst(child1) || !mirrorsAst(child2)) { return NO_SPACING; } if (leftType == mGDOC_COMMENT_START && rightType == mGDOC_COMMENT_DATA || leftType == mGDOC_COMMENT_DATA && rightType == mGDOC_COMMENT_END) { return LAZY_SPACING; } // For type parameters if (mLT == leftType && rightNode.getPsi() instanceof GrTypeParameter || mGT == rightType && leftNode.getPsi() instanceof GrTypeParameter || mIDENT == leftType && rightNode.getPsi() instanceof GrTypeParameterList) { return NO_SPACING; } // For left parentheses in method declarations or calls if (mLPAREN.equals(rightType) && rightNode.getPsi().getParent().getNode() != null && METHOD_DEFS.contains(rightNode.getPsi().getParent().getNode().getElementType())) { return NO_SPACING; } if (ARGUMENTS.equals(rightType)) { return NO_SPACING; } // For left square bracket in array declarations and selections by index if ((mLBRACK.equals(rightType) && rightNode.getPsi().getParent().getNode() != null && INDEX_OR_ARRAY.contains(rightNode.getPsi().getParent().getNode().getElementType())) || ARRAY_DECLARATOR.equals(rightType)) { return NO_SPACING; } if (METHOD_DEFS.contains(leftType)) { if (rightType == mSEMI) { return NO_SPACING; } return Spacing.createSpacing( 0, 0, settings.BLANK_LINES_AROUND_METHOD + 1, settings.KEEP_LINE_BREAKS, 100); } if (METHOD_DEFS.contains(rightType)) { if (leftNode.getElementType() == GROOVY_DOC_COMMENT) { return Spacing.createSpacing( 0, 0, settings.BLANK_LINES_AROUND_METHOD, settings.KEEP_LINE_BREAKS, 0); } return Spacing.createSpacing( 0, 0, settings.BLANK_LINES_AROUND_METHOD + 1, settings.KEEP_LINE_BREAKS, 100); } if (leftType == mLCURLY && rightType == PARAMETERS_LIST) { // closure return LAZY_SPACING; } // For parentheses in arguments and typecasts if (LEFT_BRACES.contains(leftType) || RIGHT_BRACES.contains(rightType)) { PsiElement parent = (LEFT_BRACES.contains(leftType) ? left : right).getParent(); boolean shouldHaveSpace = parent instanceof GrTypeCastExpression && settings.SPACE_WITHIN_CAST_PARENTHESES; return shouldHaveSpace ? COMMON_SPACING : NO_SPACING_WITH_NEWLINE; } // For type parameters if ((mLT.equals(leftType) || mGT.equals(rightType)) && leftNode.getPsi().getParent() != null && leftNode.getPsi().getParent() instanceof GrTypeArgumentList) { return NO_SPACING_WITH_NEWLINE; } if (rightNode.getPsi() != null && rightNode.getPsi() instanceof GrTypeArgumentList) { return NO_SPACING_WITH_NEWLINE; } if (rightType == mCOLON && left instanceof GrParameter && left.getParent() instanceof GrForInClause) { return COMMON_SPACING; } /** ******** punctuation marks *********** */ // For dots, commas etc. if ((PUNCTUATION_SIGNS.contains(rightType)) || (mCOLON.equals(rightType) && !(rightNode.getPsi().getParent() instanceof GrConditionalExpression))) { return NO_SPACING_WITH_NEWLINE; } if (DOTS.contains(leftType)) { return NO_SPACING_WITH_NEWLINE; } /** ******** imports *********** */ if (IMPORT_STATEMENT.equals(leftType) && IMPORT_STATEMENT.equals(rightType)) { return IMPORT_BETWEEN_SPACING; } if ((IMPORT_STATEMENT.equals(leftType) && (!IMPORT_STATEMENT.equals(rightType) && !mSEMI.equals(rightType))) || ((!IMPORT_STATEMENT.equals(leftType) && !mSEMI.equals(leftType)) && IMPORT_STATEMENT.equals(rightType))) { return IMPORT_OTHER_SPACING; } // todo:check it for multiple assignments if ((VARIABLE_DEFINITION.equals(leftType) || VARIABLE_DEFINITION.equals(rightType)) && !(leftNode.getTreeNext() instanceof PsiErrorElement)) { return Spacing.createSpacing(0, 0, 1, false, 100); } /** ******** exclusions *********** */ // For << and >> ... if ((mLT.equals(leftType) && mLT.equals(rightType)) || (mGT.equals(leftType) && mGT.equals(rightType))) { return NO_SPACING_WITH_NEWLINE; } // Unary and postfix expressions if (PREFIXES.contains(leftType) || POSTFIXES.contains(rightType) || (PREFIXES_OPTIONAL.contains(leftType) && leftNode.getPsi().getParent() instanceof GrUnaryExpression)) { return NO_SPACING_WITH_NEWLINE; } if (RANGES.contains(leftType) || RANGES.contains(rightType)) { return NO_SPACING_WITH_NEWLINE; } // For Gstrings and regexes if (left.getParent() != null && left.getParent().equals(right.getParent()) && (left.getParent() instanceof GrString || leftNode.getTreeParent().getElementType() == mREGEX_LITERAL || leftNode.getTreeParent().getElementType() == mDOLLAR_SLASH_REGEX_LITERAL)) { return NO_SPACING; } if (isDollarInGStringInjection(leftNode) || isDollarInGStringInjection(rightNode)) { return NO_SPACING; } if (leftNode.getPsi().getParent() instanceof GrStringInjection && rightNode.getPsi().getParent() instanceof GrString && rightNode.getPsi().getParent().equals(leftNode.getPsi().getParent().getParent())) { return NO_SPACING; } if (mGDOC_ASTERISKS == leftType && mGDOC_COMMENT_DATA == rightType) { String text = rightNode.getText(); if (text.length() > 0 && !text.startsWith(" ")) { return COMMON_SPACING; } return NO_SPACING; } if (leftType == mGDOC_TAG_VALUE_TOKEN && rightType == mGDOC_COMMENT_DATA) { return LAZY_SPACING; } if (left instanceof GrStatement && right instanceof GrStatement && left.getParent() instanceof GrStatementOwner && right.getParent() instanceof GrStatementOwner) { return COMMON_SPACING_WITH_NL; } if (rightType == mGDOC_INLINE_TAG_END || leftType == mGDOC_INLINE_TAG_START || rightType == mGDOC_INLINE_TAG_START || leftType == mGDOC_INLINE_TAG_END) { return NO_SPACING; } if ((leftType == GDOC_INLINED_TAG && rightType == mGDOC_COMMENT_DATA) || (leftType == mGDOC_COMMENT_DATA && rightType == GDOC_INLINED_TAG)) { // Keep formatting between groovy doc text and groovy doc reference tag as is. return NO_SPACING; } if (leftType == CLASS_TYPE_ELEMENT && rightType == mTRIPLE_DOT) { return NO_SPACING; } // diamonds if (rightType == mLT || rightType == mGT) { if (right.getParent() instanceof GrCodeReferenceElement) { PsiElement p = right.getParent().getParent(); if (p instanceof GrNewExpression || p instanceof GrAnonymousClassDefinition) { return NO_SPACING; } } } if (leftType == mRPAREN && left.getParent() instanceof GrTypeCastExpression) { return settings.SPACE_AFTER_TYPE_CAST ? COMMON_SPACING : NO_SPACING; } return COMMON_SPACING; }
/** * Calculates indent, based on code style, between parent block and child node * * @param parent parent block * @param child child node * @return indent */ @NotNull public static Indent getChildIndent( @NotNull final GroovyBlock parent, @NotNull final ASTNode child) { ASTNode astNode = parent.getNode(); final PsiElement psiParent = astNode.getPsi(); // For Groovy file if (psiParent instanceof GroovyFileBase) { return Indent.getNoneIndent(); } if (psiParent instanceof GrMethod && child.getPsi() instanceof GrParameterList) { return Indent.getContinuationIndent(); } if (GSTRING_TOKENS_INNER.contains(child.getElementType()) && mGSTRING_BEGIN != child.getElementType()) { return Indent.getAbsoluteNoneIndent(); } if (psiParent instanceof GrListOrMap) { if (mLBRACK.equals(child.getElementType()) || mRBRACK.equals(child.getElementType())) { return Indent.getNoneIndent(); } else { return Indent.getContinuationWithoutFirstIndent(); } } // For common code block if (BLOCK_SET.contains(astNode.getElementType()) && !BLOCK_STATEMENT.equals(astNode.getElementType())) { return indentForBlock(psiParent, child); } if (CASE_SECTION.equals(astNode.getElementType())) { return indentForCaseSection(child); } if (SWITCH_STATEMENT.equals(astNode.getElementType())) { return indentForSwitchStatement(psiParent, child); } if (psiParent instanceof GrLabeledStatement) { if (child.getPsi() instanceof GrLabel) { CommonCodeStyleSettings.IndentOptions indentOptions = parent.getSettings().getIndentOptions(); if (indentOptions.LABEL_INDENT_ABSOLUTE) { return Indent.getAbsoluteLabelIndent(); } return Indent.getLabelIndent(); } } // for control structures if (psiParent instanceof GrControlStatement) { return getControlIndent(psiParent, child); } if (psiParent instanceof GrExpression) { return getExpressionIndent(psiParent, child); } if (psiParent instanceof GrVariable && child.getPsi() == ((GrVariable) psiParent).getInitializerGroovy()) { return Indent.getNormalIndent(); } // For parameter lists if (psiParent instanceof GrParameterList || psiParent instanceof GrExtendsClause || psiParent instanceof GrThrowsClause) { if (parent.getIndent() != null) { return Indent.getContinuationWithoutFirstIndent(); } return Indent.getNoneIndent(); } // For arguments if (psiParent instanceof GrArgumentList) { if (child.getElementType() != mLPAREN && child.getElementType() != mRPAREN /*&& child.getElementType() != mCOMMA*/) { return Indent.getContinuationWithoutFirstIndent(); } } if ((psiParent instanceof GrDocComment && child.getElementType() != mGDOC_COMMENT_START) || psiParent instanceof GrDocTag && child.getElementType() != mGDOC_TAG_NAME) { return Indent.getSpaceIndent(GDOC_COMMENT_INDENT); } if (psiParent instanceof GrNamedArgument && child.getPsi() == ((GrNamedArgument) psiParent).getExpression()) { return Indent.getContinuationIndent(); } if (child.getPsi() instanceof GrVariable && psiParent instanceof GrVariableDeclaration) { return Indent.getContinuationWithoutFirstIndent(); } return Indent.getNoneIndent(); }
private static boolean mirrorsAst(GroovyBlock block) { return block.getNode().getTextRange().equals(block.getTextRange()) || block instanceof MethodCallWithoutQualifierBlock; }