[declarative-inlays] IJPL-164727 make InlayDataExternalizer abstract and repurpose it for rem-dev

GitOrigin-RevId: 07e417ea3f59ca965ac3679892fd91c568703794
This commit is contained in:
Vojtech Balik
2025-02-22 18:10:11 +00:00
committed by intellij-monorepo-bot
parent 31d71a40b0
commit 06b0f857b5
4 changed files with 212 additions and 82 deletions
@@ -1,25 +1,90 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.daemon.impl
import com.intellij.codeInsight.hints.declarative.impl.InlayData
import com.intellij.codeInsight.hints.declarative.impl.InlayDataExternalizer
import com.intellij.codeInsight.hints.declarative.*
import com.intellij.codeInsight.hints.declarative.impl.*
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.impl.zombie.LimbedNecromancy
import com.intellij.openapi.editor.impl.zombie.LimbedZombie
import java.io.*
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.PsiFile
import com.intellij.util.io.DataInputOutputUtil.readINT
import com.intellij.util.io.DataInputOutputUtil.writeINT
import com.intellij.util.io.IOUtil.readUTF
import com.intellij.util.io.IOUtil.writeUTF
import java.io.DataInput
import java.io.DataOutput
internal class DeclarativeHintsZombie(limbs: List<InlayData>) : LimbedZombie<InlayData>(limbs)
internal object DeclarativeHintsNecromancy : LimbedNecromancy<DeclarativeHintsZombie, InlayData>(InlayDataExternalizer.serdeVersion()) {
internal object DeclarativeHintsNecromancy
: LimbedNecromancy<DeclarativeHintsZombie, InlayData>(NecromancyInlayDataExternalizer.serdeVersion()) {
override fun buryLimb(grave: DataOutput, limb: InlayData) {
InlayDataExternalizer.save(grave, limb)
NecromancyInlayDataExternalizer.save(grave, limb)
}
override fun exhumeLimb(grave: DataInput): InlayData {
return InlayDataExternalizer.read(grave)
return NecromancyInlayDataExternalizer.read(grave)
}
override fun formZombie(limbs: List<InlayData>): DeclarativeHintsZombie {
return DeclarativeHintsZombie(limbs)
}
}
private object NecromancyPresentationTreeExternalizer : PresentationTreeExternalizer() {
private const val SERDE_VERSION = 0
override fun serdeVersion(): Int = SERDE_VERSION + super.serdeVersion()
override fun writeInlayActionPayload(output: DataOutput, actionPayload: InlayActionPayload) {
when(actionPayload) {
is StringInlayActionPayload -> {
writeINT(output, 0)
writeUTF(output, actionPayload.text)
}
is PsiPointerInlayActionPayload -> {
writeINT(output, 1)
}
is SymbolPointerInlayActionPayload -> {
writeINT(output, 2)
}
}
}
override fun readInlayActionPayload(input: DataInput): InlayActionPayload {
val type = readINT(input)
return when (type) {
0 -> StringInlayActionPayload(readUTF(input))
1 -> PsiPointerInlayActionPayload(ZombieSmartPointer())
2 -> SymbolPointerInlayActionPayload(ZombieSymbolPointer())
else -> throw IllegalStateException("unknown inlay action payload type: $type")
}
}
override fun decorateContent(content: String): String = decorateIfDebug(content)
private fun decorateIfDebug(content: String): String {
return if (Registry.`is`("cache.markup.debug")) {
"$content?"
} else {
content
}
}
}
private object NecromancyInlayDataExternalizer : InlayDataExternalizer(NecromancyPresentationTreeExternalizer) {
private const val SERDE_VERSION = 0
override fun serdeVersion(): Int = SERDE_VERSION + super.serdeVersion()
override fun writeProviderClass(output: DataOutput, providerClass: Class<*>) {}
override fun readProviderClass(input: DataInput): Class<*> = ZombieInlayHintsProvider::class.java
}
private class ZombieInlayHintsProvider : InlayHintsProvider {
override fun createCollector(file: PsiFile, editor: Editor): InlayHintsCollector? {
throw UnsupportedOperationException("Zombie provider does not support inlay collecting")
}
}
@@ -82,13 +82,16 @@ data class InlayData(
}
}
internal object InlayDataExternalizer : DataExternalizer<InlayData> {
// increment on format changed
private const val SERDE_VERSION = 8
@ApiStatus.Internal
abstract class InlayDataExternalizer(
private val treeExternalizer: PresentationTreeExternalizer
) : DataExternalizer<InlayData> {
companion object {
// increment on format changed
private const val SERDE_VERSION = 9
}
private val treeExternalizer: PresentationTreeExternalizer = PresentationTreeExternalizer
fun serdeVersion(): Int = SERDE_VERSION + treeExternalizer.serdeVersion()
open fun serdeVersion(): Int = SERDE_VERSION + treeExternalizer.serdeVersion()
override fun save(output: DataOutput, inlayData: InlayData) {
writePosition(output, inlayData.position)
@@ -96,8 +99,9 @@ internal object InlayDataExternalizer : DataExternalizer<InlayData> {
writeHintFormat(output, inlayData.hintFormat)
treeExternalizer.save(output, inlayData.tree)
writeUTF(output, inlayData.providerId)
output.writeBoolean(inlayData.disabled)
writeDisabled(output, inlayData.disabled)
writePayloads(output, inlayData.payloads)
writeProviderClass(output, inlayData.providerClass)
writeSourceId(output, inlayData.sourceId)
}
@@ -107,9 +111,9 @@ internal object InlayDataExternalizer : DataExternalizer<InlayData> {
val hintFormat: HintFormat = readHintFormat(input)
val tree: TinyTree<Any?> = treeExternalizer.read(input)
val providerId: String = readUTF(input)
val disabled: Boolean = input.readBoolean()
val disabled: Boolean = readDisabled(input)
val payloads: List<InlayPayload>? = readPayloads(input)
val providerClass: Class<*> = ZombieInlayHintsProvider::class.java
val providerClass: Class<*> = readProviderClass(input)
val sourceId: String = readSourceId(input)
return InlayData(position, tooltip, hintFormat, tree, providerId, disabled, payloads, providerClass, sourceId)
}
@@ -138,28 +142,33 @@ internal object InlayDataExternalizer : DataExternalizer<InlayData> {
private fun readPosition(input: DataInput): InlayPosition {
val type = readINT(input)
if (type == 0) {
val offset = readINT(input)
val related = input.readBoolean()
val priority = readINT(input)
return InlineInlayPosition(offset, related, priority)
} else if (type == 1) {
val line = readINT(input)
val priority = readINT(input)
return EndOfLinePosition(line, priority)
} else if (type == 2) {
val offset = readINT(input)
val verticalPriority = readINT(input)
val priority = readINT(input)
return AboveLineIndentedPosition(offset, verticalPriority, priority)
when (type) {
0 -> {
val offset = readINT(input)
val related = input.readBoolean()
val priority = readINT(input)
return InlineInlayPosition(offset, related, priority)
}
1 -> {
val line = readINT(input)
val priority = readINT(input)
return EndOfLinePosition(line, priority)
}
2 -> {
val offset = readINT(input)
val verticalPriority = readINT(input)
val priority = readINT(input)
return AboveLineIndentedPosition(offset, verticalPriority, priority)
}
else -> throw IllegalStateException("unknown inlay position type: $type")
}
throw IllegalStateException("unknown inlay position type: $type")
}
private fun writeTooltip(output: DataOutput, tooltip: String?) {
if (tooltip == null) {
output.writeBoolean(false)
} else {
}
else {
output.writeBoolean(true)
writeUTF(output, tooltip)
}
@@ -168,7 +177,8 @@ internal object InlayDataExternalizer : DataExternalizer<InlayData> {
private fun readTooltip(input: DataInput): String? {
return if (input.readBoolean()) {
readUTF(input)
} else {
}
else {
null
}
}
@@ -180,16 +190,17 @@ internal object InlayDataExternalizer : DataExternalizer<InlayData> {
}
private fun readHintFormat(input: DataInput): HintFormat {
val hintColorKind= HintColorKind.valueOf(readUTF(input))
val hintFontSize= HintFontSize.valueOf(readUTF(input))
val padding= HintMarginPadding.valueOf(readUTF(input))
val hintColorKind = HintColorKind.valueOf(readUTF(input))
val hintFontSize = HintFontSize.valueOf(readUTF(input))
val padding = HintMarginPadding.valueOf(readUTF(input))
return HintFormat(hintColorKind, hintFontSize, padding)
}
private fun writePayloads(output: DataOutput, payloads: List<InlayPayload>?) {
open fun writePayloads(output: DataOutput, payloads: List<InlayPayload>?) {
if (payloads == null) {
output.writeBoolean(false)
} else {
}
else {
output.writeBoolean(true)
writeINT(output, payloads.size)
for (p in payloads) {
@@ -198,7 +209,7 @@ internal object InlayDataExternalizer : DataExternalizer<InlayData> {
}
}
private fun readPayloads(input: DataInput): List<InlayPayload>? {
open fun readPayloads(input: DataInput): List<InlayPayload>? {
if (input.readBoolean()) {
val payloadCount = readINT(input)
val payloads = ArrayList<InlayPayload>(payloadCount)
@@ -207,7 +218,8 @@ internal object InlayDataExternalizer : DataExternalizer<InlayData> {
payloads.add(inlayPayload)
}
return payloads
} else {
}
else {
return null
}
}
@@ -223,17 +235,23 @@ internal object InlayDataExternalizer : DataExternalizer<InlayData> {
return InlayPayload(payloadName, inlayActionPayload)
}
private fun writeSourceId(output: DataOutput, sourceId: String) {
open fun writeSourceId(output: DataOutput, sourceId: String) {
writeUTF(output, sourceId)
}
private fun readSourceId(input: DataInput): String {
open fun readSourceId(input: DataInput): String {
return readUTF(input)
}
}
private class ZombieInlayHintsProvider : InlayHintsProvider {
override fun createCollector(file: PsiFile, editor: Editor): InlayHintsCollector? {
throw UnsupportedOperationException("Zombie provider does not support inlay collecting")
abstract fun writeProviderClass(output: DataOutput, providerClass: Class<*>)
abstract fun readProviderClass(input: DataInput): Class<*>
fun writeDisabled(output: DataOutput, disabled: Boolean) {
output.writeBoolean(disabled)
}
fun readDisabled(input: DataInput): Boolean {
return input.readBoolean()
}
}
@@ -8,13 +8,17 @@ import com.intellij.util.io.DataInputOutputUtil.readINT
import com.intellij.util.io.DataInputOutputUtil.writeINT
import com.intellij.util.io.IOUtil.readUTF
import com.intellij.util.io.IOUtil.writeUTF
import org.jetbrains.annotations.ApiStatus
import java.io.DataInput
import java.io.DataOutput
internal object PresentationTreeExternalizer : TinyTree.Externalizer<Any?>() {
@ApiStatus.Internal
abstract class PresentationTreeExternalizer : TinyTree.Externalizer<Any?>() {
// increment on format changed
private const val SERDE_VERSION = 1
companion object {
// increment on format changed
private const val SERDE_VERSION = 1
}
override fun serdeVersion(): Int = SERDE_VERSION + super.serdeVersion()
@@ -42,10 +46,10 @@ internal object PresentationTreeExternalizer : TinyTree.Externalizer<Any?>() {
when (type) {
0 -> {
val string = readNullableString(input) ?: return null
return decorateIfDebug(string)
return decorateContent(string)
}
1 -> {
val content = decorateIfDebug(readUTF(input))
val content = decorateContent(readUTF(input))
return ActionWithContent(readInlayActionData(input), content)
}
2 -> {
@@ -72,47 +76,20 @@ internal object PresentationTreeExternalizer : TinyTree.Externalizer<Any?>() {
}
}
private fun writeInlayActionData(output: DataOutput, inlayActionData: InlayActionData) {
open fun writeInlayActionData(output: DataOutput, inlayActionData: InlayActionData) {
writeUTF(output, inlayActionData.handlerId)
writeInlayActionPayload(output, inlayActionData.payload)
}
private fun readInlayActionData(input: DataInput): InlayActionData {
open fun readInlayActionData(input: DataInput): InlayActionData {
val handlerId = readUTF(input)
val payload = readInlayActionPayload(input)
return InlayActionData(payload, handlerId)
}
fun writeInlayActionPayload(output: DataOutput, actionPayload: InlayActionPayload) {
when(actionPayload) {
is StringInlayActionPayload -> {
writeINT(output, 0)
writeUTF(output, actionPayload.text)
}
is PsiPointerInlayActionPayload -> {
writeINT(output, 1)
}
is SymbolPointerInlayActionPayload -> {
writeINT(output, 2)
}
}
}
abstract fun writeInlayActionPayload(output: DataOutput, actionPayload: InlayActionPayload)
fun readInlayActionPayload(input: DataInput): InlayActionPayload {
val type = readINT(input)
return when (type) {
0 -> StringInlayActionPayload(readUTF(input))
1 -> PsiPointerInlayActionPayload(ZombieSmartPointer())
2 -> SymbolPointerInlayActionPayload(ZombieSymbolPointer())
else -> throw IllegalStateException("unknown inlay action payload type: $type")
}
}
abstract fun readInlayActionPayload(input: DataInput): InlayActionPayload
private fun decorateIfDebug(content: String): String {
return if (Registry.`is`("cache.markup.debug")) {
"$content?"
} else {
content
}
}
protected open fun decorateContent(content: String): String = content
}
@@ -0,0 +1,70 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.hints.declarative.impl
import com.intellij.codeInsight.hints.declarative.InlayActionData
import com.intellij.codeInsight.hints.declarative.InlayActionPayload
import com.intellij.codeInsight.hints.declarative.InlayHintsCollector
import com.intellij.codeInsight.hints.declarative.InlayHintsProvider
import com.intellij.codeInsight.hints.declarative.InlayPayload
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiFile
import org.jetbrains.annotations.ApiStatus
import java.io.DataInput
import java.io.DataOutput
@ApiStatus.Internal
object RdInlayDataExternalizer : InlayDataExternalizer(RdPresentationTreeExternalizer) {
override fun writeProviderClass(output: DataOutput, providerClass: Class<*>) {
// do nothing
}
override fun readProviderClass(input: DataInput): Class<*> {
return RdDummyInlayProvider::class.java
}
override fun writeSourceId(output: DataOutput, sourceId: String) {
// do nothing
}
override fun readSourceId(input: DataInput): String {
return RD_INLAY_DATA_SOURCE_ID
}
override fun writePayloads(output: DataOutput, payloads: List<InlayPayload>?) {
// do nothing
}
override fun readPayloads(input: DataInput): List<InlayPayload>? {
return null
}
}
private object RdPresentationTreeExternalizer : PresentationTreeExternalizer() {
override fun writeInlayActionPayload(output: DataOutput, actionPayload: InlayActionPayload) {
error("InlayActionPayload should not be sent to frontend")
}
override fun readInlayActionPayload(input: DataInput): InlayActionPayload {
error("InlayActionPayload should not be read on frontend")
}
override fun readInlayActionData(input: DataInput): InlayActionData {
return INLAY_ACTION_DATA_PLACEHOLDER
}
override fun writeInlayActionData(output: DataOutput, inlayActionData: InlayActionData) {
// do nothing
}
}
private object RdInlayActionPayloadPlaceholder : InlayActionPayload
private val INLAY_ACTION_DATA_PLACEHOLDER = InlayActionData(RdInlayActionPayloadPlaceholder, "rd.placeholder.handler.id")
private object RdDummyInlayProvider : InlayHintsProvider {
override fun createCollector(file: PsiFile, editor: Editor): InlayHintsCollector? {
error("Dummy provider must not be called")
}
}
const val RD_INLAY_DATA_SOURCE_ID: String = "rd.deserialized.inlay.data"