Implement display of code construct start for Kotlin

#KT-20470 Fixed
This commit is contained in:
Dmitry Jemerov
2018-01-03 16:37:21 +01:00
parent 968e6ecde4
commit fd01351740
4 changed files with 98 additions and 1 deletions
+6
View File
@@ -774,6 +774,12 @@
<gotoRelatedProvider implementation="org.jetbrains.kotlin.idea.goto.KotlinExpectOrActualGotoRelatedProvider"/> <gotoRelatedProvider implementation="org.jetbrains.kotlin.idea.goto.KotlinExpectOrActualGotoRelatedProvider"/>
<declarationRangeHandler key="org.jetbrains.kotlin.psi.KtClassOrObject"
implementationClass="org.jetbrains.kotlin.idea.codeInsight.KotlinClassDeclarationRangeHandler"/>
<declarationRangeHandler key="org.jetbrains.kotlin.psi.KtDeclarationWithBody"
implementationClass="org.jetbrains.kotlin.idea.codeInsight.KotlinFunDeclarationRangeHandler"/>
<intentionAction> <intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisIntention</className> <className>org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisIntention</className>
<category>Kotlin</category> <category>Kotlin</category>
@@ -5,11 +5,14 @@
package org.jetbrains.kotlin.idea package org.jetbrains.kotlin.idea
import com.intellij.codeInsight.hint.DeclarationRangeUtil
import com.intellij.lang.BracePair import com.intellij.lang.BracePair
import com.intellij.lang.PairedBraceMatcher import com.intellij.lang.PairedBraceMatcher
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtClassBody
class KotlinPairMatcher : PairedBraceMatcher { class KotlinPairMatcher : PairedBraceMatcher {
private val pairs = arrayOf( private val pairs = arrayOf(
@@ -37,6 +40,12 @@ class KotlinPairMatcher : PairedBraceMatcher {
} }
override fun getCodeConstructStart(file: PsiFile, openingBraceOffset: Int): Int { override fun getCodeConstructStart(file: PsiFile, openingBraceOffset: Int): Int {
return openingBraceOffset val element = file.findElementAt(openingBraceOffset)
if (element == null || element is PsiFile) return openingBraceOffset
val parent = element.parent
return when (parent) {
is KtClassBody, is KtBlockExpression -> DeclarationRangeUtil.getDeclarationRange(parent.parent).startOffset
else -> openingBraceOffset
}
} }
} }
@@ -0,0 +1,41 @@
/*
* Copyright 2000-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.codeInsight
import com.intellij.codeInsight.hint.DeclarationRangeHandler
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiNameIdentifierOwner
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.psi.psiUtil.startOffset
class KotlinClassDeclarationRangeHandler : DeclarationRangeHandler<KtClassOrObject> {
override fun getDeclarationRange(container: KtClassOrObject): TextRange {
val body = container.getBody() ?: return container.textRange
val prevSibling = body.getPrevSiblingIgnoringWhitespaceAndComments()
return TextRange(
container.getDeclarationKeyword()?.startOffset ?: container.startOffset,
prevSibling?.endOffset ?: body.startOffset
)
}
}
class KotlinFunDeclarationRangeHandler : DeclarationRangeHandler<KtDeclarationWithBody> {
override fun getDeclarationRange(container: KtDeclarationWithBody): TextRange {
val body = container.bodyExpression ?: return container.textRange
val prevSibling = body.getPrevSiblingIgnoringWhitespaceAndComments()
return TextRange(
(container as? KtNamedFunction)?.funKeyword?.startOffset
?: (container as? PsiNameIdentifierOwner)?.nameIdentifier?.startOffset
?: container.modifierList?.startOffset
?: container.startOffset,
prevSibling?.endOffset ?: body.startOffset
)
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2000-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.codeInsight
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.KotlinPairMatcher
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
import java.lang.IllegalArgumentException
class KotlinPairMatcherTest : KotlinLightCodeInsightFixtureTestCase() {
override fun getProjectDescriptor(): KotlinLightProjectDescriptor = KotlinLightProjectDescriptor.INSTANCE
private fun doTest(testData: String) {
var docText = testData
val startPos = docText.indexOf("<start>")
if (startPos == -1) {
throw IllegalArgumentException("<start> marker not found in testdata")
}
docText = docText.replace("<start>", "")
val bracePos = docText.indexOf("<brace>")
if (bracePos == -1) {
throw IllegalArgumentException("<brace> marker not found in testdata")
}
docText = docText.replace("<brace>", "")
myFixture.configureByText(KotlinFileType.INSTANCE, docText)
val pos = KotlinPairMatcher().getCodeConstructStart(myFixture.file, bracePos)
assertEquals(startPos, pos)
}
fun testClass() {
doTest("/* Doc comment */ <start>class Foo : Bar, Baz <brace>{ fun xyzzy() { } }")
}
fun testFun() {
doTest("/* Doc comment */ <start>fun xyzzy(x: Int, y: String): Any <brace>{ }")
}
}