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"/>
<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>
<className>org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisIntention</className>
<category>Kotlin</category>
@@ -5,11 +5,14 @@
package org.jetbrains.kotlin.idea
import com.intellij.codeInsight.hint.DeclarationRangeUtil
import com.intellij.lang.BracePair
import com.intellij.lang.PairedBraceMatcher
import com.intellij.psi.PsiFile
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtClassBody
class KotlinPairMatcher : PairedBraceMatcher {
private val pairs = arrayOf(
@@ -37,6 +40,12 @@ class KotlinPairMatcher : PairedBraceMatcher {
}
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>{ }")
}
}