From 2547612d54b606858e0232796d7884cd0a3515d2 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Wed, 11 Jul 2018 13:55:54 +0900 Subject: [PATCH] Implement Smart Enter handler for value argument list (KT-18807) #KT-18807 Fixed --- .../idea/editor/KotlinSmartEnterHandler.kt | 6 +- .../fixers/KotlinValueArgumentListFixer.kt | 41 ++++++++++ .../codeInsight/smartEnter/SmartEnterTest.kt | 75 +++++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/editor/fixers/KotlinValueArgumentListFixer.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/editor/KotlinSmartEnterHandler.kt b/idea/src/org/jetbrains/kotlin/idea/editor/KotlinSmartEnterHandler.kt index fce136eff41..8e3b070a430 100644 --- a/idea/src/org/jetbrains/kotlin/idea/editor/KotlinSmartEnterHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/editor/KotlinSmartEnterHandler.kt @@ -50,7 +50,9 @@ class KotlinSmartEnterHandler : SmartEnterProcessorWithFixers() { KotlinClassInitializerFixer(), - KotlinClassBodyFixer() + KotlinClassBodyFixer(), + + KotlinValueArgumentListFixer() ) addEnterProcessors(KotlinPlainEnterProcessor()) @@ -133,6 +135,8 @@ class KotlinSmartEnterHandler : SmartEnterProcessorWithFixers() { } override fun doEnter(atCaret: PsiElement, file: PsiFile?, editor: Editor, modified: Boolean): Boolean { + if (modified && atCaret is KtCallExpression) return true + val block = getControlStatementBlock(editor.caretModel.offset, atCaret) as? KtBlockExpression if (block != null) { val firstElement = block.firstChild?.nextSibling diff --git a/idea/src/org/jetbrains/kotlin/idea/editor/fixers/KotlinValueArgumentListFixer.kt b/idea/src/org/jetbrains/kotlin/idea/editor/fixers/KotlinValueArgumentListFixer.kt new file mode 100644 index 00000000000..707dab31cc8 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/editor/fixers/KotlinValueArgumentListFixer.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.editor.fixers + +import com.intellij.lang.SmartEnterProcessorWithFixers +import com.intellij.openapi.editor.Editor +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiUtilCore +import org.jetbrains.kotlin.idea.editor.KotlinSmartEnterHandler +import org.jetbrains.kotlin.psi.KtValueArgumentList +import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespace + +class KotlinValueArgumentListFixer : SmartEnterProcessorWithFixers.Fixer() { + + override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, element: PsiElement) { + if (element !is KtValueArgumentList || element.rightParenthesis != null) return + val lPar = element.leftParenthesis ?: return + + val lastArgument = element.arguments.lastOrNull() + if (lastArgument != null && PsiUtilCore.hasErrorElementChild(lastArgument)) { + val prev = lastArgument.getPrevSiblingIgnoringWhitespace() ?: lPar + val offset = prev.endOffset + if (prev == lPar) { + editor.document.insertString(offset, ")") + editor.caretModel.moveToOffset(offset) + } else { + editor.document.insertString(offset, " )") + editor.caretModel.moveToOffset(offset + 1) + } + } else { + val offset = element.endOffset + editor.document.insertString(offset, ")") + editor.caretModel.moveToOffset(offset + 1) + } + } + +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/smartEnter/SmartEnterTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/smartEnter/SmartEnterTest.kt index d8d38b2e6c0..69a2b9fd033 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/smartEnter/SmartEnterTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/smartEnter/SmartEnterTest.kt @@ -1405,6 +1405,81 @@ class SmartEnterTest : KotlinLightCodeInsightFixtureTestCase() { """ ) + fun testValueArgumentList1() = doFileTest( + """ + fun foo(i: Int) = 1 + fun test1() { + foo(1 + } + """, + """ + fun foo(i: Int) = 1 + fun test1() { + foo(1) + } + """ + ) + + fun testValueArgumentList2() = doFileTest( + """ + fun foo(i: Int) = 1 + fun test2() { + foo(foo(1 + } + """, + """ + fun foo(i: Int) = 1 + fun test2() { + foo(foo(1)) + } + """ + ) + + fun testValueArgumentList3() = doFileTest( + """ + fun foo(i: Int) = 1 + fun test3() { + foo( + } + """, + """ + fun foo(i: Int) = 1 + fun test3() { + foo() + } + """ + ) + + fun testValueArgumentList4() = doFileTest( + """ + fun foo(i: Int) = 1 + fun test4() { + foo(1, + } + """, + """ + fun foo(i: Int) = 1 + fun test4() { + foo(1, ) + } + """ + ) + + fun testValueArgumentList5() = doFileTest( + """ + class Foo(i: Int) + fun test5() { + Foo(1 + } + """, + """ + class Foo(i: Int) + fun test5() { + Foo(1) + } + """ + ) + fun doFunTest(before: String, after: String) { fun String.withFunContext(): String { val bodyText = "//----\n${this.trimIndent()}\n//----"