- Formatter parameter alignment

- Change formatter testing framework
- Activate "Wrapping and Braces" tab
This commit is contained in:
Nikolay Krasko
2012-03-30 19:22:21 +04:00
parent d378e4bd06
commit cc449bcdd8
16 changed files with 484 additions and 241 deletions
@@ -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<Block> 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<IndentWhitespaceRule>
public JetBlock(@NotNull ASTNode node,
@@ -78,9 +80,12 @@ public class JetBlock extends AbstractBlock {
}
return new ArrayList<Block>(mySubBlocks);
}
private List<Block> buildSubBlocks() {
List<Block> blocks = new ArrayList<Block>();
Map<ASTNode, Alignment> 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<ASTNode, Alignment> 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<ASTNode, Alignment> result = new HashMap<ASTNode, Alignment>();
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();
}
}
@@ -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);
}
};
}
@@ -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
@@ -0,0 +1,6 @@
fun test() {
someTestLong(12,
13)
}
// SET_TRUE: ALIGN_MULTILINE_PARAMETERS_IN_CALLS
@@ -0,0 +1,6 @@
fun test() {
someTestLong(12,
13)
}
// SET_TRUE: ALIGN_MULTILINE_PARAMETERS_IN_CALLS
@@ -0,0 +1,3 @@
fun test(a : Int,
b : Int) {
}
@@ -0,0 +1,3 @@
fun test(a : Int,
b : Int) {
}
@@ -0,0 +1,7 @@
class Test {
fun someLong(a : Int
) {
}
}
// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS
@@ -0,0 +1,7 @@
class Test {
fun someLong(a : Int
) {
}
}
// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS
@@ -0,0 +1,7 @@
class Test {
fun someLong(a : Int
) {
}
}
// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS
@@ -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<CompletionProposal> proposals = new ArrayList<CompletionProposal>();
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<String> result = new ArrayList<String>();
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<String> findLinesWithPrefixRemoved(String prefix, String fileText) {
ArrayList<String> result = new ArrayList<String>();
for (String line : fileNonEmptyLines(fileText)) {
if (line.startsWith(prefix)) {
result.add(line.substring(prefix.length()).trim());
}
}
return result;
}
@NotNull
private static List<String> fileNonEmptyLines(String fileText) {
ArrayList<String> result = new ArrayList<String>();
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) {
@@ -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) {
@@ -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;
@@ -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);
}
}
}
@@ -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();
}
}
@@ -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<String> result = new ArrayList<String>();
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<String> findLinesWithPrefixRemoved(String prefix, String fileText) {
ArrayList<String> result = new ArrayList<String>();
for (String line : fileNonEmptyLines(fileText)) {
if (line.startsWith(prefix)) {
result.add(line.substring(prefix.length()).trim());
}
}
return result;
}
@NotNull
private static List<String> fileNonEmptyLines(String fileText) {
ArrayList<String> result = new ArrayList<String>();
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;
}
}