Create KotlinLineIndentProvider and delegate it to formatter

#KT-22211
This commit is contained in:
Dmitry Gridin
2020-05-19 17:06:43 +07:00
parent 0f10faabbf
commit 9d98240272
10 changed files with 128 additions and 7 deletions
@@ -268,6 +268,16 @@ public class PerformanceTypingIndentationTestGenerated extends AbstractPerforman
runTest("idea/testData/indentationOnNewline/ReturnContinue.kt");
}
@TestMetadata("Semicolon.kt")
public void testSemicolon() throws Exception {
runTest("idea/testData/indentationOnNewline/Semicolon.kt");
}
@TestMetadata("Semicolon2.kt")
public void testSemicolon2() throws Exception {
runTest("idea/testData/indentationOnNewline/Semicolon2.kt");
}
@TestMetadata("SettingAlignMultilineParametersInCalls.kt")
public void testSettingAlignMultilineParametersInCalls() throws Exception {
runTest("idea/testData/indentationOnNewline/SettingAlignMultilineParametersInCalls.kt");
+1
View File
@@ -15,6 +15,7 @@
factoryClass="org.jetbrains.kotlin.idea.structureView.KtClsStructureViewBuilderProvider"/>
<lang.formatter language="kotlin" implementationClass="org.jetbrains.kotlin.idea.formatter.KotlinFormattingModelBuilder"/>
<lineIndentProvider implementation="org.jetbrains.kotlin.idea.formatter.KotlinLineIndentProvider"/>
<preFormatProcessor implementation="org.jetbrains.kotlin.idea.formatter.KotlinPreFormatProcessor"/>
<postFormatProcessor implementation="org.jetbrains.kotlin.idea.formatter.TrailingCommaPostFormatProcessor"/>
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.lang.Language
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.codeStyle.lineIndent.LineIndentProvider
import com.intellij.psi.impl.source.codeStyle.lineIndent.FormatterBasedLineIndentProvider
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.idea.KotlinLanguage
class KotlinLineIndentProvider : LineIndentProvider {
private val formatterBasedProvider = FormatterBasedLineIndentProvider()
override fun getLineIndent(project: Project, editor: Editor, language: Language?, offset: Int): String? {
val lineIndent = formatterBasedProvider.getLineIndent(project, editor, language, offset)
return if (useFormatter) lineIndent else lineIndent
}
override fun isSuitableFor(language: Language?): Boolean = language?.isKindOf(KotlinLanguage.INSTANCE) == true
companion object {
@get:TestOnly
@set:TestOnly
internal var useFormatter: Boolean = false
}
}
@@ -0,0 +1,7 @@
fun test(i: Int) {
test(
<caret>
)
}
// SET_FALSE: CONTINUATION_INDENT_IN_ARGUMENT_LISTS
+4
View File
@@ -0,0 +1,4 @@
fun test() {
val a = 44;
<caret>
}
+3
View File
@@ -0,0 +1,3 @@
fun test() {
val a = 44;<caret>
}
@@ -0,0 +1,4 @@
fun test() {
val a = 44;
<caret>val b = 42;
}
+3
View File
@@ -0,0 +1,3 @@
fun test() {
val a = 44;<caret> val b = 42;
}
@@ -5,13 +5,22 @@
package org.jetbrains.kotlin.formatter
import com.intellij.application.options.CodeStyle
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.codeStyle.lineIndent.LineIndentProvider
import com.intellij.testFramework.EditorTestUtil
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.formatter.KotlinLineIndentProvider
import org.jetbrains.kotlin.idea.test.KotlinLightPlatformCodeInsightTestCase
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.testFramework.runWriteAction
import org.junit.Assert
import java.io.File
abstract class AbstractTypingIndentationTestBase : KotlinLightPlatformCodeInsightTestCase() {
private val customLineIndentProvider: LineIndentProvider = KotlinLineIndentProvider()
fun doNewlineTestWithInvert(afterInvFilePath: String) {
doNewlineTest(afterInvFilePath, true)
}
@@ -22,6 +31,11 @@ abstract class AbstractTypingIndentationTestBase : KotlinLightPlatformCodeInsigh
val testFileExtension = afterFilePath.substring(afterFilePath.lastIndexOf("."))
val originFilePath = testFileName + testFileExtension
val originalFileText = FileUtil.loadFile(File(originFilePath), true)
val withoutCustomLineIndentProvider = InTextDirectivesUtils.findStringWithPrefixes(
originalFileText,
"// WITHOUT_CUSTOM_LINE_INDENT_PROVIDER"
) != null
try {
val configurator = FormatSettingsUtil.createConfigurator(originalFileText, CodeStyle.getSettings(project))
if (!inverted) {
@@ -30,19 +44,48 @@ abstract class AbstractTypingIndentationTestBase : KotlinLightPlatformCodeInsigh
configurator.configureInvertedSettings()
}
doNewlineTest(originFilePath, afterFilePath)
doNewlineTest(originFilePath, afterFilePath, withoutCustomLineIndentProvider)
} finally {
CodeStyle.getSettings(project).clearCodeStyleSettings()
}
}
private fun doNewlineTest(beforeFilePath: String, afterFilePath: String) {
private fun doNewlineTest(beforeFilePath: String, afterFilePath: String, withoutCustomLineIndentProvider: Boolean) {
KotlinLineIndentProvider.useFormatter = true
typeAndCheck(beforeFilePath, afterFilePath, "with FormatterBasedLineIndentProvider")
KotlinLineIndentProvider.useFormatter = false
if (!withoutCustomLineIndentProvider) {
typeAndCheck(beforeFilePath, afterFilePath, "with ${customLineIndentProvider.javaClass.simpleName}")
}
configureByFile(beforeFilePath)
type('\n')
val caretModel = editor.caretModel
val offset = caretModel.offset
val actualTextWithCaret = StringBuilder(editor.document.text).insert(offset, EditorTestUtil.CARET_TAG).toString()
KotlinTestUtils.assertEqualsToFile(File(afterFilePath), actualTextWithCaret)
assertCustomIndentExist(withoutCustomLineIndentProvider)
}
private fun assertCustomIndentExist(withoutCustomLineIndentProvider: Boolean) {
val offset = editor.caretModel.offset
runWriteAction {
editor.document.insertString(offset, "\n")
}
val customIndent = customLineIndentProvider.getLineIndent(project, editor, KotlinLanguage.INSTANCE, offset + 1)
val condition = customIndent == null
Assert.assertTrue(
"${if (withoutCustomLineIndentProvider) "Remove" else "Add"} \"// WITHOUT_CUSTOM_LINE_INDENT_PROVIDER\" or fix ${customLineIndentProvider.javaClass.simpleName}",
if (withoutCustomLineIndentProvider) condition else !condition
)
}
private fun typeAndCheck(beforeFilePath: String, afterFilePath: String, errorMessage: String) {
configureByFile(beforeFilePath)
executeAction(IdeActions.ACTION_EDITOR_ENTER)
val actualTextWithCaret = StringBuilder(editor.document.text).insert(
editor.caretModel.offset,
EditorTestUtil.CARET_TAG
).toString()
KotlinTestUtils.assertEqualsToFile(errorMessage, File(afterFilePath), actualTextWithCaret)
}
override fun getTestDataPath(): String = ""
@@ -270,6 +270,16 @@ public class TypingIndentationTestBaseGenerated extends AbstractTypingIndentatio
runTest("idea/testData/indentationOnNewline/ReturnContinue.after.kt");
}
@TestMetadata("Semicolon.after.kt")
public void testSemicolon() throws Exception {
runTest("idea/testData/indentationOnNewline/Semicolon.after.kt");
}
@TestMetadata("Semicolon2.after.kt")
public void testSemicolon2() throws Exception {
runTest("idea/testData/indentationOnNewline/Semicolon2.after.kt");
}
@TestMetadata("SettingAlignMultilineParametersInCalls.after.kt")
public void testSettingAlignMultilineParametersInCalls() throws Exception {
runTest("idea/testData/indentationOnNewline/SettingAlignMultilineParametersInCalls.after.kt");
@@ -336,6 +346,11 @@ public class TypingIndentationTestBaseGenerated extends AbstractTypingIndentatio
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/indentationOnNewline"), Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), null, true);
}
@TestMetadata("ArgumentListNormalIndent.after.inv.kt")
public void testArgumentListNormalIndent() throws Exception {
runTest("idea/testData/indentationOnNewline/ArgumentListNormalIndent.after.inv.kt");
}
@TestMetadata("AssignmentAfterEq.after.inv.kt")
public void testAssignmentAfterEq() throws Exception {
runTest("idea/testData/indentationOnNewline/AssignmentAfterEq.after.inv.kt");