Added ability to align consecutive variables declaration (IDEA-56947)

This commit is contained in:
Yaroslav Lepenkin
2015-01-16 11:53:47 +02:00
parent f59e542201
commit de17dfa24d
9 changed files with 268 additions and 10 deletions
@@ -152,7 +152,8 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett
"FINALLY_ON_NEW_LINE",
"INDENT_CASE_FROM_SWITCH",
"SPECIAL_ELSE_IF_TREATMENT",
"ENUM_CONSTANTS_WRAP");
"ENUM_CONSTANTS_WRAP",
"ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS");
consumer.showCustomOption(JavaCodeStyleSettings.class,
"ANNOTATION_PARAMETER_WRAP",
@@ -501,8 +501,10 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
else if (childType == JavaElementType.FIELD) {
child = processField(result, child, alignmentStrategy, defaultWrap, childIndent);
}
else if (childType == JavaElementType.LOCAL_VARIABLE ||
childType == JavaElementType.DECLARATION_STATEMENT && myNode.getElementType() == JavaElementType.METHOD) {
else if (childType == JavaElementType.LOCAL_VARIABLE
|| childType == JavaElementType.DECLARATION_STATEMENT
&& (nodeType == JavaElementType.METHOD || nodeType == JavaElementType.CODE_BLOCK))
{
result.add(new SimpleJavaBlock(child, defaultWrap, alignmentStrategy, childIndent, mySettings, myJavaSettings));
}
else {
@@ -1137,10 +1139,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
processChild(localResult, child, AlignmentStrategy.getNullStrategy(), null, Indent.getNoneIndent());
child = child.getTreeNext();
ChildAlignmentStrategyProvider alignmentStrategyProvider = ChildAlignmentStrategyProvider.NULL_STRATEGY_PROVIDER;
if (mySettings.ALIGN_GROUP_FIELD_DECLARATIONS) {
alignmentStrategyProvider = new SubsequentFieldAligner(mySettings);
}
ChildAlignmentStrategyProvider alignmentStrategyProvider = getStrategyProvider();
while (child != null) {
if (FormatterUtil.containsWhiteSpacesOnly(child)) {
@@ -1167,6 +1166,20 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
return null;
}
private ChildAlignmentStrategyProvider getStrategyProvider() {
if (mySettings.ALIGN_GROUP_FIELD_DECLARATIONS && myNode.getElementType() == JavaElementType.CLASS) {
return new SubsequentFieldAligner(mySettings);
}
ASTNode parent = myNode.getTreeParent();
IElementType parentType = parent != null ? parent.getElementType() : null;
if (mySettings.ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS && parentType == JavaElementType.METHOD) {
return new SubsequentVariablesAligner();
}
return ChildAlignmentStrategyProvider.NULL_STRATEGY_PROVIDER;
}
private Indent getIndentForCodeBlock(ASTNode child, int childrenIndent) {
if (child.getElementType() == JavaElementType.CODE_BLOCK
&& (getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED
@@ -87,11 +87,13 @@ public class SimpleJavaBlock extends AbstractJavaBlock {
final ASTNode astNode = myCurrentChild;
AlignmentStrategy alignmentStrategyToUse = AlignmentStrategy.wrap(chooseAlignment(myReservedAlignment, myReservedAlignment2, myCurrentChild));
if (myNode.getElementType() == JavaElementType.FIELD) {
if (myNode.getElementType() == JavaElementType.FIELD
|| myNode.getElementType() == JavaElementType.DECLARATION_STATEMENT
|| myNode.getElementType() == JavaElementType.LOCAL_VARIABLE)
{
alignmentStrategyToUse = myAlignmentStrategy;
}
myCurrentChild = processChild(result, astNode, alignmentStrategyToUse, childWrap, myCurrentIndent, myCurrentOffset);
if (astNode != myCurrentChild && myCurrentChild != null) {
myCurrentOffset = myCurrentChild.getTextRange().getStartOffset();
@@ -0,0 +1,66 @@
/*
* Copyright 2000-2015 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.formatter.java;
import com.intellij.formatting.alignment.AlignmentStrategy;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
public class SubsequentVariablesAligner implements ChildAlignmentStrategyProvider {
private final static Set<IElementType> TYPES_TO_ALIGN = ContainerUtil.newHashSet(
JavaTokenType.IDENTIFIER,
JavaTokenType.EQ
);
private AlignmentStrategy myAlignmentStrategy;
public SubsequentVariablesAligner() {
updateAlignmentStrategy();
}
private void updateAlignmentStrategy() {
myAlignmentStrategy = AlignmentStrategy.createAlignmentPerTypeStrategy(TYPES_TO_ALIGN, JavaElementType.LOCAL_VARIABLE, true);
}
@Override
public AlignmentStrategy getNextChildStrategy(@NotNull ASTNode child) {
IElementType childType = child.getElementType();
if (childType != JavaElementType.DECLARATION_STATEMENT || StringUtil.countNewLines(child.getChars()) > 0) {
updateAlignmentStrategy();
return AlignmentStrategy.getNullStrategy();
}
if (isWhiteSpaceWithBlankLines(child.getTreePrev())) {
updateAlignmentStrategy();
return myAlignmentStrategy;
}
return myAlignmentStrategy;
}
private static boolean isWhiteSpaceWithBlankLines(@Nullable ASTNode node) {
return node != null && node.getElementType() == TokenType.WHITE_SPACE && StringUtil.countNewLines(node.getChars()) > 1;
}
}
@@ -421,4 +421,176 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest {
);
}
public void testLocalVariablesAlignment() {
getSettings().ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS = true;
doMethodTest(
"int a = 2;\n" +
"String myString = \"my string\"",
"int a = 2;\n" +
"String myString = \"my string\""
);
}
public void testAlignOnlyDeclarationStatements() {
getSettings().ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS = true;
doMethodTest(
" String s;\n" +
" int a = 2;\n" +
"s = \"abs\";\n" +
"long stamp = 12;",
"String s;\n" +
"int a = 2;\n" +
"s = \"abs\";\n" +
"long stamp = 12;"
);
}
public void testDoNotAlignWhenBlankLine() {
getSettings().ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS = true;
doMethodTest(
"int a = 2;\n" +
"\n" +
"String myString = \"my string\"",
"int a = 2;\n" +
"\n" +
"String myString = \"my string\""
);
}
public void testDoNotAlignWhenGroupInterrupted() {
getSettings().ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS = true;
doMethodTest(
"int a = 2;\n" +
"System.out.println(\"hi!\")\n" +
"String myString = \"my string\"",
"int a = 2;\n" +
"System.out.println(\"hi!\")\n" +
"String myString = \"my string\""
);
}
public void testDoNotAlignMultiDeclarations() {
getSettings().ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS = true;
doMethodTest(
" int a, b = 2;\n" +
"String myString = \"my string\"",
"int a, b = 2;\n" +
"String myString = \"my string\""
);
}
public void testDoNotAlignMultilineParams() {
getSettings().ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS = true;
doMethodTest(
"int a = 12;\n" +
" Runnable runnable = new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"AAA!\");\n" +
" }\n" +
"};",
"int a = 12;\n" +
"Runnable runnable = new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"AAA!\");\n" +
" }\n" +
"};"
);
doMethodTest(
" Runnable runnable = new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"AAA!\");\n" +
" }\n" +
"};\n" +
"int c = 12;",
"Runnable runnable = new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"AAA!\");\n" +
" }\n" +
"};\n" +
"int c = 12;"
);
doMethodTest(
" int ac = 99;\n" +
"Runnable runnable = new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"AAA!\");\n" +
" }\n" +
"};\n" +
"int c = 12;",
"int ac = 99;\n" +
"Runnable runnable = new Runnable() {\n" +
" @Override\n" +
" public void run() {\n" +
" System.out.println(\"AAA!\");\n" +
" }\n" +
"};\n" +
"int c = 12;"
);
}
public void testDoNotAlign_IfFirstMultiline() {
getSettings().ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS = true;
doMethodTest(
"int\n" +
" i = 0;\n" +
"int[] a = new int[]{1, 2, 0x0052, 0x0053, 0x0054};\n" +
"int var1 = 1;\n" +
"int var2 = 2;",
"int\n" +
" i = 0;\n" +
"int[] a = new int[]{1, 2, 0x0052, 0x0053, 0x0054};\n" +
"int var1 = 1;\n" +
"int var2 = 2;"
);
}
public void testAlign_InMethod() {
getSettings().ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS = true;
doClassTest(
"public void run() {\n" +
"\n" +
" int a = 2;\n" +
" String superString = \"\";\n" +
"\n" +
" test(call1(), call2(), call3());\n" +
" }",
"public void run() {\n" +
"\n" +
" int a = 2;\n" +
" String superString = \"\";\n" +
"\n" +
" test(call1(), call2(), call3());\n" +
"}"
);
doClassTest(
"public void run() {\n" +
"\n" +
" test(call1(), call2(), call3());\n" +
"\n" +
" int a = 2;\n" +
" String superString = \"\";\n" +
"}",
"public void run() {\n" +
"\n" +
" test(call1(), call2(), call3());\n" +
"\n" +
" int a = 2;\n" +
" String superString = \"\";\n" +
"}");
}
}
@@ -193,7 +193,8 @@ public interface CodeStyleSettingsCustomizable {
FINALLY_ON_NEW_LINE,
INDENT_CASE_FROM_SWITCH,
SPECIAL_ELSE_IF_TREATMENT,
ENUM_CONSTANTS_WRAP
ENUM_CONSTANTS_WRAP,
ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS
}
@@ -452,6 +452,7 @@ public class CommonCodeStyleSettings {
* int end = 10;
*/
public boolean ALIGN_GROUP_FIELD_DECLARATIONS = false;
public boolean ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS = false;
//----------------- SPACES --------------------
@@ -111,6 +111,7 @@ public class WrappingAndBracesPanel extends OptionTableWithPreviewPanel {
addOption("ASSIGNMENT_WRAP", WRAPPING_ASSIGNMENT, WRAP_OPTIONS, WRAP_VALUES);
addOption("ALIGN_MULTILINE_ASSIGNMENT", ApplicationBundle.message("wrapping.align.when.multiline"), WRAPPING_ASSIGNMENT);
addOption("PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE", ApplicationBundle.message("wrapping.assignment.sign.on.next.line"), WRAPPING_ASSIGNMENT);
addOption("ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS", ApplicationBundle.message("wrapping.assignment.align.consecutive.variable.declarations"), WRAPPING_ASSIGNMENT);
addOption("TERNARY_OPERATION_WRAP", WRAPPING_TERNARY_OPERATION, WRAP_OPTIONS, WRAP_VALUES);
addOption("ALIGN_MULTILINE_TERNARY_OPERATION", ApplicationBundle.message("wrapping.align.when.multiline"), WRAPPING_TERNARY_OPERATION);
@@ -204,6 +204,7 @@ wrapping.take.priority.over.call.chain.wrapping=Take priority over call chain wr
wrapping.operation.sign.on.next.line=Operation sign on next line
wrapping.comma.on.next.line=',' on next line
wrapping.assignment.sign.on.next.line=Assignment sign on next line
wrapping.assignment.align.consecutive.variable.declarations=Align consecutive variable declarations
wrapping.quest.and.colon.signs.on.next.line='?' and ':' signs on next line
wrapping.new.line.after.lbrace=New line after '{'
wrapping.rbrace.on.new.line=Place '}' on new line