Smart enter for fun declaration
#KT-3600 In Progress
This commit is contained in:
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.psi.JetExpression
|
|||||||
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody
|
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody
|
||||||
import org.jetbrains.jet.lang.psi.JetIfExpression
|
import org.jetbrains.jet.lang.psi.JetIfExpression
|
||||||
import org.jetbrains.jet.lang.psi.JetForExpression
|
import org.jetbrains.jet.lang.psi.JetForExpression
|
||||||
|
import org.jetbrains.jet.lang.psi.JetParameter
|
||||||
import com.intellij.psi.tree.TokenSet
|
import com.intellij.psi.tree.TokenSet
|
||||||
import org.jetbrains.jet.JetNodeTypes
|
import org.jetbrains.jet.JetNodeTypes
|
||||||
import org.jetbrains.jet.lang.psi.JetLoopExpression
|
import org.jetbrains.jet.lang.psi.JetLoopExpression
|
||||||
@@ -48,7 +49,10 @@ public class KotlinSmartEnterHandler: SmartEnterProcessorWithFixers() {
|
|||||||
KotlinWhenSubjectCaretFixer(),
|
KotlinWhenSubjectCaretFixer(),
|
||||||
KotlinMissingWhenBodyFixer(),
|
KotlinMissingWhenBodyFixer(),
|
||||||
|
|
||||||
KotlinDoWhileFixer()
|
KotlinDoWhileFixer(),
|
||||||
|
|
||||||
|
KotlinFunctionParametersFixer(),
|
||||||
|
KotlinFunctionDeclarationBodyFixer()
|
||||||
)
|
)
|
||||||
|
|
||||||
addEnterProcessors(KotlinPlainEnterProcessor())
|
addEnterProcessors(KotlinPlainEnterProcessor())
|
||||||
@@ -62,7 +66,9 @@ public class KotlinSmartEnterHandler: SmartEnterProcessorWithFixers() {
|
|||||||
while (atCaret != null) {
|
while (atCaret != null) {
|
||||||
if (atCaret?.isJetStatement() == true) return atCaret
|
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
|
return atCaret
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +100,9 @@ public class KotlinSmartEnterHandler: SmartEnterProcessorWithFixers() {
|
|||||||
val old = settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE
|
val old = settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE
|
||||||
settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = false
|
settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = false
|
||||||
val elt = PsiTreeUtil.getParentOfType(file.findElementAt(caretOffset - 1), javaClass<JetBlockExpression>())
|
val elt = PsiTreeUtil.getParentOfType(file.findElementAt(caretOffset - 1), javaClass<JetBlockExpression>())
|
||||||
reformat(elt)
|
if (elt != null) {
|
||||||
|
reformat(elt)
|
||||||
|
}
|
||||||
settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = old
|
settings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE = old
|
||||||
editor.getCaretModel().moveToOffset(caretOffset - 1)
|
editor.getCaretModel().moveToOffset(caretOffset - 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<KotlinSmartEnterHandler>() {
|
||||||
|
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<JetDeclaration>())
|
||||||
|
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, "{}")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<KotlinSmartEnterHandler>() {
|
||||||
|
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, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -723,6 +723,124 @@ class SmartEnterTest : JetLightCodeInsightFixtureTestCase() {
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun testFunBody() = doFileTest(
|
||||||
|
"""
|
||||||
|
fun test<caret>()
|
||||||
|
"""
|
||||||
|
,
|
||||||
|
"""
|
||||||
|
fun test() {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
fun testFunBody1() = doFileTest(
|
||||||
|
"""
|
||||||
|
fun test<caret>
|
||||||
|
"""
|
||||||
|
,
|
||||||
|
"""
|
||||||
|
fun test() {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
fun testFunBody2() = doFileTest(
|
||||||
|
"""
|
||||||
|
fun (p: Int, s: String<caret>
|
||||||
|
"""
|
||||||
|
,
|
||||||
|
"""
|
||||||
|
fun (p: Int, s: String) {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
fun testFunBody3() = doFileTest(
|
||||||
|
"""
|
||||||
|
trait Some {
|
||||||
|
fun (<caret>p: Int)
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
,
|
||||||
|
"""
|
||||||
|
trait Some {
|
||||||
|
fun (p: Int)
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
fun testFunBody4() = doFileTest(
|
||||||
|
"""
|
||||||
|
class Some {
|
||||||
|
abstract fun (<caret>p: Int)
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
,
|
||||||
|
"""
|
||||||
|
class Some {
|
||||||
|
abstract fun (p: Int)
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
fun testFunBody5() = doFileTest(
|
||||||
|
"""
|
||||||
|
class Some {
|
||||||
|
fun test(<caret>p: Int) = 1
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
,
|
||||||
|
"""
|
||||||
|
class Some {
|
||||||
|
fun test(p: Int) = 1
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
fun testFunBody6() = doFileTest(
|
||||||
|
"""
|
||||||
|
fun test(<caret>p: Int) {
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
,
|
||||||
|
"""
|
||||||
|
fun test(p: Int) {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
fun testFunBody7() = doFileTest(
|
||||||
|
"""
|
||||||
|
trait T
|
||||||
|
fun <U> other() where U: T<caret>
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
trait T
|
||||||
|
fun <U> other() where U : T {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
fun testFunBody8() = doFileTest(
|
||||||
|
"""
|
||||||
|
fun Int.other<caret>
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
fun Int.other() {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
fun doFunTest(before: String, after: String) {
|
fun doFunTest(before: String, after: String) {
|
||||||
fun String.withFunContext(): String {
|
fun String.withFunContext(): String {
|
||||||
val bodyText = "//----${this.trimIndent()}//----"
|
val bodyText = "//----${this.trimIndent()}//----"
|
||||||
@@ -734,6 +852,10 @@ class SmartEnterTest : JetLightCodeInsightFixtureTestCase() {
|
|||||||
doTest(before.withFunContext(), after.withFunContext())
|
doTest(before.withFunContext(), after.withFunContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun doFileTest(before: String, after: String) {
|
||||||
|
doTest(before.trimIndent().removeFirstEmptyLines(), after.trimIndent().removeFirstEmptyLines())
|
||||||
|
}
|
||||||
|
|
||||||
fun doTest(before: String, after: String) {
|
fun doTest(before: String, after: String) {
|
||||||
myFixture.configureByText(JetFileType.INSTANCE, before)
|
myFixture.configureByText(JetFileType.INSTANCE, before)
|
||||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_COMPLETE_STATEMENT)
|
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_COMPLETE_STATEMENT)
|
||||||
@@ -741,4 +863,6 @@ class SmartEnterTest : JetLightCodeInsightFixtureTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getProjectDescriptor(): LightProjectDescriptor = LightCodeInsightFixtureTestCase.JAVA_LATEST
|
override fun getProjectDescriptor(): LightProjectDescriptor = LightCodeInsightFixtureTestCase.JAVA_LATEST
|
||||||
|
|
||||||
|
private fun String.removeFirstEmptyLines() = this.split("\n").dropWhile { it.isEmpty() }.joinToString(separator = "\n")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user