diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java index 73d586970d6..2a8d99ec95d 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java @@ -17,29 +17,31 @@ package org.jetbrains.jet.plugin.formatter; import com.intellij.formatting.*; +import com.intellij.formatting.alignment.AlignmentStrategy; import com.intellij.lang.ASTNode; import com.intellij.psi.TokenType; import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.formatter.common.AbstractBlock; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.jet.plugin.JetLanguage; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; /** - * @see Block for good JavaDoc documentation * @author yole + * @see Block for good JavaDoc documentation */ public class JetBlock extends AbstractBlock { private Indent myIndent; private CodeStyleSettings mySettings; private final SpacingBuilder mySpacingBuilder; - + private List mySubBlocks; private static final TokenSet CODE_BLOCKS = TokenSet.create( @@ -50,7 +52,7 @@ public class JetBlock extends AbstractBlock { private static final TokenSet STATEMENT_PARTS = TokenSet.create( JetNodeTypes.THEN, JetNodeTypes.ELSE); - + // private static final List public JetBlock(@NotNull ASTNode node, @@ -78,9 +80,12 @@ public class JetBlock extends AbstractBlock { } return new ArrayList(mySubBlocks); } - + private List buildSubBlocks() { List blocks = new ArrayList(); + + Map childrenAlignments = createChildrenAlignments(); + for (ASTNode child = myNode.getFirstChildNode(); child != null; child = child.getTreeNext()) { IElementType childType = child.getElementType(); @@ -90,77 +95,31 @@ public class JetBlock extends AbstractBlock { continue; } - blocks.add(buildSubBlock(child)); + Alignment childAlignment = childrenAlignments.containsKey(child) ? childrenAlignments.get(child) : null; + blocks.add(buildSubBlock(child, childAlignment)); } return Collections.unmodifiableList(blocks); } @NotNull - private Block buildSubBlock(@NotNull ASTNode child) { + private Block buildSubBlock(@NotNull ASTNode child, Alignment childAlignment) { Wrap wrap = null; - Indent childIndent = Indent.getNoneIndent(); - Alignment childAlignment = null; + // Affects to spaces around operators... if (child.getElementType() == JetNodeTypes.OPERATION_REFERENCE) { ASTNode operationNode = child.getFirstChildNode(); if (operationNode != null) { - return new JetBlock(operationNode, childAlignment, childIndent, wrap, mySettings, mySpacingBuilder); + return new JetBlock(operationNode, childAlignment, Indent.getNoneIndent(), wrap, mySettings, mySpacingBuilder); } } - ASTNode childParent = child.getTreeParent(); - - if (CODE_BLOCKS.contains(myNode.getElementType())) { - childIndent = indentIfNotBrace(child); - } - else if (childParent != null && - childParent.getElementType() == JetNodeTypes.BODY && - child.getElementType() != JetNodeTypes.BLOCK) { - - // For a single statement if 'for' - childIndent = Indent.getNormalIndent(); - } - else if (child.getElementType() == JetNodeTypes.WHEN_ENTRY) { - // For the entry in when - // TODO: Add an option for configuration? - childIndent = Indent.getNormalIndent(); - } - else if (childParent != null && childParent.getElementType() == JetNodeTypes.WHEN_ENTRY) { - ASTNode prev = getPrevWithoutWhitespace(child); - if (prev != null && prev.getText().equals("->")) { - childIndent = indentIfNotBrace(child); - } - } - else if (STATEMENT_PARTS.contains(myNode.getElementType()) && child.getElementType() != JetNodeTypes.BLOCK) { - childIndent = Indent.getNormalIndent(); - } - else if (childParent != null && childParent.getElementType() == JetNodeTypes.DOT_QUALIFIED_EXPRESSION) { - if (childParent.getFirstChildNode() != child && childParent.getLastChildNode() != child) { - childIndent = Indent.getContinuationWithoutFirstIndent(false); - } - } - else if (childParent != null && childParent.getElementType() == JetNodeTypes.VALUE_PARAMETER_LIST) { - String childText = child.getText(); - - if (!(childText.equals("(") || childText.equals(")"))) { - childIndent = Indent.getContinuationWithoutFirstIndent(false); - } - } - else if (childParent != null && childParent.getElementType() == JetNodeTypes.TYPE_PARAMETER_LIST) { - String childText = child.getText(); - - if (!(childText.equals("<") || childText.equals(">"))) { - childIndent = Indent.getContinuationWithoutFirstIndent(false); - } - } - - return new JetBlock(child, childAlignment, childIndent, wrap, mySettings, mySpacingBuilder); + return new JetBlock(child, childAlignment, createChildIndent(child), wrap, mySettings, mySpacingBuilder); } private static Indent indentIfNotBrace(@NotNull ASTNode child) { return child.getElementType() == JetTokens.RBRACE || child.getElementType() == JetTokens.LBRACE - ? Indent.getNoneIndent() - : Indent.getNormalIndent(); + ? Indent.getNoneIndent() + : Indent.getNormalIndent(); } private static ASTNode getPrevWithoutWhitespace(ASTNode node) { @@ -176,17 +135,17 @@ public class JetBlock extends AbstractBlock { public Spacing getSpacing(Block child1, Block child2) { return mySpacingBuilder.getSpacing(this, child1, child2); } - + @NotNull @Override public ChildAttributes getChildAttributes(int newChildIndex) { final IElementType type = getNode().getElementType(); if (CODE_BLOCKS.contains(type) || - type == JetNodeTypes.WHEN || - type == JetNodeTypes.IF || - type == JetNodeTypes.FOR || - type == JetNodeTypes.WHILE || - type == JetNodeTypes.DO_WHILE) { + type == JetNodeTypes.WHEN || + type == JetNodeTypes.IF || + type == JetNodeTypes.FOR || + type == JetNodeTypes.WHILE || + type == JetNodeTypes.DO_WHILE) { return new ChildAttributes(Indent.getNormalIndent(), null); } @@ -201,4 +160,113 @@ public class JetBlock extends AbstractBlock { public boolean isLeaf() { return myNode.getFirstChildNode() == null; } + + @NotNull + protected Map createChildrenAlignments() { + CommonCodeStyleSettings jetCommonSettings = mySettings.getCommonSettings(JetLanguage.INSTANCE); + + // Prepare strategies for setting up alignments - no alignment should be set by default + AlignmentStrategy[] strategies = new AlignmentStrategy[] { AlignmentStrategy.getNullStrategy() }; + + // Redefine list of strategies for some special elements + IElementType parentType = myNode.getElementType(); + if (parentType == JetNodeTypes.VALUE_PARAMETER_LIST) { + strategies = getAlignmentForChildInParenthesis( + jetCommonSettings.ALIGN_MULTILINE_PARAMETERS, JetNodeTypes.VALUE_PARAMETER, JetTokens.COMMA, + jetCommonSettings.ALIGN_MULTILINE_METHOD_BRACKETS, JetTokens.LPAR, JetTokens.RPAR); + } + else if (parentType == JetNodeTypes.VALUE_ARGUMENT_LIST) { + strategies = getAlignmentForChildInParenthesis( + jetCommonSettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS, JetNodeTypes.VALUE_ARGUMENT, JetTokens.COMMA, + jetCommonSettings.ALIGN_MULTILINE_METHOD_BRACKETS, JetTokens.LPAR, JetTokens.RPAR); + } + + // Construct information about children alignment + HashMap result = new HashMap(); + + for (ASTNode child = myNode.getFirstChildNode(); child != null; child = child.getTreeNext()) { + IElementType childType = child.getElementType(); + + if (child.getTextRange().getLength() == 0) continue; + + if (childType == TokenType.WHITE_SPACE) { + continue; + } + + for (AlignmentStrategy strategy : strategies) { + Alignment childAlignment = strategy.getAlignment(parentType, child.getElementType()); + if (childAlignment != null) { + result.put(child, childAlignment); + break; + } + } + } + + return result; + } + + private static AlignmentStrategy[] getAlignmentForChildInParenthesis( + boolean shouldAlignChild, IElementType parameter, IElementType delimiter, + boolean shouldAlignParenthesis, IElementType openParenth, IElementType closeParenth + ) { + return new AlignmentStrategy[] { + AlignmentStrategy.wrap(shouldAlignChild ? Alignment.createAlignment() : null, false, parameter), + AlignmentStrategy.wrap(shouldAlignChild ? Alignment.createAlignment() : null, false, delimiter), + AlignmentStrategy.wrap(shouldAlignParenthesis ? Alignment.createAlignment() : null, false, openParenth, closeParenth) + }; + } + + @Nullable + protected Indent createChildIndent(@NotNull ASTNode child) { + ASTNode childParent = child.getTreeParent(); + + if (CODE_BLOCKS.contains(myNode.getElementType())) { + return indentIfNotBrace(child); + } + + if (childParent != null && + childParent.getElementType() == JetNodeTypes.BODY && + child.getElementType() != JetNodeTypes.BLOCK) { + + // For a single statement if 'for' + return Indent.getNormalIndent(); + } + + if (child.getElementType() == JetNodeTypes.WHEN_ENTRY) { + // For the entry in when + // TODO: Add an option for configuration? + return Indent.getNormalIndent(); + } + + if (childParent != null && childParent.getElementType() == JetNodeTypes.WHEN_ENTRY) { + ASTNode prev = getPrevWithoutWhitespace(child); + if (prev != null && prev.getText().equals("->")) { + return indentIfNotBrace(child); + } + } + + if (STATEMENT_PARTS.contains(myNode.getElementType()) && child.getElementType() != JetNodeTypes.BLOCK) { + return Indent.getNormalIndent(); + } + + if (childParent != null && childParent.getElementType() == JetNodeTypes.DOT_QUALIFIED_EXPRESSION) { + if (childParent.getFirstChildNode() != child && childParent.getLastChildNode() != child) { + return Indent.getContinuationWithoutFirstIndent(false); + } + } + + if (childParent != null && + (childParent.getElementType() == JetNodeTypes.VALUE_PARAMETER_LIST || + childParent.getElementType() == JetNodeTypes.TYPE_PARAMETER_LIST || + childParent.getElementType() == JetNodeTypes.VALUE_ARGUMENT_LIST || + childParent.getElementType() == JetNodeTypes.TYPE_ARGUMENT_LIST)) { + if (child.getElementType() == JetTokens.RPAR) { + return Indent.getNoneIndent(); + } + + return Indent.getContinuationWithoutFirstIndent(false); + } + + return Indent.getNoneIndent(); + } } diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetCodeStyleSettingsProvider.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetCodeStyleSettingsProvider.java index b445630039f..1b3a9404431 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetCodeStyleSettingsProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetCodeStyleSettingsProvider.java @@ -44,8 +44,6 @@ public class JetCodeStyleSettingsProvider extends CodeStyleSettingsProvider { return new JetCodeStyleSettings(settings); } - - @NotNull @Override public Configurable createSettingsPage(CodeStyleSettings settings, CodeStyleSettings originalSettings) { @@ -58,6 +56,7 @@ public class JetCodeStyleSettingsProvider extends CodeStyleSettingsProvider { // TODO: activate all parent tabs addIndentOptionsTab(settings); addSpacesTab(settings); + addWrappingAndBracesTab(settings); } }; } diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetLanguageCodeStyleSettingsProvider.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetLanguageCodeStyleSettingsProvider.java index f7573a43e71..641a1e44881 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetLanguageCodeStyleSettingsProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetLanguageCodeStyleSettingsProvider.java @@ -37,13 +37,32 @@ public class JetLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSetti @Override public String getCodeSample(@NotNull SettingsType settingsType) { - return - "class Some {\n" + - " fun foo() : Int {\n" + - " val test : Int = 12\n" + - " return test\n" + - " }\n" + - "}"; + switch (settingsType) { + case WRAPPING_AND_BRACES_SETTINGS: + return + "public class ThisIsASampleClass {\n" + + " private fun foo1(i1: Int,\n" + + " i2: Int,\n" + + " i3: Int) : Int {\n" + + " return 0\n" + + " }\n" + + " private fun foo2():Int {\n" + + " return foo1(\n" + + " 12,\n" + + " 13,\n" + + " 14\n" + + " )\n" + + " }\n" + + "}"; + default: + return + "class Some {\n" + + " fun foo() : Int {\n" + + " val test : Int = 12\n" + + " return test\n" + + " }\n" + + "}"; + } } @Override @@ -53,86 +72,40 @@ public class JetLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSetti @Override public void customizeSettings(@NotNull CodeStyleSettingsCustomizable consumer, @NotNull SettingsType settingsType) { - if (settingsType == SettingsType.SPACING_SETTINGS) { - consumer.showStandardOptions( - "SPACE_AROUND_ASSIGNMENT_OPERATORS", - "SPACE_AROUND_LOGICAL_OPERATORS", - "SPACE_AROUND_EQUALITY_OPERATORS", - "SPACE_AROUND_RELATIONAL_OPERATORS", - // "SPACE_AROUND_BITWISE_OPERATORS", - "SPACE_AROUND_ADDITIVE_OPERATORS", - "SPACE_AROUND_MULTIPLICATIVE_OPERATORS", - // "SPACE_AROUND_SHIFT_OPERATORS", - "SPACE_AROUND_UNARY_OPERATOR", - "SPACE_AFTER_COMMA", - // "SPACE_AFTER_COMMA_IN_TYPE_ARGUMENTS", - "SPACE_BEFORE_COMMA" - // "SPACE_AFTER_SEMICOLON", - // "SPACE_BEFORE_SEMICOLON", - // "SPACE_WITHIN_PARENTHESES", - // "SPACE_WITHIN_METHOD_CALL_PARENTHESES", - // "SPACE_WITHIN_EMPTY_METHOD_CALL_PARENTHESES", - // "SPACE_WITHIN_METHOD_PARENTHESES", - // "SPACE_WITHIN_EMPTY_METHOD_PARENTHESES", - // "SPACE_WITHIN_IF_PARENTHESES", - // "SPACE_WITHIN_WHILE_PARENTHESES", - // "SPACE_WITHIN_FOR_PARENTHESES", - // "SPACE_WITHIN_TRY_PARENTHESES", - // "SPACE_WITHIN_CATCH_PARENTHESES", - // "SPACE_WITHIN_SWITCH_PARENTHESES", - // "SPACE_WITHIN_SYNCHRONIZED_PARENTHESES", - // "SPACE_WITHIN_CAST_PARENTHESES", - // "SPACE_WITHIN_BRACKETS", - // "SPACE_WITHIN_BRACES", - // "SPACE_WITHIN_ARRAY_INITIALIZER_BRACES", - // "SPACE_AFTER_TYPE_CAST", - // "SPACE_BEFORE_METHOD_CALL_PARENTHESES", - // "SPACE_BEFORE_METHOD_PARENTHESES", - // "SPACE_BEFORE_IF_PARENTHESES", - // "SPACE_BEFORE_WHILE_PARENTHESES", - // "SPACE_BEFORE_FOR_PARENTHESES", - // "SPACE_BEFORE_TRY_PARENTHESES", - // "SPACE_BEFORE_CATCH_PARENTHESES", - // "SPACE_BEFORE_SWITCH_PARENTHESES", - // "SPACE_BEFORE_SYNCHRONIZED_PARENTHESES", - // "SPACE_BEFORE_CLASS_LBRACE", - // "SPACE_BEFORE_METHOD_LBRACE", - // "SPACE_BEFORE_IF_LBRACE", - // "SPACE_BEFORE_ELSE_LBRACE", - // "SPACE_BEFORE_WHILE_LBRACE", - // "SPACE_BEFORE_FOR_LBRACE", - // "SPACE_BEFORE_DO_LBRACE", - // "SPACE_BEFORE_SWITCH_LBRACE", - // "SPACE_BEFORE_TRY_LBRACE", - // "SPACE_BEFORE_CATCH_LBRACE", - // "SPACE_BEFORE_FINALLY_LBRACE", - // "SPACE_BEFORE_SYNCHRONIZED_LBRACE", - // "SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE", - // "SPACE_BEFORE_ANNOTATION_ARRAY_INITIALIZER_LBRACE", - // "SPACE_BEFORE_ELSE_KEYWORD", - // "SPACE_BEFORE_WHILE_KEYWORD", - // "SPACE_BEFORE_CATCH_KEYWORD", - // "SPACE_BEFORE_FINALLY_KEYWORD", - // "SPACE_BEFORE_QUEST", - // "SPACE_AFTER_QUEST", - // "SPACE_BEFORE_COLON", - // "SPACE_AFTER_COLON", - // "SPACE_BEFORE_TYPE_PARAMETER_LIST" - ); + switch (settingsType) { + case SPACING_SETTINGS: + consumer.showStandardOptions( + "SPACE_AROUND_ASSIGNMENT_OPERATORS", + "SPACE_AROUND_LOGICAL_OPERATORS", + "SPACE_AROUND_EQUALITY_OPERATORS", + "SPACE_AROUND_RELATIONAL_OPERATORS", + "SPACE_AROUND_ADDITIVE_OPERATORS", + "SPACE_AROUND_MULTIPLICATIVE_OPERATORS", + "SPACE_AROUND_UNARY_OPERATOR", + "SPACE_AFTER_COMMA", + "SPACE_BEFORE_COMMA" + ); - consumer.showCustomOption(JetCodeStyleSettings.class, "SPACE_AROUND_RANGE", "Around range (..)", - CodeStyleSettingsCustomizable.SPACES_AROUND_OPERATORS); + consumer.showCustomOption(JetCodeStyleSettings.class, "SPACE_AROUND_RANGE", "Around range (..)", + CodeStyleSettingsCustomizable.SPACES_AROUND_OPERATORS); - consumer.showCustomOption(JetCodeStyleSettings.class, "SPACE_AFTER_TYPE_COLON", "Space after colon, before declarations' type", - CodeStyleSettingsCustomizable.SPACES_OTHER); + consumer.showCustomOption(JetCodeStyleSettings.class, "SPACE_AFTER_TYPE_COLON", "Space after colon, before declarations' type", + CodeStyleSettingsCustomizable.SPACES_OTHER); - consumer.showCustomOption(JetCodeStyleSettings.class, "SPACE_BEFORE_TYPE_COLON", "Space before colon, after declarations' name", - CodeStyleSettingsCustomizable.SPACES_OTHER); - } else { - consumer.showAllStandardOptions(); + consumer.showCustomOption(JetCodeStyleSettings.class, "SPACE_BEFORE_TYPE_COLON", "Space before colon, after declarations' name", + CodeStyleSettingsCustomizable.SPACES_OTHER); + break; + case WRAPPING_AND_BRACES_SETTINGS: + consumer.showStandardOptions( + // "ALIGN_MULTILINE_CHAINED_METHODS", + "ALIGN_MULTILINE_PARAMETERS", + "ALIGN_MULTILINE_PARAMETERS_IN_CALLS", + "ALIGN_MULTILINE_METHOD_BRACKETS" + ); + break; + default: + consumer.showStandardOptions(); } - - } @Override diff --git a/idea/testData/formatter/FunctionCallParametersAlign.kt b/idea/testData/formatter/FunctionCallParametersAlign.kt new file mode 100644 index 00000000000..c82ccbb4492 --- /dev/null +++ b/idea/testData/formatter/FunctionCallParametersAlign.kt @@ -0,0 +1,6 @@ +fun test() { + someTestLong(12, + 13) +} + +// SET_TRUE: ALIGN_MULTILINE_PARAMETERS_IN_CALLS \ No newline at end of file diff --git a/idea/testData/formatter/FunctionCallParametersAlign_after.kt b/idea/testData/formatter/FunctionCallParametersAlign_after.kt new file mode 100644 index 00000000000..9d49208c08c --- /dev/null +++ b/idea/testData/formatter/FunctionCallParametersAlign_after.kt @@ -0,0 +1,6 @@ +fun test() { + someTestLong(12, + 13) +} + +// SET_TRUE: ALIGN_MULTILINE_PARAMETERS_IN_CALLS \ No newline at end of file diff --git a/idea/testData/formatter/FunctionDefParametersAlign.kt b/idea/testData/formatter/FunctionDefParametersAlign.kt new file mode 100644 index 00000000000..566e4de2d70 --- /dev/null +++ b/idea/testData/formatter/FunctionDefParametersAlign.kt @@ -0,0 +1,3 @@ +fun test(a : Int, + b : Int) { +} \ No newline at end of file diff --git a/idea/testData/formatter/FunctionDefParametersAlign_after.kt b/idea/testData/formatter/FunctionDefParametersAlign_after.kt new file mode 100644 index 00000000000..566e4de2d70 --- /dev/null +++ b/idea/testData/formatter/FunctionDefParametersAlign_after.kt @@ -0,0 +1,3 @@ +fun test(a : Int, + b : Int) { +} \ No newline at end of file diff --git a/idea/testData/formatter/RightBracketOnNewLine.kt b/idea/testData/formatter/RightBracketOnNewLine.kt new file mode 100644 index 00000000000..6fb95fc392b --- /dev/null +++ b/idea/testData/formatter/RightBracketOnNewLine.kt @@ -0,0 +1,7 @@ +class Test { +fun someLong(a : Int +) { +} +} + +// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS \ No newline at end of file diff --git a/idea/testData/formatter/RightBracketOnNewLine_after.kt b/idea/testData/formatter/RightBracketOnNewLine_after.kt new file mode 100644 index 00000000000..ea676549741 --- /dev/null +++ b/idea/testData/formatter/RightBracketOnNewLine_after.kt @@ -0,0 +1,7 @@ +class Test { + fun someLong(a : Int + ) { + } +} + +// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS \ No newline at end of file diff --git a/idea/testData/formatter/RightBracketOnNewLine_after_inv.kt b/idea/testData/formatter/RightBracketOnNewLine_after_inv.kt new file mode 100644 index 00000000000..c913e0f58b7 --- /dev/null +++ b/idea/testData/formatter/RightBracketOnNewLine_after_inv.kt @@ -0,0 +1,7 @@ +class Test { + fun someLong(a : Int + ) { + } +} + +// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/ExpectedCompletionUtils.java b/idea/tests/org/jetbrains/jet/completion/ExpectedCompletionUtils.java index a57bed3eef5..d802950ed81 100644 --- a/idea/tests/org/jetbrains/jet/completion/ExpectedCompletionUtils.java +++ b/idea/tests/org/jetbrains/jet/completion/ExpectedCompletionUtils.java @@ -25,10 +25,8 @@ import com.intellij.util.ArrayUtil; import junit.framework.Assert; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.testing.InTextDirectivesUtils; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; import java.util.ArrayList; import java.util.List; @@ -46,8 +44,6 @@ public class ExpectedCompletionUtils { private final String lookupString; private final String tailString; - - public CompletionProposal(@NotNull String lookupString, @Nullable String tailString) { this.lookupString = lookupString; this.tailString = tailString != null ? tailString.trim() : null; @@ -106,7 +102,7 @@ public class ExpectedCompletionUtils { public static CompletionProposal[] processProposalAssertions(String prefix, String fileText) { List proposals = new ArrayList(); - for (String proposalStr : findListWithPrefix(prefix, fileText)) { + for (String proposalStr : InTextDirectivesUtils.findListWithPrefix(prefix, fileText)) { int tailChar = proposalStr.indexOf(CompletionProposal.TAIL_FLAG); if (tailChar > 0) { @@ -123,74 +119,12 @@ public class ExpectedCompletionUtils { @Nullable public Integer getExpectedNumber(String fileText) { - return getPrefixedInt(fileText, numberLinePrefix); + return InTextDirectivesUtils.getPrefixedInt(fileText, numberLinePrefix); } @Nullable public Integer getExecutionTime(String fileText) { - return getPrefixedInt(fileText, executionTimePrefix); - } - - @Nullable - public static Integer getPrefixedInt(String fileText, String prefix) { - final String[] numberStrings = findListWithPrefix(prefix, fileText); - if (numberStrings.length > 0) { - return Integer.parseInt(numberStrings[0]); - } - - return null; - } - - @NotNull - private static String[] findListWithPrefix(String prefix, String fileText) { - ArrayList result = new ArrayList(); - - for (String line : findLinesWithPrefixRemoved(prefix, fileText)) { - String[] variants = line.split(","); - - for (String variant : variants) { - result.add(StringUtil.unquoteString(variant.trim())); - } - } - - return ArrayUtil.toStringArray(result); - } - - @NotNull - private static List findLinesWithPrefixRemoved(String prefix, String fileText) { - ArrayList result = new ArrayList(); - - for (String line : fileNonEmptyLines(fileText)) { - if (line.startsWith(prefix)) { - result.add(line.substring(prefix.length()).trim()); - } - } - - return result; - } - - @NotNull - private static List fileNonEmptyLines(String fileText) { - ArrayList result = new ArrayList(); - - try { - BufferedReader reader = new BufferedReader(new StringReader(fileText)); - try { - String line; - - while ((line = reader.readLine()) != null) { - if (!line.isEmpty()) { - result.add(line.trim()); - } - } - } finally { - reader.close(); - } - } catch(IOException e) { - throw new AssertionError(e); - } - - return result; + return InTextDirectivesUtils.getPrefixedInt(fileText, executionTimePrefix); } protected static void assertContainsRenderedItems(CompletionProposal[] expected, LookupElement[] items) { diff --git a/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java b/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java index 663c14df8b9..d12ef7d1976 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java +++ b/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java @@ -27,6 +27,7 @@ import com.intellij.openapi.projectRoots.Sdk; import org.apache.commons.lang.SystemUtils; import org.jetbrains.jet.plugin.PluginTestCaseBase; import org.jetbrains.jet.testing.ConfigRuntimeUtil; +import org.jetbrains.jet.testing.InTextDirectivesUtils; /** * @author Nikolay.Krasko @@ -48,7 +49,7 @@ public abstract class JetCompletionTestBase extends LightCompletionTestCase { final String fileText = getFile().getText(); type = getCompletionType(testName, fileText); - boolean withKotlinRuntime = ExpectedCompletionUtils.getPrefixedInt(fileText, "// RUNTIME:") != null; + boolean withKotlinRuntime = InTextDirectivesUtils.getPrefixedInt(fileText, "// RUNTIME:") != null; try { if (withKotlinRuntime) { diff --git a/idea/tests/org/jetbrains/jet/formatter/AbstractJetFormatterTest.java b/idea/tests/org/jetbrains/jet/formatter/AbstractJetFormatterTest.java index fb17dd563b9..f00e8020031 100644 --- a/idea/tests/org/jetbrains/jet/formatter/AbstractJetFormatterTest.java +++ b/idea/tests/org/jetbrains/jet/formatter/AbstractJetFormatterTest.java @@ -75,32 +75,23 @@ public abstract class AbstractJetFormatterTest extends LightIdeaTestCase { LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.HIGHEST); } -// public static CommonCodeStyleSettings getSettings() { -// CodeStyleSettings rootSettings = CodeStyleSettingsManager.getSettings(getProject()); -// return rootSettings.getCommonSettings(JavaLanguage.INSTANCE); -// } -// -// public static CommonCodeStyleSettings.IndentOptions getIndentOptions() { -// return getSettings().getRootSettings().getIndentOptions(StdFileTypes.JAVA); -// } - public void doTest() throws Exception { doTest(getTestName(false) + ".kt", getTestName(false) + "_after.kt"); } public void doTest(@NonNls String fileNameBefore, @NonNls String fileNameAfter) throws Exception { - doTextTest(Action.REFORMAT, loadFile(fileNameBefore), loadFile(fileNameAfter)); + doTextTest(Action.REFORMAT, loadFile(fileNameBefore), loadFile(fileNameAfter), ""); } - public void doTextTest(@NonNls final String text, @NonNls String textAfter) throws IncorrectOperationException { - doTextTest(Action.REFORMAT, text, textAfter); + public void doTextTest(@NonNls final String text, @NonNls String textAfter, String commentToTextCompare) throws IncorrectOperationException { + doTextTest(Action.REFORMAT, text, textAfter, commentToTextCompare); } public void doIndentTextTest(@NonNls final String text, @NonNls String textAfter) throws IncorrectOperationException { - doTextTest(Action.INDENT, text, textAfter); + doTextTest(Action.INDENT, text, textAfter, ""); } - public void doTextTest(final Action action, final String text, String textAfter) throws IncorrectOperationException { + public void doTextTest(final Action action, final String text, String textAfter, String commentToTextCompare) throws IncorrectOperationException { final PsiFile file = createFile("A.kt", text); if (myLineRange != null) { @@ -140,10 +131,9 @@ public abstract class AbstractJetFormatterTest extends LightIdeaTestCase { fail("Don't expect the document to be null"); return; } - assertEquals(prepareText(textAfter), prepareText(document.getText())); + assertEquals(commentToTextCompare, prepareText(textAfter), prepareText(document.getText())); manager.commitDocument(document); - assertEquals(prepareText(textAfter), prepareText(file.getText())); - + assertEquals(commentToTextCompare, prepareText(textAfter), prepareText(file.getText())); } private static String prepareText(String actual) { @@ -171,7 +161,7 @@ public abstract class AbstractJetFormatterTest extends LightIdeaTestCase { return doc.getText(); } - private static String loadFile(String name) throws Exception { + public static String loadFile(String name) throws Exception { String text = FileUtil.loadFile(new File(BASE_PATH, name)); text = StringUtil.convertLineSeparators(text); return text; diff --git a/idea/tests/org/jetbrains/jet/formatter/FormattingSettingsConfigurator.java b/idea/tests/org/jetbrains/jet/formatter/FormattingSettingsConfigurator.java new file mode 100644 index 00000000000..171f8ac7689 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/formatter/FormattingSettingsConfigurator.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010-2012 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 org.jetbrains.jet.formatter; + +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import org.jetbrains.jet.plugin.JetLanguage; +import org.jetbrains.jet.plugin.formatter.JetCodeStyleSettings; +import org.jetbrains.jet.testing.InTextDirectivesUtils; +import org.junit.Assert; + +import java.lang.reflect.Field; + +/** + * @author Nikolay Krasko + */ +public class FormattingSettingsConfigurator { + private final String[] settingsToTrue; + private final String[] settingsToFalse; + + public FormattingSettingsConfigurator(String fileText) { + settingsToTrue = InTextDirectivesUtils.findListWithPrefix("// SET_TRUE:", fileText); + settingsToFalse = InTextDirectivesUtils.findListWithPrefix("// SET_FALSE:", fileText); + } + + public void configureSettings(CodeStyleSettings settings) { + JetCodeStyleSettings jetSettings = settings.getCustomSettings(JetCodeStyleSettings.class); + CommonCodeStyleSettings jetCommonSettings = settings.getCommonSettings(JetLanguage.INSTANCE); + + for (String trueSetting : settingsToTrue) { + configureSetting(jetSettings, jetCommonSettings, trueSetting, true); + } + + for (String falseSetting : settingsToFalse) { + configureSetting(jetSettings, jetCommonSettings, falseSetting, false); + } + } + + public void configureInvertedSettings(CodeStyleSettings settings) { + JetCodeStyleSettings jetSettings = settings.getCustomSettings(JetCodeStyleSettings.class); + CommonCodeStyleSettings jetCommonSettings = settings.getCommonSettings(JetLanguage.INSTANCE); + + for (String trueSetting : settingsToTrue) { + configureSetting(jetSettings, jetCommonSettings, trueSetting, false); + } + + for (String falseSetting : settingsToFalse) { + configureSetting(jetSettings, jetCommonSettings, falseSetting, true); + } + } + + private static void configureSetting(JetCodeStyleSettings jetSettings, + CommonCodeStyleSettings jetCommonSettings, + String settingName, + boolean value + ) { + try { + Field field = jetCommonSettings.getClass().getDeclaredField(settingName); + setSetting(field, jetCommonSettings, value); + } + catch (NoSuchFieldException e) { + try { + Field field = jetSettings.getClass().getDeclaredField(settingName); + setSetting(field, jetSettings, value); + } + catch (NoSuchFieldException e1) { + Assert.assertTrue(String.format("There's no property with name '%s' for kotlin language", settingName), false); + } + } + } + + private static void setSetting(Field settingField, Object settings, boolean value) { + try { + settingField.setBoolean(settings, value); + } + catch (IllegalAccessException e) { + Assert.assertTrue(String.format("Can't set property with the name %s", settingField.getName()), false); + } + } +} diff --git a/idea/tests/org/jetbrains/jet/formatter/JetFormatterTest.java b/idea/tests/org/jetbrains/jet/formatter/JetFormatterTest.java index 4af6021b330..5e4c65c0729 100644 --- a/idea/tests/org/jetbrains/jet/formatter/JetFormatterTest.java +++ b/idea/tests/org/jetbrains/jet/formatter/JetFormatterTest.java @@ -59,6 +59,14 @@ public class JetFormatterTest extends AbstractJetFormatterTest { doTest(); } + public void testFunctionCallParametersAlign() throws Exception { + doTest(); + } + + public void testFunctionDefParametersAlign() throws Exception { + doTest(); + } + public void testIf() throws Exception { doTest(); } @@ -84,6 +92,10 @@ public class JetFormatterTest extends AbstractJetFormatterTest { getSettings().clearCodeStyleSettings(); } + public void testRightBracketOnNewLine() throws Exception { + doTestWithInvert(); + } + public void testSpaceAroundTypeColon() throws Exception { getJetSettings().SPACE_AFTER_TYPE_COLON = false; getJetSettings().SPACE_BEFORE_TYPE_COLON = true; @@ -105,4 +117,37 @@ public class JetFormatterTest extends AbstractJetFormatterTest { public static CodeStyleSettings getSettings() { return CodeStyleSettingsManager.getSettings(getProject()); } + + @Override + public void doTest() throws Exception { + String originalFileText = AbstractJetFormatterTest.loadFile(getTestName(false) + ".kt"); + + String afterFileName = getTestName(false) + "_after.kt"; + String afterText = AbstractJetFormatterTest.loadFile(afterFileName); + + FormattingSettingsConfigurator configurator = new FormattingSettingsConfigurator(AbstractJetFormatterTest.loadFile( + getTestName(false) + ".kt")); + configurator.configureSettings(getSettings()); + + doTextTest(originalFileText, afterText, String.format("Failure in NORMAL file: %s", afterFileName)); + + getSettings().clearCodeStyleSettings(); + } + + public void doTestWithInvert() throws Exception { + String originalFileText = AbstractJetFormatterTest.loadFile(getTestName(false) + ".kt"); + FormattingSettingsConfigurator configurator = new FormattingSettingsConfigurator(originalFileText); + + String afterFileName = getTestName(false) + "_after.kt"; + String afterText = AbstractJetFormatterTest.loadFile(afterFileName); + configurator.configureSettings(getSettings()); + doTextTest(originalFileText, afterText, String.format("Failure in NORMAL file: %s", afterFileName)); + + String afterInvertedFileName = getTestName(false) + "_after_inv.kt"; + String afterInvertedText = AbstractJetFormatterTest.loadFile(afterInvertedFileName); + configurator.configureInvertedSettings(getSettings()); + doTextTest(originalFileText, afterInvertedText, String.format("Failure in INVERTED file: %s", afterInvertedFileName)); + + getSettings().clearCodeStyleSettings(); + } } diff --git a/idea/tests/org/jetbrains/jet/testing/InTextDirectivesUtils.java b/idea/tests/org/jetbrains/jet/testing/InTextDirectivesUtils.java new file mode 100644 index 00000000000..e02397443dc --- /dev/null +++ b/idea/tests/org/jetbrains/jet/testing/InTextDirectivesUtils.java @@ -0,0 +1,100 @@ +/* + * Copyright 2010-2012 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 org.jetbrains.jet.testing; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Nikolay Krasko + */ +public final class InTextDirectivesUtils { + + private InTextDirectivesUtils() { + } + + @Nullable + public static Integer getPrefixedInt(String fileText, String prefix) { + final String[] numberStrings = findListWithPrefix(prefix, fileText); + if (numberStrings.length > 0) { + return Integer.parseInt(numberStrings[0]); + } + + return null; + } + + @NotNull + public static String[] findListWithPrefix(String prefix, String fileText) { + ArrayList result = new ArrayList(); + + for (String line : findLinesWithPrefixRemoved(prefix, fileText)) { + String[] variants = line.split(","); + + for (String variant : variants) { + result.add(StringUtil.unquoteString(variant.trim())); + } + } + + return ArrayUtil.toStringArray(result); + } + + @NotNull + private static List findLinesWithPrefixRemoved(String prefix, String fileText) { + ArrayList result = new ArrayList(); + + for (String line : fileNonEmptyLines(fileText)) { + if (line.startsWith(prefix)) { + result.add(line.substring(prefix.length()).trim()); + } + } + + return result; + } + + + @NotNull + private static List fileNonEmptyLines(String fileText) { + ArrayList result = new ArrayList(); + + try { + BufferedReader reader = new BufferedReader(new StringReader(fileText)); + try { + String line; + + while ((line = reader.readLine()) != null) { + if (!line.isEmpty()) { + result.add(line.trim()); + } + } + } finally { + reader.close(); + } + } catch(IOException e) { + throw new AssertionError(e); + } + + return result; + } +}