diff --git a/idea/src/org/jetbrains/jet/plugin/editor/KotlinSmartEnterHandler.kt b/idea/src/org/jetbrains/jet/plugin/editor/KotlinSmartEnterHandler.kt index d8f24a8d526..f3232244132 100644 --- a/idea/src/org/jetbrains/jet/plugin/editor/KotlinSmartEnterHandler.kt +++ b/idea/src/org/jetbrains/jet/plugin/editor/KotlinSmartEnterHandler.kt @@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.psi.JetExpression import org.jetbrains.jet.lang.psi.JetDeclarationWithBody import org.jetbrains.jet.lang.psi.JetIfExpression import org.jetbrains.jet.lang.psi.JetForExpression +import org.jetbrains.jet.lang.psi.JetParameter import com.intellij.psi.tree.TokenSet import org.jetbrains.jet.JetNodeTypes import org.jetbrains.jet.lang.psi.JetLoopExpression @@ -48,7 +49,10 @@ public class KotlinSmartEnterHandler: SmartEnterProcessorWithFixers() { KotlinWhenSubjectCaretFixer(), KotlinMissingWhenBodyFixer(), - KotlinDoWhileFixer() + KotlinDoWhileFixer(), + + KotlinFunctionParametersFixer(), + KotlinFunctionDeclarationBodyFixer() ) addEnterProcessors(KotlinPlainEnterProcessor()) @@ -62,7 +66,9 @@ public class KotlinSmartEnterHandler: SmartEnterProcessorWithFixers() { while (atCaret != null) { if (atCaret?.isJetStatement() == true) return atCaret - if (atCaret is JetDeclaration && (atCaret?.getParent() !is JetForExpression)) { + if (atCaret is JetDeclaration && + atCaret !is JetParameter && + (atCaret?.getParent() !is JetForExpression)) { return atCaret } @@ -94,7 +100,9 @@ public class KotlinSmartEnterHandler: SmartEnterProcessorWithFixers() { val old = settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = false val elt = PsiTreeUtil.getParentOfType(file.findElementAt(caretOffset - 1), javaClass()) - reformat(elt) + if (elt != null) { + reformat(elt) + } settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = old editor.getCaretModel().moveToOffset(caretOffset - 1) } diff --git a/idea/src/org/jetbrains/jet/plugin/editor/fixers/KotlinFunctionDeclarationBodyFixer.kt b/idea/src/org/jetbrains/jet/plugin/editor/fixers/KotlinFunctionDeclarationBodyFixer.kt new file mode 100644 index 00000000000..c6845d9c096 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/editor/fixers/KotlinFunctionDeclarationBodyFixer.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.editor.fixers + +import com.intellij.lang.SmartEnterProcessorWithFixers +import com.intellij.openapi.editor.Editor +import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.jet.lang.psi.JetDeclaration +import org.jetbrains.jet.lang.psi.JetFunction +import org.jetbrains.jet.lang.psi.JetClassOrObject +import org.jetbrains.jet.lang.psi.JetPsiUtil +import org.jetbrains.jet.lexer.JetTokens +import org.jetbrains.jet.lang.psi.JetNamedFunction + + +public class KotlinFunctionDeclarationBodyFixer : SmartEnterProcessorWithFixers.Fixer() { + override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, psiElement: PsiElement) { + if (psiElement !is JetNamedFunction) return + if (psiElement.getBodyExpression() != null|| psiElement.getEqualsToken() != null) return + + val parentDeclaration = PsiTreeUtil.getParentOfType(psiElement, javaClass()) + if (parentDeclaration is JetClassOrObject) { + if (JetPsiUtil.isTrait(parentDeclaration) || psiElement.hasModifier(JetTokens.ABSTRACT_KEYWORD)) { + return + } + } + + val doc = editor.getDocument() + var endOffset = psiElement.range.end + + if (psiElement.getText()?.last() == ';') { + doc.deleteString(endOffset - 1, endOffset) + endOffset-- + } + + doc.insertString(endOffset, "{}") + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/editor/fixers/KotlinFunctionParametersFixer.kt b/idea/src/org/jetbrains/jet/plugin/editor/fixers/KotlinFunctionParametersFixer.kt new file mode 100644 index 00000000000..a5a042715f9 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/editor/fixers/KotlinFunctionParametersFixer.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.editor.fixers + +import com.intellij.lang.SmartEnterProcessorWithFixers +import com.intellij.psi.PsiElement +import org.jetbrains.jet.plugin.editor.KotlinSmartEnterHandler +import com.intellij.openapi.editor.Editor +import org.jetbrains.jet.lang.psi.JetNamedFunction + + +public class KotlinFunctionParametersFixer : SmartEnterProcessorWithFixers.Fixer() { + override fun apply(editor: Editor, processor: KotlinSmartEnterHandler, psiElement: PsiElement) { + if (psiElement !is JetNamedFunction) return; + + val parameterList = psiElement.getValueParameterList() + if (parameterList == null) { + val identifier = psiElement.getNameIdentifier() + if (identifier == null) return + + // Insert () after name or after type parameters list when it placed after name + val offset = Math.max(identifier.range.end, psiElement.getTypeParameterList()?.range?.end ?: psiElement.range.start) + editor.getDocument().insertString(offset, "()") + processor.registerUnresolvedError(offset + 1) + } + else { + val rParen = parameterList.getLastChild() + if (rParen == null) return + + if (")" != rParen.getText()) { + val params = parameterList.getParameters() + val offset = if (params.isEmpty()) parameterList.range.start + 1 else params.last().range.end + editor.getDocument().insertString(offset, ")") + } + } + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/codeInsight/smartEnter/SmartEnterTest.kt b/idea/tests/org/jetbrains/jet/plugin/codeInsight/smartEnter/SmartEnterTest.kt index 60788277e4a..f2ed2b6f204 100644 --- a/idea/tests/org/jetbrains/jet/plugin/codeInsight/smartEnter/SmartEnterTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/codeInsight/smartEnter/SmartEnterTest.kt @@ -723,6 +723,124 @@ class SmartEnterTest : JetLightCodeInsightFixtureTestCase() { """ ) + fun testFunBody() = doFileTest( + """ + fun test() + """ + , + """ + fun test() { + + } + """ + ) + + fun testFunBody1() = doFileTest( + """ + fun test + """ + , + """ + fun test() { + + } + """ + ) + + fun testFunBody2() = doFileTest( + """ + fun (p: Int, s: String + """ + , + """ + fun (p: Int, s: String) { + + } + """ + ) + + fun testFunBody3() = doFileTest( + """ + trait Some { + fun (p: Int) + } + """ + , + """ + trait Some { + fun (p: Int) + + } + """ + ) + + fun testFunBody4() = doFileTest( + """ + class Some { + abstract fun (p: Int) + } + """ + , + """ + class Some { + abstract fun (p: Int) + + } + """ + ) + + fun testFunBody5() = doFileTest( + """ + class Some { + fun test(p: Int) = 1 + } + """ + , + """ + class Some { + fun test(p: Int) = 1 + + } + """ + ) + + fun testFunBody6() = doFileTest( + """ + fun test(p: Int) { + } + """ + , + """ + fun test(p: Int) { + + } + """ + ) + + fun testFunBody7() = doFileTest( + """ + trait T + fun other() where U: T + """, + """ + trait T + fun other() where U : T { + + } + """ + ) + + fun testFunBody8() = doFileTest( + """ + fun Int.other + """, + """ + fun Int.other() { + + } + """ + ) + fun doFunTest(before: String, after: String) { fun String.withFunContext(): String { val bodyText = "//----${this.trimIndent()}//----" @@ -734,6 +852,10 @@ class SmartEnterTest : JetLightCodeInsightFixtureTestCase() { doTest(before.withFunContext(), after.withFunContext()) } + fun doFileTest(before: String, after: String) { + doTest(before.trimIndent().removeFirstEmptyLines(), after.trimIndent().removeFirstEmptyLines()) + } + fun doTest(before: String, after: String) { myFixture.configureByText(JetFileType.INSTANCE, before) myFixture.performEditorAction(IdeActions.ACTION_EDITOR_COMPLETE_STATEMENT) @@ -741,4 +863,6 @@ class SmartEnterTest : JetLightCodeInsightFixtureTestCase() { } override fun getProjectDescriptor(): LightProjectDescriptor = LightCodeInsightFixtureTestCase.JAVA_LATEST + + private fun String.removeFirstEmptyLines() = this.split("\n").dropWhile { it.isEmpty() }.joinToString(separator = "\n") }