diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/ASTIndentStrategy.java b/idea/src/org/jetbrains/jet/plugin/formatter/ASTIndentStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..7649dbdfefc547e85989800789a5ebd91927e16c --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/formatter/ASTIndentStrategy.java @@ -0,0 +1,158 @@ +/* + * 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.plugin.formatter; + +import com.intellij.formatting.Indent; +import com.intellij.lang.ASTNode; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author Nikolay Krasko + */ +public abstract class ASTIndentStrategy { + public static ASTIndentStrategy constIndent(Indent indent) { + return new ConstIndentStrategy(indent); + } + + public static PositionStrategy forNode(@Nullable String debugInfo) { + return new PositionStrategy(debugInfo); + } + + @Nullable + public abstract Indent getIndent(@NotNull ASTNode node); + + public static class ConstIndentStrategy extends ASTIndentStrategy { + private final Indent indent; + + public ConstIndentStrategy(Indent indent) { + this.indent = indent; + } + + @Nullable + @Override + public Indent getIndent(@NotNull ASTNode node) { + return indent; + } + } + + public static class PositionStrategy extends ASTIndentStrategy { + private Indent defaultIndent = Indent.getNoneIndent(); + + private List in = new ArrayList(); + private List notIn = new ArrayList(); + private List forElement = new ArrayList(); + private List notForElement = new ArrayList(); + + private String debugInfo; + + public PositionStrategy(@Nullable String debugInfo) { + this.debugInfo = debugInfo; + } + + @Override + public String toString() { + return "PositionStrategy " + (debugInfo != null ? debugInfo : "No debug info"); + } + + public PositionStrategy set(Indent indent) { + defaultIndent = indent; + return this; + } + + public PositionStrategy in(@NotNull IElementType parentType, @NotNull IElementType... orParentTypes) { + in.clear(); + in.add(parentType); + Collections.addAll(in, orParentTypes); + return this; + } + + public PositionStrategy notIn(@NotNull IElementType parentType, @NotNull IElementType... orParentTypes) { + notIn.clear(); + notIn.add(parentType); + Collections.addAll(notIn, orParentTypes); + return this; + } + + public PositionStrategy inAny() { + in.clear(); + notIn.clear(); + return this; + } + + public PositionStrategy forType(@NotNull IElementType elementType, @NotNull IElementType... otherTypes) { + forElement.clear(); + forElement.add(elementType); + Collections.addAll(forElement, otherTypes); + + return this; + } + + public PositionStrategy notForType(@NotNull IElementType elementType, @NotNull IElementType... otherTypes) { + notForElement.clear(); + notForElement.add(elementType); + Collections.addAll(notForElement, otherTypes); + + return this; + } + + public PositionStrategy forAny() { + forElement.clear(); + notForElement.clear(); + return this; + } + + @Nullable + @Override + public Indent getIndent(@NotNull ASTNode node) { + if (!forElement.isEmpty()) { + if (!forElement.contains(node.getElementType())) { + return null; + } + } + + if (notForElement.contains(node.getElementType())) { + return null; + } + + ASTNode parent = node.getTreeParent(); + if (parent != null) { + if (!in.isEmpty()) { + if (!in.contains(parent.getElementType())) { + return null; + } + } + + if (notIn.contains(parent.getElementType())) { + return null; + } + } + else { + if (!in.isEmpty()) { + return null; + } + } + + return defaultIndent; + } + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java index 773f432d7b30b680f93c18810c7edaead919598c..5286b584591b5f107082311972618fc3b25fe13b 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java @@ -48,10 +48,6 @@ public class JetBlock extends AbstractBlock { JetNodeTypes.CLASS_BODY, JetNodeTypes.FUNCTION_LITERAL_EXPRESSION); - private static final TokenSet STATEMENT_PARTS = TokenSet.create( - JetNodeTypes.THEN, - JetNodeTypes.ELSE); - // private static final List public JetBlock(@NotNull ASTNode node, @@ -241,35 +237,50 @@ public class JetBlock extends AbstractBlock { }; } - @Override - protected Indent getChildIndent() { - return super.getChildIndent(); //To change body of overridden methods use File | Settings | File Templates. - } + static ASTIndentStrategy[] INDENT_RULES = new ASTIndentStrategy[] { + ASTIndentStrategy.forNode("No indent for braces in blocks") + .in(JetNodeTypes.BLOCK, JetNodeTypes.CLASS_BODY, JetNodeTypes.FUNCTION_LITERAL_EXPRESSION) + .forType(JetTokens.RBRACE, JetTokens.LBRACE) + .set(Indent.getNoneIndent()), + + ASTIndentStrategy.forNode("Indent for block content") + .in(JetNodeTypes.BLOCK, JetNodeTypes.CLASS_BODY, JetNodeTypes.FUNCTION_LITERAL_EXPRESSION) + .notForType(JetTokens.RBRACE, JetTokens.LBRACE) + .set(Indent.getNormalIndent()), + + ASTIndentStrategy.forNode("Indent for property accessors") + .in(JetNodeTypes.PROPERTY) + .forType(JetNodeTypes.PROPERTY_ACCESSOR) + .set(Indent.getNormalIndent()), + + ASTIndentStrategy.forNode("For a single statement if 'for'") + .in(JetNodeTypes.BODY) + .notForType(JetNodeTypes.BLOCK) + .set(Indent.getNormalIndent()), + + ASTIndentStrategy.forNode("For the entry in when") + .forType(JetNodeTypes.WHEN_ENTRY) + .set(Indent.getNormalIndent()), + + ASTIndentStrategy.forNode("For single statement in THEN and ELSE") + .in(JetNodeTypes.THEN, JetNodeTypes.ELSE) + .notForType(JetNodeTypes.BLOCK) + .set(Indent.getNormalIndent()) + }; @Nullable - protected Indent createChildIndent(@NotNull ASTNode child) { - CommonCodeStyleSettings commonSettings = mySettings.getCommonSettings(JetLanguage.INSTANCE); - + protected static Indent createChildIndent(@NotNull ASTNode child) { ASTNode childParent = child.getTreeParent(); IElementType childType = child.getElementType(); - if (CODE_BLOCKS.contains(myNode.getElementType())) { - return indentIfNotBrace(child); - } - - if (childParent != null && - childParent.getElementType() == JetNodeTypes.BODY && - childType != JetNodeTypes.BLOCK) { - - // For a single statement if 'for' - return Indent.getNormalIndent(); + for (ASTIndentStrategy strategy : INDENT_RULES) { + Indent indent = strategy.getIndent(child); + if (indent != null) { + return indent; + } } - if (childType == JetNodeTypes.WHEN_ENTRY) { - // For the entry in when - // TODO: Add an option for configuration? - return Indent.getNormalIndent(); - } + // TODO: Try to rewrite other rules to declarative style if (childParent != null && childParent.getElementType() == JetNodeTypes.WHEN_ENTRY) { ASTNode prev = getPrevWithoutWhitespace(child); @@ -278,10 +289,6 @@ public class JetBlock extends AbstractBlock { } } - if (STATEMENT_PARTS.contains(myNode.getElementType()) && childType != 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); diff --git a/idea/testData/formatter/GetterAndSetter.kt b/idea/testData/formatter/GetterAndSetter.kt new file mode 100644 index 0000000000000000000000000000000000000000..79666bc37fa868924b019fa27d0e551a4dcaf8b5 --- /dev/null +++ b/idea/testData/formatter/GetterAndSetter.kt @@ -0,0 +1,9 @@ +class Test { + var test : Int + get () { + return 0 + } + set (value) { + throw NotSupportedException() + } +} \ No newline at end of file diff --git a/idea/testData/formatter/GetterAndSetter_after.kt b/idea/testData/formatter/GetterAndSetter_after.kt new file mode 100644 index 0000000000000000000000000000000000000000..005dc390f7521eaf7b96545c623b337d90a4a23c --- /dev/null +++ b/idea/testData/formatter/GetterAndSetter_after.kt @@ -0,0 +1,9 @@ +class Test { + var test : Int + get () { + return 0 + } + set (value) { + throw NotSupportedException() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/afterWrongGetterParameterType.kt b/idea/testData/quickfix/typeAddition/afterWrongGetterParameterType.kt index bd4fd0c651927273ebedd527f884baf7d4365b94..e42545e10ae742286eae55a494a925c9bc7c621d 100644 --- a/idea/testData/quickfix/typeAddition/afterWrongGetterParameterType.kt +++ b/idea/testData/quickfix/typeAddition/afterWrongGetterParameterType.kt @@ -1,5 +1,5 @@ // "Change getter type to Int" "true" class A() { val i: Int - get(): Int = 1 + get(): Int = 1 } diff --git a/idea/testData/quickfix/typeAddition/afterWrongSetterParameterType.kt b/idea/testData/quickfix/typeAddition/afterWrongSetterParameterType.kt index 99e86a2179dbf5256116797af41ad2c78e1ee1cd..3dd8a3f46ff9fbe00db573534895e349d1675d25 100644 --- a/idea/testData/quickfix/typeAddition/afterWrongSetterParameterType.kt +++ b/idea/testData/quickfix/typeAddition/afterWrongSetterParameterType.kt @@ -1,5 +1,5 @@ // "Change setter parameter type to Int" "true" class A() { var i: Int = 0 - set(v: Int) {} + set(v: Int) {} } diff --git a/idea/testData/quickfix/typeAddition/beforeWrongGetterParameterType.kt b/idea/testData/quickfix/typeAddition/beforeWrongGetterParameterType.kt index 5e9d12911c8e34438bb5316ae9cfae1204e05f66..5ce32d1deb7638d64383b840240cb4cc36856397 100644 --- a/idea/testData/quickfix/typeAddition/beforeWrongGetterParameterType.kt +++ b/idea/testData/quickfix/typeAddition/beforeWrongGetterParameterType.kt @@ -1,5 +1,5 @@ // "Change getter type to Int" "true" class A() { val i: Int - get(): Any = 1 + get(): Any = 1 } diff --git a/idea/testData/quickfix/typeAddition/beforeWrongSetterParameterType.kt b/idea/testData/quickfix/typeAddition/beforeWrongSetterParameterType.kt index b84c2887217e07e44e944708d7569613108d0ff0..7544f3f1f68ddd94fc221adee594c5538947aee4 100644 --- a/idea/testData/quickfix/typeAddition/beforeWrongSetterParameterType.kt +++ b/idea/testData/quickfix/typeAddition/beforeWrongSetterParameterType.kt @@ -1,5 +1,5 @@ // "Change setter parameter type to Int" "true" class A() { var i: Int = 0 - set(v: Any) {} + set(v: Any) {} } diff --git a/idea/testData/quickfix/variables/changeMutability/afterValWithSetter.kt b/idea/testData/quickfix/variables/changeMutability/afterValWithSetter.kt index 6c6d3bcca0ba6da5aa0bfb33678479609d5b3fd6..f9853f46cf07ce94d5925134a2a8c19d9c2a4f3c 100644 --- a/idea/testData/quickfix/variables/changeMutability/afterValWithSetter.kt +++ b/idea/testData/quickfix/variables/changeMutability/afterValWithSetter.kt @@ -1,6 +1,6 @@ // "Make variable mutable" "true" class A() { var a : Int = 0 - set(v : Int) { - } + set(v : Int) { + } } diff --git a/idea/testData/templates/exval.exp.kt b/idea/testData/templates/exval.exp.kt index f3e8ea4ec7a48a94ce0052dc7506492afb1e71ef..7f73364024af1b41948aa3b8fb0e22f36869a56e 100644 --- a/idea/testData/templates/exval.exp.kt +++ b/idea/testData/templates/exval.exp.kt @@ -1,4 +1,4 @@ val Int.v : Int -get() { - -} \ No newline at end of file + get() { + + } \ No newline at end of file diff --git a/idea/testData/templates/exvar.exp.kt b/idea/testData/templates/exvar.exp.kt index bf56eeac0555961ccc3ba7588a746a4d98d6a76d..3ac384da2040b86a2aea6197feb0ff4797abeddc 100644 --- a/idea/testData/templates/exvar.exp.kt +++ b/idea/testData/templates/exvar.exp.kt @@ -1,7 +1,7 @@ var Int.v : Int -get() { - -} -set(value) { + get() { + + } + set(value) { -} \ No newline at end of file + } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/formatter/JetFormatterTest.java b/idea/tests/org/jetbrains/jet/formatter/JetFormatterTest.java index 5e4c65c0729752444af232addd2e0458092fcdeb..5a56dc6b949b28f5428db165a4f2c39c79999aad 100644 --- a/idea/tests/org/jetbrains/jet/formatter/JetFormatterTest.java +++ b/idea/tests/org/jetbrains/jet/formatter/JetFormatterTest.java @@ -67,6 +67,10 @@ public class JetFormatterTest extends AbstractJetFormatterTest { doTest(); } + public void testGetterAndSetter() throws Exception { + doTest(); + } + public void testIf() throws Exception { doTest(); } diff --git a/idea/tests/org/jetbrains/jet/formatter/JetTypingIndentationTest.java b/idea/tests/org/jetbrains/jet/formatter/JetTypingIndentationTest.java index 696397f5a43006ff7e4d3c8824543e8a71f0e176..df528a40841892d20c75f34a2392bff45b1a409d 100644 --- a/idea/tests/org/jetbrains/jet/formatter/JetTypingIndentationTest.java +++ b/idea/tests/org/jetbrains/jet/formatter/JetTypingIndentationTest.java @@ -21,7 +21,6 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.testFramework.LightCodeInsightTestCase; import org.jetbrains.jet.plugin.PluginTestCaseBase; -import org.jetbrains.jet.plugin.formatter.JetCodeStyleSettings; import java.io.File; @@ -106,10 +105,6 @@ public class JetTypingIndentationTest extends LightCodeInsightTestCase { checkResultByFile(afterFileName); } - public static JetCodeStyleSettings getJetSettings() { - return getSettings().getCustomSettings(JetCodeStyleSettings.class); - } - public static CodeStyleSettings getSettings() { return CodeStyleSettingsManager.getSettings(getProject()); }