[refactoring] KotlinAbstractHintsProvider: move InlayPresentation computation to companion object

This commit enables to reuse `InlayPresentation` computation logic for clases which don't
inherit from `KotlinAbstractHintsProvider`. I will use this new possibility in a next commit

relates to KTIJ-5665

GitOrigin-RevId: bc5d2cd214cddcc4984b87a50c335f9eb7f3d4ee
This commit is contained in:
Nikita Bobko
2021-07-13 16:18:34 +00:00
committed by intellij-monorepo-bot
parent c0d212d2be
commit aa2d1c546f
@@ -11,6 +11,7 @@ import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.KotlinLanguage
@Suppress("UnstableApiUsage")
abstract class KotlinAbstractHintsProvider<T : Any> : InlayHintsProvider<T> {
@@ -29,83 +30,89 @@ abstract class KotlinAbstractHintsProvider<T : Any> : InlayHintsProvider<T> {
val f = factory
resolved.provideHintDetails(element)
.map { convert(it, f, editor.project ?: element.project) }
.map {
PresentationAndSettings(
getInlayPresentationForInlayInfoDetails(it, f, editor.project ?: element.project, this@KotlinAbstractHintsProvider),
it.inlayInfo.offset,
it.inlayInfo.relatesToPrecedingText
)
}
.forEach { p ->
sink.addInlineElement(p.offset, p.relatesToPrecedingText, p.presentation, hintsArePlacedAtTheEndOfLine)
}
return true
}
}
}
private fun convert(
infoDetails: InlayInfoDetails,
f: PresentationFactory, project: Project
): PresentationAndSettings {
val inlayInfo = infoDetails.inlayInfo
val details = mergeAdjacentTextInlayInfoDetails(infoDetails.details)
val basePresentation = when (details.size) {
1 -> convert(details.first(), f, project)
else -> f.seq(*(details.map { convert(it, f, project) }.toTypedArray()))
}
val roundedPresentation = f.roundWithBackground(basePresentation)
val finalPresentation = InsetPresentation(
MenuOnClickPresentation(roundedPresentation, project) {
val provider = this@KotlinAbstractHintsProvider
listOf(
InlayProviderDisablingAction(provider.name, file.language, project, provider.key),
ShowInlayHintsSettings()
)
}, left = 1
)
return PresentationAndSettings(finalPresentation, inlayInfo.offset, inlayInfo.relatesToPrecedingText)
companion object {
private fun getInlayPresentationForInlayInfoDetails(
infoDetails: InlayInfoDetails,
factory: PresentationFactory,
project: Project,
provider: InlayHintsProvider<*>
): InlayPresentation {
val inlayInfo = infoDetails.inlayInfo
val details = mergeAdjacentTextInlayInfoDetails(infoDetails.details)
val basePresentation = when (details.size) {
1 -> getInlayPresentationForInlayInfoDetail(details.first(), factory, project)
else -> factory.seq(*(details.map { getInlayPresentationForInlayInfoDetail(it, factory, project) }.toTypedArray()))
}
val roundedPresentation = factory.roundWithBackground(basePresentation)
return InsetPresentation(
MenuOnClickPresentation(roundedPresentation, project) {
listOf(
InlayProviderDisablingAction(provider.name, KotlinLanguage.INSTANCE, project, provider.key),
ShowInlayHintsSettings()
)
}, left = 1
)
}
private fun mergeAdjacentTextInlayInfoDetails(details: List<InlayInfoDetail>): List<InlayInfoDetail> {
val result = mutableListOf<InlayInfoDetail>()
val iterator = details.iterator()
var builder: StringBuilder? = null
while (iterator.hasNext()) {
when (val next = iterator.next()) {
is TextInlayInfoDetail -> {
builder = builder ?: StringBuilder()
builder.append(next.text)
}
else -> {
builder?.let {
result.add(TextInlayInfoDetail(it.toString()))
builder = null
}
result.add(next)
private fun mergeAdjacentTextInlayInfoDetails(details: List<InlayInfoDetail>): List<InlayInfoDetail> {
val result = mutableListOf<InlayInfoDetail>()
val iterator = details.iterator()
var builder: StringBuilder? = null
while (iterator.hasNext()) {
when (val next = iterator.next()) {
is TextInlayInfoDetail -> {
builder = builder ?: StringBuilder()
builder.append(next.text)
}
else -> {
builder?.let {
result.add(TextInlayInfoDetail(it.toString()))
builder = null
}
result.add(next)
}
}
builder?.let {
result.add(TextInlayInfoDetail(it.toString()))
builder = null
}
return result
}
private fun convert(
details: InlayInfoDetail,
f: PresentationFactory,
project: Project
): InlayPresentation {
val textPresentation = f.smallText(details.text)
val navigationElement = when(details) {
is PsiInlayInfoDetail -> details.element
is TypeInlayInfoDetail -> details.fqName?.run {
project.resolveClass(this)?.navigationElement
}
else -> null
}
val basePresentation = navigationElement?.let {
factory.psiSingleReference(textPresentation, withDebugToString = true) { it }
} ?: textPresentation
return basePresentation
builder?.let {
result.add(TextInlayInfoDetail(it.toString()))
builder = null
}
return result
}
private fun getInlayPresentationForInlayInfoDetail(
details: InlayInfoDetail,
factory: PresentationFactory,
project: Project
): InlayPresentation {
val textPresentation = factory.smallText(details.text)
val navigationElement = when(details) {
is PsiInlayInfoDetail -> details.element
is TypeInlayInfoDetail -> details.fqName?.run {
project.resolveClass(this)?.navigationElement
}
else -> null
}
val basePresentation = navigationElement?.let {
factory.psiSingleReference(textPresentation, withDebugToString = true) { it }
} ?: textPresentation
return basePresentation
}
}