Call chain indentation logic that actually makes sense
#KT-22346 Fixed
This commit is contained in:
@@ -127,7 +127,11 @@ abstract class KotlinCommonBlock(
|
|||||||
// relative to it when it starts from new line (see Indent javadoc).
|
// relative to it when it starts from new line (see Indent javadoc).
|
||||||
|
|
||||||
val isNonFirstChainedCall = operationBlockIndex > 0 && isCallBlock(nodeSubBlocks[operationBlockIndex - 1])
|
val isNonFirstChainedCall = operationBlockIndex > 0 && isCallBlock(nodeSubBlocks[operationBlockIndex - 1])
|
||||||
val enforceIndentToChildren = isNonFirstChainedCall && hasLineBreakBefore(nodeSubBlocks[operationBlockIndex])
|
|
||||||
|
// enforce indent to children when there's a line break before the dot in any call in the chain (meaning that
|
||||||
|
// the call chain following that call is indented)
|
||||||
|
val enforceIndentToChildren = anyCallInCallChainIsWrapped(nodeSubBlocks[operationBlockIndex - 1])
|
||||||
|
|
||||||
val indentType = if (settings.kotlinCustomSettings.CONTINUATION_INDENT_FOR_CHAINED_CALLS) {
|
val indentType = if (settings.kotlinCustomSettings.CONTINUATION_INDENT_FOR_CHAINED_CALLS) {
|
||||||
if (enforceIndentToChildren) Indent.Type.CONTINUATION else Indent.Type.CONTINUATION_WITHOUT_FIRST
|
if (enforceIndentToChildren) Indent.Type.CONTINUATION else Indent.Type.CONTINUATION_WITHOUT_FIRST
|
||||||
} else {
|
} else {
|
||||||
@@ -159,6 +163,18 @@ abstract class KotlinCommonBlock(
|
|||||||
return subList(0, index) + operationSyntheticBlock
|
return subList(0, index) + operationSyntheticBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun anyCallInCallChainIsWrapped(astBlock: ASTBlock): Boolean {
|
||||||
|
var result: ASTBlock? = astBlock
|
||||||
|
while (true) {
|
||||||
|
if (result == null || !isCallBlock(result)) return false
|
||||||
|
val dot = result.node?.findChildByType(QUALIFIED_OPERATION)
|
||||||
|
if (dot != null && hasLineBreakBefore(dot)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
result = result.subBlocks.firstOrNull() as? ASTBlock?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun isCallBlock(astBlock: ASTBlock): Boolean {
|
private fun isCallBlock(astBlock: ASTBlock): Boolean {
|
||||||
val node = astBlock.node
|
val node = astBlock.node
|
||||||
return node.elementType in QUALIFIED_EXPRESSIONS && node.lastChildNode?.elementType == KtNodeTypes.CALL_EXPRESSION
|
return node.elementType in QUALIFIED_EXPRESSIONS && node.lastChildNode?.elementType == KtNodeTypes.CALL_EXPRESSION
|
||||||
@@ -602,9 +618,9 @@ fun needWrapArgumentList(psi: PsiElement): Boolean {
|
|||||||
return args?.singleOrNull()?.getArgumentExpression() !is KtObjectLiteralExpression
|
return args?.singleOrNull()?.getArgumentExpression() !is KtObjectLiteralExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hasLineBreakBefore(block: ASTBlock): Boolean {
|
private fun hasLineBreakBefore(node: ASTNode): Boolean {
|
||||||
val prevSibling = block.node.leaves(false)
|
val prevSibling = node.leaves(false)
|
||||||
.dropWhile { it.psi is PsiComment || it.elementType == KtTokens.RBRACE }
|
.dropWhile { it.psi is PsiComment }
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
return prevSibling?.elementType == TokenType.WHITE_SPACE && prevSibling?.textContains('\n') == true
|
return prevSibling?.elementType == TokenType.WHITE_SPACE && prevSibling?.textContains('\n') == true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
val x = foo.bar {
|
||||||
|
it + 2
|
||||||
|
}.let {
|
||||||
|
println(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SET_FALSE: CONTINUATION_INDENT_FOR_CHAINED_CALLS
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
val x = foo.bar {
|
||||||
|
it + 2
|
||||||
|
}.let {
|
||||||
|
println(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SET_FALSE: CONTINUATION_INDENT_FOR_CHAINED_CALLS
|
||||||
@@ -988,6 +988,12 @@ public class FormatterTestGenerated extends AbstractFormatterTest {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/callChain/KT22148.after.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/callChain/KT22148.after.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("KT22346.after.kt")
|
||||||
|
public void testKT22346() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/callChain/KT22346.after.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/formatter/fileAnnotations")
|
@TestMetadata("idea/testData/formatter/fileAnnotations")
|
||||||
|
|||||||
Reference in New Issue
Block a user