mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
207 lines
8.1 KiB
Kotlin
207 lines
8.1 KiB
Kotlin
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
|
package com.intellij.codeInsight.hints
|
|
|
|
import com.intellij.codeInsight.hints.presentation.RecursivelyUpdatingRootPresentation
|
|
import com.intellij.codeInsight.hints.presentation.RootInlayPresentation
|
|
import com.intellij.codeInsight.hints.presentation.SpacePresentation
|
|
import com.intellij.lang.Language
|
|
import com.intellij.openapi.actionSystem.ex.ActionUtil
|
|
import com.intellij.openapi.editor.Editor
|
|
import com.intellij.openapi.editor.Inlay
|
|
import com.intellij.openapi.progress.DumbProgressIndicator
|
|
import com.intellij.psi.PsiElement
|
|
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
|
|
class InlayPassTest : BasePlatformTestCase() {
|
|
private val noSettings = SettingsKey<NoSettings>("no")
|
|
private lateinit var sharedSink: InlayHintsSinkImpl
|
|
override fun setUp() {
|
|
super.setUp()
|
|
myFixture.configureByText("file.java", "class A{ }")
|
|
sharedSink = InlayHintsSinkImpl(myFixture.editor)
|
|
}
|
|
|
|
fun testTurnedOffHintsDisappear() {
|
|
createPass(listOf(createOneOffCollector {
|
|
it.addBlockElement(0, true, TestRootPresentation(0), null)
|
|
it.addInlineElement(5, TestRootPresentation(1), null)
|
|
})).collectAndApply()
|
|
assertEquals(2, allHintsCount)
|
|
createPass(emptyList()).collectAndApply()
|
|
assertEquals(0, allHintsCount)
|
|
}
|
|
|
|
fun testNonProviderMangedInlayStayUntouched() {
|
|
val presentation = HorizontalConstrainedPresentation(TestRootPresentation(), null)
|
|
@Suppress("UNCHECKED_CAST")
|
|
inlayModel.addInlineElement(3, InlineInlayRenderer(listOf(presentation as HorizontalConstrainedPresentation<in Any>)))
|
|
createPass(emptyList()).collectAndApply()
|
|
assertEquals(1, inlineElements.size)
|
|
val renderer = inlineElements.first().renderer as InlineInlayRenderer
|
|
assertEquals(presentation, renderer.getConstrainedPresentations().first())
|
|
}
|
|
|
|
fun testInlaysFromMultipleCollectorsMerged() {
|
|
createPass(listOf(
|
|
createOneOffCollector {
|
|
it.addInlineElement(1, TestRootPresentation(1), null)
|
|
},
|
|
createOneOffCollector {
|
|
it.addInlineElement(2, TestRootPresentation(2), null)
|
|
}
|
|
)).collectAndApply()
|
|
val inlays = inlineElements
|
|
assertEquals(2, inlays.size)
|
|
assertEquals(1, extractContent(inlays, 0))
|
|
assertEquals(2, extractContent(inlays, 1))
|
|
}
|
|
|
|
fun testInlaysRespectHorizontalConstraints() {
|
|
createPass(listOf(createOneOffCollector {
|
|
it.addInlineElement(1, true, TestRootPresentation(1), true)
|
|
it.addInlineElement(2, true, TestRootPresentation(2), false)
|
|
it.addInlineElement(3, false, TestRootPresentation(3), false)
|
|
})).collectAndApply()
|
|
var inlays = inlineElements
|
|
assertEquals(2, inlays.size)
|
|
assertTrue(inlays[0].isRelatedToPrecedingText)
|
|
assertFalse(inlays[1].isRelatedToPrecedingText)
|
|
inlays = afterLineEndElements
|
|
assertEquals(1, inlays.size)
|
|
}
|
|
|
|
fun testInlaysAtSameOffsetWithMatchingRelatesToPrecedingText() {
|
|
createPass(listOf(createOneOffCollector {
|
|
it.addInlineElement(1, true, TestRootPresentation(1), false)
|
|
it.addInlineElement(1, true, TestRootPresentation(2), false)
|
|
})).collectAndApply()
|
|
val inlays = inlineElements
|
|
assertEquals(1, inlays.size)
|
|
assertTrue(inlays[0].isRelatedToPrecedingText)
|
|
}
|
|
|
|
fun testInlaysAtSameOffsetWithDifferentRelatesToPrecedingTextDefaultToFalse() {
|
|
createPass(listOf(createOneOffCollector {
|
|
it.addInlineElement(1, true, TestRootPresentation(1), false)
|
|
it.addInlineElement(1, false, TestRootPresentation(2), false)
|
|
})).collectAndApply()
|
|
val inlays = inlineElements
|
|
assertEquals(1, inlays.size)
|
|
assertFalse(inlays[0].isRelatedToPrecedingText)
|
|
}
|
|
|
|
fun testPresentationUpdated() {
|
|
createPass(listOf(
|
|
createOneOffCollector {
|
|
it.addInlineElement(1, TestRootPresentation(1), null)
|
|
}
|
|
)).collectAndApply()
|
|
assertEquals(1, inlineElements.size)
|
|
assertEquals(1, extractContent(inlineElements, 0))
|
|
|
|
createPass(listOf(
|
|
createOneOffCollector {
|
|
it.addInlineElement(1, TestRootPresentation(3), null)
|
|
}
|
|
)).collectAndApply()
|
|
assertEquals(1, inlineElements.size)
|
|
assertEquals(3, extractContent(inlineElements, 0))
|
|
}
|
|
|
|
fun testNoPresentationRecreatedWhenNothingChanges() {
|
|
val initilalRoot = RecursivelyUpdatingRootPresentation(SpacePresentation(10, 10))
|
|
applyPassWithCollectorOfSingleElement(initilalRoot)
|
|
applyPassWithCollectorOfSingleElement(RecursivelyUpdatingRootPresentation(SpacePresentation(10, 10)))
|
|
val root = expectSingleHorizontalPresentation()
|
|
assertSame(initilalRoot, root)
|
|
}
|
|
|
|
fun testPresentationIsTheSameButContentUpdated() {
|
|
val initialContent = SpacePresentation(10, 10)
|
|
val initilalRoot = RecursivelyUpdatingRootPresentation(initialContent)
|
|
applyPassWithCollectorOfSingleElement(initilalRoot)
|
|
applyPassWithCollectorOfSingleElement(RecursivelyUpdatingRootPresentation(SpacePresentation(5, 5)))
|
|
val root = expectSingleHorizontalPresentation()
|
|
assertSame(initilalRoot, root)
|
|
assertNotSame(initialContent, root.content)
|
|
}
|
|
|
|
fun testUpdateWithNonRecursiveRootPresentation() {
|
|
applyPassWithCollectorOfSingleElement(RecursivelyUpdatingRootPresentation(SpacePresentation(10, 10)))
|
|
val rootAfter = TestRootPresentation(1)
|
|
applyPassWithCollectorOfSingleElement(rootAfter)
|
|
val presentation = expectSingleHorizontalPresentation()
|
|
assertSame(rootAfter, presentation)
|
|
}
|
|
|
|
private fun expectSingleHorizontalPresentation(): RootInlayPresentation<out Any> {
|
|
assertEquals(1, inlineElements.size)
|
|
val inlay = inlineElements.first()
|
|
val renderer = inlay.renderer as InlineInlayRenderer
|
|
val presentations = renderer.getConstrainedPresentations()
|
|
assertEquals(1, presentations.size)
|
|
val constrainedPresentation = presentations.first()
|
|
return constrainedPresentation.root
|
|
}
|
|
|
|
|
|
private fun <T : Any> applyPassWithCollectorOfSingleElement(presentation: RootInlayPresentation<T>) {
|
|
createPass(listOf(
|
|
createOneOffCollector {
|
|
it.addInlineElement(1, presentation, null)
|
|
}
|
|
)).collectAndApply()
|
|
}
|
|
|
|
private fun extractContent(inlays: List<Inlay<*>>, index: Int): Int {
|
|
val renderer = inlays[index].renderer as InlineInlayRenderer
|
|
return renderer.getConstrainedPresentations().first().root.content as Int
|
|
}
|
|
|
|
private fun createOneOffCollector(collector: (InlayHintsSink) -> Unit): CollectorWithSettings<NoSettings> {
|
|
val firstTime = AtomicBoolean(true)
|
|
val collectorLambda: (PsiElement, Editor, InlayHintsSink) -> Boolean = { _, _, sink ->
|
|
if (firstTime.compareAndSet(true, false)) {
|
|
collector(sink)
|
|
}
|
|
false
|
|
}
|
|
return createCollector(collectorLambda)
|
|
}
|
|
|
|
private fun createCollector(collector: (PsiElement, Editor, InlayHintsSink) -> Boolean): CollectorWithSettings<NoSettings> {
|
|
return CollectorWithSettings(object : InlayHintsCollector {
|
|
override fun collect(element: PsiElement, editor: Editor, sink: InlayHintsSink): Boolean {
|
|
return collector(element, editor, sink)
|
|
}
|
|
}, noSettings, Language.ANY, sharedSink)
|
|
}
|
|
|
|
private fun createPass(collectors: List<CollectorWithSettings<*>>): InlayHintsPass {
|
|
val visibleRange = myFixture.editor.calculateVisibleRange()
|
|
return ActionUtil.underModalProgress(project, "") { InlayHintsPass(myFixture.file, collectors, myFixture.editor, visibleRange, sharedSink) }
|
|
}
|
|
|
|
private fun InlayHintsPass.collectAndApply() {
|
|
val dumbProgressIndicator = DumbProgressIndicator()
|
|
doCollectInformation(dumbProgressIndicator)
|
|
applyInformationToEditor()
|
|
sharedSink.reset()
|
|
}
|
|
|
|
private val inlayModel
|
|
get() = myFixture.editor.inlayModel
|
|
|
|
private val blockElements: List<Inlay<*>>
|
|
get() = inlayModel.getBlockElementsInRange(0, myFixture.file.textRange.endOffset)
|
|
|
|
private val inlineElements: List<Inlay<*>>
|
|
get() = inlayModel.getInlineElementsInRange(0, myFixture.file.textRange.endOffset)
|
|
|
|
private val afterLineEndElements: List<Inlay<*>>
|
|
get() = inlayModel.getAfterLineEndElementsInRange(0, myFixture.file.textRange.endOffset)
|
|
|
|
private val allHintsCount: Int
|
|
get() = inlineElements.size + blockElements.size
|
|
} |