From 50996fd44e38fb04eeae521c9063d0dfb16e42b1 Mon Sep 17 00:00:00 2001 From: Nikolay Rykunov Date: Tue, 18 Feb 2025 16:26:14 +0100 Subject: [PATCH] [java-rd] IJPL-176967: Rewrite XValueDescriptor, so it may be extended by plugins GitOrigin-RevId: 9fd606e89cbf0680357a12c5159cc99ec3463914 --- .../actions/FrontendViewTextAction.kt | 7 +- .../intellij/debugger/engine/JavaValue.java | 14 +-- .../intellij.java.debugger.impl.shared.xml | 2 + .../impl/shared/engine/JavaValueDescriptor.kt | 26 +++++ .../debugger/impl/shared/engine/XValueType.kt | 7 -- .../xdebugger/frame/XValueDescriptor.kt | 110 +++++++++++++++--- .../resources/META-INF/xdebugger.xml | 3 + 7 files changed, 131 insertions(+), 38 deletions(-) create mode 100644 java/debugger/shared/src/com/intellij/java/debugger/impl/shared/engine/JavaValueDescriptor.kt delete mode 100644 java/debugger/shared/src/com/intellij/java/debugger/impl/shared/engine/XValueType.kt diff --git a/java/debugger/frontend/src/com/intellij/java/debugger/impl/frontend/actions/FrontendViewTextAction.kt b/java/debugger/frontend/src/com/intellij/java/debugger/impl/frontend/actions/FrontendViewTextAction.kt index eb7658b911bb..7fb1128fde8b 100644 --- a/java/debugger/frontend/src/com/intellij/java/debugger/impl/frontend/actions/FrontendViewTextAction.kt +++ b/java/debugger/frontend/src/com/intellij/java/debugger/impl/frontend/actions/FrontendViewTextAction.kt @@ -2,11 +2,10 @@ package com.intellij.java.debugger.impl.frontend.actions import com.intellij.java.debugger.impl.shared.actions.ViewTextActionBase -import com.intellij.java.debugger.impl.shared.engine.JAVA_VALUE_KIND +import com.intellij.java.debugger.impl.shared.engine.JavaValueDescriptor import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.remoting.ActionRemoteBehaviorSpecification import com.intellij.platform.debugger.impl.frontend.evaluate.quick.FrontendXValue -import com.intellij.xdebugger.frame.XValueType import com.intellij.xdebugger.impl.actions.areFrontendDebuggerActionsEnabled import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl @@ -27,9 +26,9 @@ private class FrontendViewTextAction : ViewTextActionBase(), ActionRemoteBehavio override fun getStringNode(e: AnActionEvent): XValueNodeImpl? { val node = XDebuggerTreeActionBase.getSelectedNodes(e.dataContext).singleOrNull() ?: return null val xValue = node.valueContainer as? FrontendXValue ?: return null - val descriptor = xValue.descriptor ?: return null + val descriptor = (xValue.descriptor as? JavaValueDescriptor) ?: return null - if (xValue.modifier != null && descriptor.kind == JAVA_VALUE_KIND && descriptor.type is XValueType.StringType) { + if (xValue.modifier != null && descriptor.isString) { return node } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java index f9a66f5e04b9..45c7c6cc0385 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -22,6 +22,7 @@ import com.intellij.debugger.ui.impl.watch.*; import com.intellij.debugger.ui.tree.*; import com.intellij.debugger.ui.tree.render.*; import com.intellij.debugger.ui.tree.render.Renderer; +import com.intellij.java.debugger.impl.shared.engine.JavaValueDescriptor; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; @@ -58,7 +59,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; -import static com.intellij.java.debugger.impl.shared.engine.XValueTypeKt.JAVA_VALUE_KIND; +import static com.intellij.java.debugger.impl.shared.engine.JavaValueDescriptorKt.JAVA_VALUE_KIND; public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XValueTextProvider, PinToTopParentValue, PinToTopMemberValue { @@ -513,14 +514,9 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV @Override public @Nullable CompletableFuture getXValueDescriptorAsync() { return myValueDescriptor.getInitFuture().thenApply(ignored -> { - XValueType type; - if (myValueDescriptor.isString()) { - type = XValueType.StringType.INSTANCE; - } - else { - type = XValueType.Unknown.INSTANCE; - } - return new XValueDescriptor(JAVA_VALUE_KIND, type); + return new JavaValueDescriptor( + myValueDescriptor.isString() + ); }); } diff --git a/java/debugger/shared/resources/intellij.java.debugger.impl.shared.xml b/java/debugger/shared/resources/intellij.java.debugger.impl.shared.xml index a111706a75ad..e37f00df1e55 100644 --- a/java/debugger/shared/resources/intellij.java.debugger.impl.shared.xml +++ b/java/debugger/shared/resources/intellij.java.debugger.impl.shared.xml @@ -4,5 +4,7 @@ + diff --git a/java/debugger/shared/src/com/intellij/java/debugger/impl/shared/engine/JavaValueDescriptor.kt b/java/debugger/shared/src/com/intellij/java/debugger/impl/shared/engine/JavaValueDescriptor.kt new file mode 100644 index 000000000000..25a4ae8cd047 --- /dev/null +++ b/java/debugger/shared/src/com/intellij/java/debugger/impl/shared/engine/JavaValueDescriptor.kt @@ -0,0 +1,26 @@ +// 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.java.debugger.impl.shared.engine + +import com.intellij.xdebugger.frame.XValueCustomDescriptorSerializerProvider +import com.intellij.xdebugger.frame.XValueDescriptor +import kotlinx.serialization.Serializable +import kotlinx.serialization.modules.PolymorphicModuleBuilder +import kotlinx.serialization.modules.subclass +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Internal +const val JAVA_VALUE_KIND: String = "JavaValue" + +@ApiStatus.Internal +@Serializable +class JavaValueDescriptor( + val isString: Boolean, +) : XValueDescriptor { + override val kind: String = JAVA_VALUE_KIND +} + +private class JavaValueDescriptorSerializerProvider : XValueCustomDescriptorSerializerProvider { + override fun registerSerializer(builder: PolymorphicModuleBuilder) { + builder.subclass(JavaValueDescriptor::class) + } +} \ No newline at end of file diff --git a/java/debugger/shared/src/com/intellij/java/debugger/impl/shared/engine/XValueType.kt b/java/debugger/shared/src/com/intellij/java/debugger/impl/shared/engine/XValueType.kt deleted file mode 100644 index 281bdff86f6d..000000000000 --- a/java/debugger/shared/src/com/intellij/java/debugger/impl/shared/engine/XValueType.kt +++ /dev/null @@ -1,7 +0,0 @@ -// 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.java.debugger.impl.shared.engine - -import org.jetbrains.annotations.ApiStatus - -@ApiStatus.Internal -const val JAVA_VALUE_KIND: String = "JavaValue" \ No newline at end of file diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValueDescriptor.kt b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValueDescriptor.kt index 6ec3de346914..c639aa66ad24 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValueDescriptor.kt +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValueDescriptor.kt @@ -1,16 +1,40 @@ // 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.xdebugger.frame +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.service +import com.intellij.openapi.extensions.ExtensionPointAdapter +import com.intellij.openapi.extensions.ExtensionPointName +import kotlinx.coroutines.CoroutineScope +import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.decodeFromJsonElement +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.modules.PolymorphicModuleBuilder +import kotlinx.serialization.modules.SerializersModule +import kotlinx.serialization.modules.polymorphic import org.jetbrains.annotations.ApiStatus /** - * Provides additional information about XValue which can be used by UI and actions. + * Provides additional information about XValue which can be used by UI and actions on the Frontend. * + * Internal plugins may extend this interface providing custom implementation, but they should be serializable. + * Also, it is required to provide serializer for the implementation using + * [com.intellij.xdebugger.frame.XValueCustomDescriptorSerializerProvider]. + * Otherwise, the default implementation will be used during a serialization/deserialization process. + * + * + * @see createXValueDescriptor + * @see XValueCustomDescriptorSerializerProvider */ @ApiStatus.Internal -@Serializable -data class XValueDescriptor( +@Serializable(with = XValueDescriptorSerializer::class) +interface XValueDescriptor { /** * [kind] is used to differentiate various implementations of XValue by their type instead of using `instanceOf` on [XValue]. * Examples of possible kinds: "JavaValue", "PhpValue", "RubyValue" @@ -19,25 +43,75 @@ data class XValueDescriptor( * which makes `instanceOf` comparisons of XValue impossible, this property provides a way to * differentiate between various types of XValue on the frontend. */ - val kind: String, + val kind: String +} - /** - * [XValue] type (see instances of the [XValueType]). - * Typically, the client may use the type to check the availability of some action or show XValue differently in UI. - */ - val type: XValueType, -) +// TODO: should be called just XValueDescriptor, but it won't be available in Java then +@ApiStatus.Internal +fun createXValueDescriptor(kind: String): XValueDescriptor { + return XValueDescriptorImpl(kind) +} @ApiStatus.Internal +interface XValueCustomDescriptorSerializerProvider { + companion object { + internal val EP_NAME = ExtensionPointName("com.intellij.xdebugger.xValueCustomDescriptorSerializerProvider") + } + + fun registerSerializer(builder: PolymorphicModuleBuilder) +} + @Serializable -sealed interface XValueType { - // TODO: add other types of XValue - @Serializable - data object StringType : XValueType +private data class XValueDescriptorImpl(override val kind: String) : XValueDescriptor - @Serializable - data class Other(val rawType: String) : XValueType - @Serializable - data object Unknown : XValueType +private object XValueDescriptorSerializer : KSerializer { + override val descriptor: SerialDescriptor = JsonElement.serializer().descriptor + + override fun serialize(encoder: Encoder, value: XValueDescriptor) { + val json = service().json + val element = json.encodeToJsonElement(value) + encoder.encodeSerializableValue(JsonElement.serializer(), element) + } + + override fun deserialize(decoder: Decoder): XValueDescriptor { + val json = service().json + val element = decoder.decodeSerializableValue(JsonElement.serializer()) + return json.decodeFromJsonElement(element) + } +} + +@Service +private class XValueDescriptorJsonProvider(cs: CoroutineScope) { + @Volatile + var json = Json { + ignoreUnknownKeys = true + encodeDefaults = true + } + + init { + updateJson() + XValueCustomDescriptorSerializerProvider.EP_NAME.addExtensionPointListener(cs, object : ExtensionPointAdapter() { + override fun extensionListChanged() { + updateJson() + } + }) + } + + private fun updateJson() { + json = Json { + ignoreUnknownKeys = true + encodeDefaults = true + serializersModule = SerializersModule { + polymorphic(XValueDescriptor::class) { + for (provider in XValueCustomDescriptorSerializerProvider.EP_NAME.extensionList) { + provider.registerSerializer(this) + } + defaultDeserializer { + XValueDescriptorImpl.serializer() + } + } + } + } + } } \ No newline at end of file diff --git a/platform/xdebugger-impl/resources/META-INF/xdebugger.xml b/platform/xdebugger-impl/resources/META-INF/xdebugger.xml index cc031629fce3..3596b070db88 100644 --- a/platform/xdebugger-impl/resources/META-INF/xdebugger.xml +++ b/platform/xdebugger-impl/resources/META-INF/xdebugger.xml @@ -28,6 +28,9 @@ + +