LineIndentProvider: support elvis operator

Part of #KT-22211
This commit is contained in:
Dmitry Gridin
2020-06-09 12:35:00 +07:00
parent cf655a829c
commit f833b4fe63
20 changed files with 227 additions and 6 deletions
@@ -13,4 +13,8 @@ interface KotlinIndentationAdjuster {
// ALIGN_MULTILINE_BINARY_OPERATION // ALIGN_MULTILINE_BINARY_OPERATION
val alignWhenMultilineBinaryExpression: Boolean val alignWhenMultilineBinaryExpression: Boolean
get() = false get() = false
// CONTINUATION_INDENT_IN_ELVIS
val continuationIndentInElvis: Boolean
get() = false
} }
@@ -68,6 +68,18 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
val before = currentPosition.beforeOptionalMix(*WHITE_SPACE_OR_COMMENT_BIT_SET) val before = currentPosition.beforeOptionalMix(*WHITE_SPACE_OR_COMMENT_BIT_SET)
val after = currentPosition.afterOptionalMix(*WHITE_SPACE_OR_COMMENT_BIT_SET) val after = currentPosition.afterOptionalMix(*WHITE_SPACE_OR_COMMENT_BIT_SET)
when { when {
after.isAt(Quest) && after.after().isAt(Colon) -> {
val indent = if (settings.continuationIndentInElvis)
Indent.getContinuationIndent()
else
Indent.getNormalIndent()
return factory.createIndentCalculator(indent, before.startOffset)
}
before.isAt(Colon) && before.before().isAt(Quest) ->
return factory.createIndentCalculator(Indent.getNoneIndent(), before.startOffset)
before.isAt(TemplateEntryOpen) -> { before.isAt(TemplateEntryOpen) -> {
val indent = if (!currentPosition.hasLineBreaksAfter(offset) && after.isAt(TemplateEntryClose)) val indent = if (!currentPosition.hasLineBreaksAfter(offset) && after.isAt(TemplateEntryClose))
Indent.getNoneIndent() Indent.getNoneIndent()
@@ -77,10 +89,8 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
return factory.createIndentCalculator(indent, before.startOffset) return factory.createIndentCalculator(indent, before.startOffset)
} }
before.isAtAnyOf(TryKeyword) || before.isFinallyKeyword() -> return factory.createIndentCalculator( before.isAtAnyOf(TryKeyword) || before.isFinallyKeyword() ->
Indent.getNoneIndent(), return factory.createIndentCalculator(Indent.getNoneIndent(), IndentCalculator.LINE_BEFORE)
IndentCalculator.LINE_BEFORE,
)
after.isAt(TemplateEntryClose) -> { after.isAt(TemplateEntryClose) -> {
val indent = if (currentPosition.hasEmptyLineAfter(offset)) Indent.getNormalIndent() else Indent.getNoneIndent() val indent = if (currentPosition.hasEmptyLineAfter(offset)) Indent.getNormalIndent() else Indent.getNoneIndent()
@@ -456,8 +466,7 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
private fun JavaLikeLangLineIndentProvider.IndentCalculatorFactory.createIndentCalculator( private fun JavaLikeLangLineIndentProvider.IndentCalculatorFactory.createIndentCalculator(
indent: Indent, indent: Indent,
baseLineOffset: Int, baseLineOffset: Int,
): IndentCalculator = ): IndentCalculator = createIndentCalculator(indent) { baseLineOffset } ?: error("Contract (null, _ -> null) is broken")
createIndentCalculator(indent) { baseLineOffset } ?: error("Contract (null, _ -> null) is broken")
private fun SemanticEditorPosition.textOfCurrentPosition(): String = private fun SemanticEditorPosition.textOfCurrentPosition(): String =
if (isAtEnd) "" else chars.subSequence(startOffset, after().startOffset).toString() if (isAtEnd) "" else chars.subSequence(startOffset, after().startOffset).toString()
@@ -903,6 +903,44 @@ public class PerformanceTypingIndentationTestGenerated extends AbstractPerforman
runTest("idea/testData/indentationOnNewline/WhileWithoutCondition.kt"); runTest("idea/testData/indentationOnNewline/WhileWithoutCondition.kt");
} }
@TestMetadata("idea/testData/indentationOnNewline/elvis")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Elvis extends AbstractPerformanceTypingIndentationTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doPerfTest, this, testDataFilePath);
}
@TestMetadata("AfterElvis.kt")
public void testAfterElvis() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/AfterElvis.kt");
}
@TestMetadata("AfterElvis2.kt")
public void testAfterElvis2() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/AfterElvis2.kt");
}
@TestMetadata("AfterElvisInBinaryExpression.kt")
public void testAfterElvisInBinaryExpression() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/AfterElvisInBinaryExpression.kt");
}
public void testAllFilesPresentInElvis() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/indentationOnNewline/elvis"), Pattern.compile("^([^.]+)\\.(kt|kts)$"), null, true);
}
@TestMetadata("BeforeElvis.kt")
public void testBeforeElvis() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/BeforeElvis.kt");
}
@TestMetadata("BeforeElvisInBinaryExpression.kt")
public void testBeforeElvisInBinaryExpression() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/BeforeElvisInBinaryExpression.kt");
}
}
@TestMetadata("idea/testData/indentationOnNewline/script") @TestMetadata("idea/testData/indentationOnNewline/script")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -28,6 +28,9 @@ class KotlinLineIndentProvider : KotlinLikeLangLineIndentProvider() {
override val alignWhenMultilineBinaryExpression: Boolean override val alignWhenMultilineBinaryExpression: Boolean
get() = settings.kotlinCommonSettings.ALIGN_MULTILINE_BINARY_OPERATION get() = settings.kotlinCommonSettings.ALIGN_MULTILINE_BINARY_OPERATION
override val continuationIndentInElvis: Boolean
get() = settings.kotlinCustomSettings.CONTINUATION_INDENT_IN_ELVIS
} }
companion object { companion object {
@@ -0,0 +1,6 @@
fun test(some: Any?, error: Int) {
val test = some ?:
<caret>error
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,6 @@
fun test(some: Any?, error: Int) {
val test = some ?:
<caret>error
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,5 @@
fun test(some: Any?, error: Int) {
val test = some ?:<caret> error
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,8 @@
fun test(some: Any?, error: Int) {
some?.let {
println(some)
} ?:
<caret>println(error)
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,8 @@
fun test(some: Any?, error: Int) {
some?.let {
println(some)
} ?:
<caret>println(error)
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,7 @@
fun test(some: Any?, error: Int) {
some?.let {
println(some)
} ?: <caret>println(error)
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,6 @@
fun a() {
println(1 + null ?:
<caret>2)
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,6 @@
fun a() {
println(1 + null ?:
<caret>2)
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,5 @@
fun a() {
println(1 + null ?: <caret>2)
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,6 @@
fun test(some: Any?, error: Int) {
val test = some
<caret>?: error
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,6 @@
fun test(some: Any?, error: Int) {
val test = some
<caret>?: error
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,5 @@
fun test(some: Any?, error: Int) {
val test = some <caret>?: error
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,6 @@
fun a() {
println(1 + null
<caret>?: 2)
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,6 @@
fun a() {
println(1 + null
<caret>?: 2)
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -0,0 +1,5 @@
fun a() {
println(1 + null <caret>?: 2)
}
// SET_FALSE: CONTINUATION_INDENT_IN_ELVIS
@@ -900,6 +900,44 @@ public class TypingIndentationTestBaseGenerated extends AbstractTypingIndentatio
runTest("idea/testData/indentationOnNewline/WhileWithoutCondition.after.kt"); runTest("idea/testData/indentationOnNewline/WhileWithoutCondition.after.kt");
} }
@TestMetadata("idea/testData/indentationOnNewline/elvis")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Elvis extends AbstractTypingIndentationTestBase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doNewlineTest, this, testDataFilePath);
}
@TestMetadata("AfterElvis.after.kt")
public void testAfterElvis() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/AfterElvis.after.kt");
}
@TestMetadata("AfterElvis2.after.kt")
public void testAfterElvis2() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/AfterElvis2.after.kt");
}
@TestMetadata("AfterElvisInBinaryExpression.after.kt")
public void testAfterElvisInBinaryExpression() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/AfterElvisInBinaryExpression.after.kt");
}
public void testAllFilesPresentInElvis() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/indentationOnNewline/elvis"), Pattern.compile("^([^\\.]+)\\.after\\.kt.*$"), null, true);
}
@TestMetadata("BeforeElvis.after.kt")
public void testBeforeElvis() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/BeforeElvis.after.kt");
}
@TestMetadata("BeforeElvisInBinaryExpression.after.kt")
public void testBeforeElvisInBinaryExpression() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/BeforeElvisInBinaryExpression.after.kt");
}
}
@TestMetadata("idea/testData/indentationOnNewline/script") @TestMetadata("idea/testData/indentationOnNewline/script")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1076,6 +1114,44 @@ public class TypingIndentationTestBaseGenerated extends AbstractTypingIndentatio
runTest("idea/testData/indentationOnNewline/SettingAlignMultilineParametersInCalls.after.inv.kt"); runTest("idea/testData/indentationOnNewline/SettingAlignMultilineParametersInCalls.after.inv.kt");
} }
@TestMetadata("idea/testData/indentationOnNewline/elvis")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Elvis extends AbstractTypingIndentationTestBase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doNewlineTestWithInvert, this, testDataFilePath);
}
@TestMetadata("AfterElvis.after.inv.kt")
public void testAfterElvis() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/AfterElvis.after.inv.kt");
}
@TestMetadata("AfterElvis2.after.inv.kt")
public void testAfterElvis2() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/AfterElvis2.after.inv.kt");
}
@TestMetadata("AfterElvisInBinaryExpression.after.inv.kt")
public void testAfterElvisInBinaryExpression() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/AfterElvisInBinaryExpression.after.inv.kt");
}
public void testAllFilesPresentInElvis() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/indentationOnNewline/elvis"), Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), null, true);
}
@TestMetadata("BeforeElvis.after.inv.kt")
public void testBeforeElvis() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/BeforeElvis.after.inv.kt");
}
@TestMetadata("BeforeElvisInBinaryExpression.after.inv.kt")
public void testBeforeElvisInBinaryExpression() throws Exception {
runTest("idea/testData/indentationOnNewline/elvis/BeforeElvisInBinaryExpression.after.inv.kt");
}
}
@TestMetadata("idea/testData/indentationOnNewline/script") @TestMetadata("idea/testData/indentationOnNewline/script")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)