Option to apply normal indent to children of 'if' expressions

This commit is contained in:
Dmitry Jemerov
2017-12-13 16:29:27 +01:00
parent 640bf22e4f
commit 79a509df7b
11 changed files with 124 additions and 8 deletions
@@ -45,6 +45,7 @@ public class KotlinCodeStyleSettings extends CustomCodeStyleSettings {
public boolean CONTINUATION_INDENT_FOR_EXPRESSION_BODIES = true; public boolean CONTINUATION_INDENT_FOR_EXPRESSION_BODIES = true;
public boolean CONTINUATION_INDENT_FOR_CHAINED_CALLS = true; public boolean CONTINUATION_INDENT_FOR_CHAINED_CALLS = true;
public boolean CONTINUATION_INDENT_IN_SUPERTYPE_LISTS = true; public boolean CONTINUATION_INDENT_IN_SUPERTYPE_LISTS = true;
public boolean CONTINUATION_INDENT_IN_IF_CONDITIONS = true;
public int BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES = 0; public int BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES = 0;
public int WRAP_EXPRESSION_BODY_FUNCTIONS = 0; public int WRAP_EXPRESSION_BODY_FUNCTIONS = 0;
public int WRAP_ELVIS_EXPRESSIONS = 1; public int WRAP_ELVIS_EXPRESSIONS = 1;
@@ -358,12 +358,32 @@ abstract class KotlinCommonBlock(
val childrenAlignmentStrategy = getChildrenAlignmentStrategy() val childrenAlignmentStrategy = getChildrenAlignmentStrategy()
val wrappingStrategy = getWrappingStrategy() val wrappingStrategy = getWrappingStrategy()
return node.children() val childNodes = if (node.elementType == KtNodeTypes.BINARY_EXPRESSION) {
val binaryExpressionChildren = mutableListOf<ASTNode>()
collectBinaryExpressionChildren(node, binaryExpressionChildren)
binaryExpressionChildren.asSequence()
}
else {
node.children()
}
return childNodes
.filter { it.textRange.length > 0 && it.elementType != TokenType.WHITE_SPACE } .filter { it.textRange.length > 0 && it.elementType != TokenType.WHITE_SPACE }
.map { buildSubBlock(it, childrenAlignmentStrategy, wrappingStrategy ) } .map { buildSubBlock(it, childrenAlignmentStrategy, wrappingStrategy ) }
.toList() .toList()
} }
private fun collectBinaryExpressionChildren(node: ASTNode, result: MutableList<ASTNode>) {
for (child in node.children()) {
if (child.elementType == KtNodeTypes.BINARY_EXPRESSION) {
collectBinaryExpressionChildren(child, result)
}
else {
result.add(child)
}
}
}
private fun getWrappingStrategy(): WrappingStrategy { private fun getWrappingStrategy(): WrappingStrategy {
val commonSettings = settings.kotlinCommonSettings val commonSettings = settings.kotlinCommonSettings
val elementType = node.elementType val elementType = node.elementType
@@ -574,6 +594,16 @@ private val INDENT_RULES = arrayOf<NodeIndentStrategy>(
} }
.continuationIf(KotlinCodeStyleSettings::CONTINUATION_INDENT_FOR_EXPRESSION_BODIES, indentFirst = true), .continuationIf(KotlinCodeStyleSettings::CONTINUATION_INDENT_FOR_EXPRESSION_BODIES, indentFirst = true),
strategy("If condition")
.within(KtNodeTypes.CONDITION)
.set { settings ->
val indentType = if (settings.kotlinCustomSettings.CONTINUATION_INDENT_IN_IF_CONDITIONS)
Indent.Type.CONTINUATION
else
Indent.Type.NORMAL
Indent.getIndent(indentType, false, true)
},
strategy("Property accessor expression body") strategy("Property accessor expression body")
.within(KtNodeTypes.PROPERTY_ACCESSOR) .within(KtNodeTypes.PROPERTY_ACCESSOR)
.forElement { .forElement {
@@ -614,6 +644,7 @@ private val INDENT_RULES = arrayOf<NodeIndentStrategy>(
strategy("Binary expressions") strategy("Binary expressions")
.within(BINARY_EXPRESSIONS) .within(BINARY_EXPRESSIONS)
.forElement { node -> !node.suppressBinaryExpressionIndent() }
.set(Indent.getContinuationWithoutFirstIndent(false)), .set(Indent.getContinuationWithoutFirstIndent(false)),
strategy("Parenthesized expression") strategy("Parenthesized expression")
@@ -678,6 +709,18 @@ private fun hasErrorElementBefore(node: ASTNode): Boolean {
return lastChild?.elementType == TokenType.ERROR_ELEMENT return lastChild?.elementType == TokenType.ERROR_ELEMENT
} }
/**
* Suppress indent for binary expressions when there is a block higher in the tree that forces
* its indent to children ('if' condition or elvis).
*/
private fun ASTNode.suppressBinaryExpressionIndent(): Boolean {
var psi = psi.parent as? KtBinaryExpression ?: return false
while (psi.parent is KtBinaryExpression) {
psi = psi.parent as KtBinaryExpression
}
return psi.parent?.node?.elementType == KtNodeTypes.CONDITION || psi.operationToken == KtTokens.ELVIS
}
private fun getAlignmentForChildInParenthesis( private fun getAlignmentForChildInParenthesis(
shouldAlignChild: Boolean, parameter: IElementType, delimiter: IElementType, shouldAlignChild: Boolean, parameter: IElementType, delimiter: IElementType,
shouldAlignParenthesis: Boolean, openBracket: IElementType, closeBracket: IElementType): CommonAlignmentStrategy { shouldAlignParenthesis: Boolean, openBracket: IElementType, closeBracket: IElementType): CommonAlignmentStrategy {
@@ -40,6 +40,10 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
is Number -> 0 is Number -> 0
else -> 1 else -> 1
} }
if (i2 > 0 &&
i3 < 0) {
return 2
}
return 0 return 0
} }
private fun foo2():Int { private fun foo2():Int {
@@ -307,6 +311,11 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
"Elvis expressions", "Elvis expressions",
options = *arrayOf(CodeStyleSettingsCustomizable.WRAP_OPTIONS_FOR_SINGLETON, CodeStyleSettingsCustomizable.WRAP_VALUES_FOR_SINGLETON) options = *arrayOf(CodeStyleSettingsCustomizable.WRAP_OPTIONS_FOR_SINGLETON, CodeStyleSettingsCustomizable.WRAP_VALUES_FOR_SINGLETON)
) )
showCustomOption(
KotlinCodeStyleSettings::CONTINUATION_INDENT_IN_IF_CONDITIONS,
"Use continuation indent in conditions",
CodeStyleSettingsCustomizable.WRAPPING_IF_STATEMENT
)
} }
LanguageCodeStyleSettingsProvider.SettingsType.BLANK_LINES_SETTINGS -> { LanguageCodeStyleSettingsProvider.SettingsType.BLANK_LINES_SETTINGS -> {
consumer.showStandardOptions( consumer.showStandardOptions(
+3 -4
View File
@@ -2,9 +2,9 @@ fun test() {
val somelong = 1 + 2 + val somelong = 1 + 2 +
3 - 4 - 3 - 4 -
5 * 6 * 5 * 6 *
7 / 8 / 7 / 8 /
9 % 10 % 9 % 10 %
11 11
val withBrackets = 3 + val withBrackets = 3 +
4 - (5 + 4 - (5 +
@@ -12,4 +12,3 @@ fun test() {
} }
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION // SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// Strage behaviour for disabled alignment is same to Java
-1
View File
@@ -12,4 +12,3 @@ fun test() {
} }
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION // SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// Strage behaviour for disabled alignment is same to Java
-1
View File
@@ -12,4 +12,3 @@ fun test() {
} }
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION // SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// Strage behaviour for disabled alignment is same to Java
+18
View File
@@ -0,0 +1,18 @@
fun foo() {
if ("abc" > "def" &&
"qqq" < "bbb" &&
"ddd" > "efg") {
println("foo")
}
}
fun foo() {
if (
"abc" > "def" &&
"qqq" < "bbb" &&
"ddd" > "efg") {
println("foo")
}
}
// SET_TRUE: CONTINUATION_INDENT_IN_IF_CONDITIONS
+18
View File
@@ -0,0 +1,18 @@
fun foo() {
if ("abc" > "def" &&
"qqq" < "bbb" &&
"ddd" > "efg") {
println("foo")
}
}
fun foo() {
if (
"abc" > "def" &&
"qqq" < "bbb" &&
"ddd" > "efg") {
println("foo")
}
}
// SET_TRUE: CONTINUATION_INDENT_IN_IF_CONDITIONS
+18
View File
@@ -0,0 +1,18 @@
fun foo() {
if ("abc" > "def" &&
"qqq" < "bbb" &&
"ddd" > "efg") {
println("foo")
}
}
fun foo() {
if (
"abc" > "def" &&
"qqq" < "bbb" &&
"ddd" > "efg") {
println("foo")
}
}
// SET_TRUE: CONTINUATION_INDENT_IN_IF_CONDITIONS
@@ -1,5 +1,5 @@
fun foo(b: Boolean) { fun foo(b: Boolean) {
if (// comment 1 if (// comment 1
b) 1 // comment 2 b) 1 // comment 2
else 2 else 2
} }
@@ -470,6 +470,12 @@ public class FormatterTestGenerated extends AbstractFormatterTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("IfConditionIndent.after.kt")
public void testIfConditionIndent() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/IfConditionIndent.after.kt");
doTest(fileName);
}
@TestMetadata("IfElseRemoveLineBreak.after.kt") @TestMetadata("IfElseRemoveLineBreak.after.kt")
public void testIfElseRemoveLineBreak() throws Exception { public void testIfElseRemoveLineBreak() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/IfElseRemoveLineBreak.after.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/IfElseRemoveLineBreak.after.kt");
@@ -1316,6 +1322,12 @@ public class FormatterTestGenerated extends AbstractFormatterTest {
doTestInverted(fileName); doTestInverted(fileName);
} }
@TestMetadata("IfConditionIndent.after.inv.kt")
public void testIfConditionIndent() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/IfConditionIndent.after.inv.kt");
doTestInverted(fileName);
}
@TestMetadata("IfElseWithTrickyComments.after.inv.kt") @TestMetadata("IfElseWithTrickyComments.after.inv.kt")
public void testIfElseWithTrickyComments() throws Exception { public void testIfElseWithTrickyComments() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/IfElseWithTrickyComments.after.inv.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/IfElseWithTrickyComments.after.inv.kt");