From ee9186bf36916586c82e81f3fd292a8e6acc7665 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Thu, 2 May 2013 18:46:14 +0400 Subject: [PATCH] Groovy code style settings: blank lines --- ...oovyLanguageCodeStyleSettingsProvider.java | 22 ++++ .../processors/GroovySpacingProcessor.java | 121 +++++++++++++++--- .../GroovySpacingProcessorBasic.java | 29 +---- .../lang/formatter/FormatterTest.groovy | 1 + .../OptimizeImportsTest.groovy | 4 +- .../inlineLocal/varInGString4.test | 1 + .../optimizeImports/Commented_after.groovy | 1 - 7 files changed, 132 insertions(+), 47 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeStyle/GroovyLanguageCodeStyleSettingsProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeStyle/GroovyLanguageCodeStyleSettingsProvider.java index 8ac2121e05bf..995ac822b642 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeStyle/GroovyLanguageCodeStyleSettingsProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeStyle/GroovyLanguageCodeStyleSettingsProvider.java @@ -221,6 +221,28 @@ public class GroovyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSe consumer.showCustomOption(GroovyCodeStyleSettings.class, "SPACE_WITHIN_TUPLE_EXPRESSION", "Tuple assignment expression", CodeStyleSettingsCustomizable.SPACES_WITHIN); return; } + if (settingsType == SettingsType.BLANK_LINES_SETTINGS) { + + consumer.showStandardOptions( + "KEEP_BLANK_LINES_IN_DECLARATIONS", + "KEEP_BLANK_LINES_IN_CODE", + "KEEP_BLANK_LINES_BEFORE_RBRACE", + + "BLANK_LINES_BEFORE_PACKAGE", + "BLANK_LINES_AFTER_PACKAGE", + "BLANK_LINES_BEFORE_IMPORTS", + "BLANK_LINES_AFTER_IMPORTS", + "BLANK_LINES_AROUND_CLASS", + "BLANK_LINES_AFTER_CLASS_HEADER", + //"BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER", + "BLANK_LINES_AROUND_FIELD_IN_INTERFACE", + "BLANK_LINES_AROUND_FIELD", + "BLANK_LINES_AROUND_METHOD_IN_INTERFACE", + "BLANK_LINES_AROUND_METHOD", + "BLANK_LINES_BEFORE_METHOD_BODY" + ); + return; + } consumer.showAllStandardOptions(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java index 99f554568c9e..8fb369f09b25 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java @@ -61,13 +61,13 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAn import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrArrayTypeElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList; import static org.jetbrains.plugins.groovy.GroovyFileType.GROOVY_LANGUAGE; import static org.jetbrains.plugins.groovy.formatter.models.spacing.SpacingTokens.*; +import static org.jetbrains.plugins.groovy.formatter.models.spacing.SpacingTokens.GROOVY_DOC_COMMENT; import static org.jetbrains.plugins.groovy.formatter.models.spacing.SpacingTokens.mCOMMA; import static org.jetbrains.plugins.groovy.formatter.models.spacing.SpacingTokens.mELVIS; import static org.jetbrains.plugins.groovy.formatter.models.spacing.SpacingTokens.mQUESTION; @@ -331,13 +331,51 @@ public class GroovySpacingProcessor extends GroovyElementVisitor { @Override public void visitFile(GroovyFileBase file) { - if (myType1 == PACKAGE_DEFINITION && myType2 != mSEMI || - myType1 == mSEMI && getStatementBySemicolon(myChild1.getPsi()) instanceof GrPackageDefinition) { - myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_PACKAGE + 1, mySettings.KEEP_LINE_BREAKS, 100); + if (isAfterElementOrSemi(PACKAGE_DEFINITION)) { + myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_PACKAGE + 1, mySettings.KEEP_LINE_BREAKS, Integer.MAX_VALUE / 2); } else if (myType2 == PACKAGE_DEFINITION) { - myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_BEFORE_PACKAGE + 1, mySettings.KEEP_LINE_BREAKS, 100); + myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_BEFORE_PACKAGE + 1, mySettings.KEEP_LINE_BREAKS, Integer.MAX_VALUE / 2); } + else if (TYPE_DEFINITION_TYPES.contains(myType1) || TYPE_DEFINITION_TYPES.contains(myType2)) { + if (myType1 == GROOVY_DOC_COMMENT) { + createLF(true); + } + else { + myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AROUND_CLASS + 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS); + } + } + else if (isAfterElementOrSemi(IMPORT_STATEMENT) && myType2 != IMPORT_STATEMENT) { //after imports + myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_IMPORTS + 1, mySettings.KEEP_LINE_BREAKS, Integer.MAX_VALUE / 2); + } + else if (myType1 != IMPORT_STATEMENT && !isSemiAfter(IMPORT_STATEMENT) && myType2 == IMPORT_STATEMENT) { //before imports + myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_BEFORE_IMPORTS, mySettings.KEEP_LINE_BREAKS, Integer.MAX_VALUE / 2); + } + else if (isAfterElementOrSemi(IMPORT_STATEMENT) && myType2 == IMPORT_STATEMENT) { + myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, Integer.MAX_VALUE / 2); + } + else { + processClassMembers(null); + } + } + + private boolean isAfterElementOrSemi(final IElementType elementType) { + return myType1 == elementType && myType2 != mSEMI || isSemiAfter(PACKAGE_DEFINITION); + } + + private boolean isSemiAfter(@NotNull IElementType statement) { + return myType1 == mSEMI && getStatementTypeBySemi(myChild1) == statement; + } + + private boolean isSemiAfter(@NotNull TokenSet set) { + return myType1 == mSEMI && set.contains(getStatementTypeBySemi(myChild1)); + } + + @Nullable + private static IElementType getStatementTypeBySemi(@NotNull ASTNode semi) { + final GrTopStatement statement = getStatementBySemicolon(semi.getPsi()); + if (statement == null) return null; + return statement.getNode().getElementType(); } @Nullable @@ -390,15 +428,22 @@ public class GroovySpacingProcessor extends GroovyElementVisitor { } public void visitOpenBlock(GrOpenBlock block) { - - final PsiElement parent = block.getParent(); - boolean keepInOneLine = parent instanceof GrMethod ? mySettings.KEEP_SIMPLE_METHODS_IN_ONE_LINE : - mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE; + boolean isMethod = block.getParent() instanceof GrMethod; + boolean keepInOneLine = isMethod ? mySettings.KEEP_SIMPLE_METHODS_IN_ONE_LINE : mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE; if (myType1 == mLCURLY && myType2 == mRCURLY) { createLF(!keepInOneLine); } - else if (myType1 == mLCURLY || myType2 == mRCURLY) { + else if (myType1 == mLCURLY) { + if (keepInOneLine) { + createDependentLFSpacing(true, mySettings.SPACE_WITHIN_BRACES, block.getTextRange()); + } + else { + int lineFeedsCount = isMethod ? mySettings.BLANK_LINES_BEFORE_METHOD_BODY + 1 : 1; + myResult = Spacing.createSpacing(0, 0, lineFeedsCount, mySettings.KEEP_LINE_BREAKS, keepBlankLines()); + } + } + else if (myType2 == mRCURLY) { if (keepInOneLine) { createDependentLFSpacing(true, mySettings.SPACE_WITHIN_BRACES, block.getTextRange()); } @@ -436,11 +481,49 @@ public class GroovySpacingProcessor extends GroovyElementVisitor { else { createLF(true); } - } else if (myType1 == mLCURLY) { - myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_CLASS_HEADER + 1, - mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS); - } else if (myType2 == mRCURLY) { - myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE); + } + else if (myType1 == mLCURLY) { + myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_CLASS_HEADER + 1, mySettings.KEEP_LINE_BREAKS, + mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS); + } + else if (myType2 == mRCURLY) { + createLF(true); + } + else { + processClassMembers(typeDefinitionBody); + } + } + + private void processClassMembers(@Nullable GrTypeDefinitionBody typeDefinitionBody) { + final boolean isInterface = typeDefinitionBody != null && ((GrTypeDefinition)typeDefinitionBody.getParent()).isInterface(); + + if (myType2 == mSEMI) return; + + if (typeDefinitionBody != null) { //check variable definitions only inside class body + if ((myType1 == VARIABLE_DEFINITION || isSemiAfter(VARIABLE_DEFINITION)) && METHOD_DEFS.contains(myType2)) { + final int minBlankLines = Math.max( + isInterface ? mySettings.BLANK_LINES_AROUND_METHOD_IN_INTERFACE : mySettings.BLANK_LINES_AROUND_METHOD, + isInterface ? mySettings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE : mySettings.BLANK_LINES_AROUND_FIELD + ); + myResult = Spacing.createSpacing(0, 0, minBlankLines + 1, mySettings.KEEP_LINE_BREAKS, keepBlankLines()); + return; + } + else if (myType1 == VARIABLE_DEFINITION || isSemiAfter(VARIABLE_DEFINITION) || myType2 == VARIABLE_DEFINITION) { + final int minBlankLines = + isInterface ? mySettings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE : mySettings.BLANK_LINES_AROUND_FIELD; + myResult = Spacing.createSpacing(0, 0, minBlankLines + 1, mySettings.KEEP_LINE_BREAKS, keepBlankLines()); + return; + } + } + + if (METHOD_DEFS.contains(myType1) || isSemiAfter(METHOD_DEFS) || METHOD_DEFS.contains((myType2))) { + if (myType1 == GROOVY_DOC_COMMENT) { + createLF(true); + } + else { + final int minBlankLines = isInterface ? mySettings.BLANK_LINES_AROUND_METHOD_IN_INTERFACE : mySettings.BLANK_LINES_AROUND_METHOD; + myResult = Spacing.createSpacing(0, 0, minBlankLines + 1, mySettings.KEEP_LINE_BREAKS, keepBlankLines()); + } } } @@ -661,6 +744,7 @@ public class GroovySpacingProcessor extends GroovyElementVisitor { @Override public void visitBinaryExpression(GrBinaryExpression expression) { + @SuppressWarnings("SimplifiableConditionalExpression" ) boolean spaceAround = isLeftOrRight(LOGICAL_OPERATORS) ? mySettings.SPACE_AROUND_LOGICAL_OPERATORS : isLeftOrRight(EQUALITY_OPERATORS) ? mySettings.SPACE_AROUND_EQUALITY_OPERATORS : isLeftOrRight(RELATIONAL_OPERATORS) ? mySettings.SPACE_AROUND_RELATIONAL_OPERATORS : @@ -972,7 +1056,12 @@ public class GroovySpacingProcessor extends GroovyElementVisitor { } private int keepBlankLines() { - return mySettings.KEEP_BLANK_LINES_IN_CODE; + if (myType2 == mRCURLY) { + return mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE; + } + else { + return mySettings.KEEP_BLANK_LINES_IN_CODE; + } } static boolean isWhiteSpace(final ASTNode node) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessorBasic.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessorBasic.java index acc4fbcec596..c7928d3975ad 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessorBasic.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessorBasic.java @@ -46,7 +46,6 @@ import static org.jetbrains.plugins.groovy.lang.groovydoc.parser.GroovyDocElemen import static org.jetbrains.plugins.groovy.lang.groovydoc.parser.GroovyDocElementTypes.GROOVY_DOC_COMMENT; import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mTRIPLE_DOT; import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.DOTS; -import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.METHOD_DEFS; /** * @author ilyas @@ -57,8 +56,6 @@ public abstract class GroovySpacingProcessorBasic { private static final Spacing NO_SPACING = Spacing.createSpacing(0, 0, 0, false, 0); private static final Spacing COMMON_SPACING = Spacing.createSpacing(1, 1, 0, true, 100); private static final Spacing COMMON_SPACING_WITH_NL = Spacing.createSpacing(1, 1, 1, true, 100); - private static final Spacing IMPORT_BETWEEN_SPACING = Spacing.createSpacing(0, 0, 1, true, 100); - private static final Spacing IMPORT_OTHER_SPACING = Spacing.createSpacing(0, 0, 2, true, 100); private static final Spacing LAZY_SPACING = Spacing.createSpacing(0, 239, 0, true, 100); public static Spacing getSpacing(GroovyBlock child1, @@ -95,21 +92,7 @@ public abstract class GroovySpacingProcessorBasic { return COMMON_SPACING_WITH_NL; } - 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 (right != null && right instanceof GrTypeArgumentList) { + if (right instanceof GrTypeArgumentList) { return NO_SPACING_WITH_NEWLINE; } @@ -136,16 +119,6 @@ public abstract class GroovySpacingProcessorBasic { 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)) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/FormatterTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/FormatterTest.groovy index 2f620c082434..c398fba2595b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/FormatterTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/formatter/FormatterTest.groovy @@ -274,6 +274,7 @@ class B { ''', '''\ class A { } + class B { } ''') diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/OptimizeImportsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/OptimizeImportsTest.groovy index b3d5697c33f7..e38546f0fac4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/OptimizeImportsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/OptimizeImportsTest.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -253,7 +253,7 @@ package pack import foo.Foo import foo.Bar -import java.test.Test +import java.test.Test import java.test2.Test2 import static foo.Bar.foo0 import static java.test.Test.foo diff --git a/plugins/groovy/testdata/groovy/refactoring/inlineLocal/varInGString4.test b/plugins/groovy/testdata/groovy/refactoring/inlineLocal/varInGString4.test index 06b851a43ee2..a83125a354f0 100644 --- a/plugins/groovy/testdata/groovy/refactoring/inlineLocal/varInGString4.test +++ b/plugins/groovy/testdata/groovy/refactoring/inlineLocal/varInGString4.test @@ -8,4 +8,5 @@ print "foo $s.foo x" class X { def getFoo(){2} } + print "foo ${new X().foo} x" \ No newline at end of file diff --git a/plugins/groovy/testdata/optimizeImports/Commented_after.groovy b/plugins/groovy/testdata/optimizeImports/Commented_after.groovy index 29d323e66010..70fba0b96995 100644 --- a/plugins/groovy/testdata/optimizeImports/Commented_after.groovy +++ b/plugins/groovy/testdata/optimizeImports/Commented_after.groovy @@ -1,5 +1,4 @@ import javax.swing.* - // preved! def frame = new JFrame() \ No newline at end of file