diff --git a/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXDebuggerEvaluatorApi.kt b/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXDebuggerEvaluatorApi.kt index d56b3ff823b9..564bf45a97e9 100644 --- a/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXDebuggerEvaluatorApi.kt +++ b/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXDebuggerEvaluatorApi.kt @@ -61,41 +61,6 @@ internal class BackendXDebuggerEvaluatorApi : XDebuggerEvaluatorApi { } } - override suspend fun evaluateFullValue(fullValueEvaluatorId: XFullValueEvaluatorId): Deferred { - val xFullValueEvaluator = fullValueEvaluatorId.eid.findValueEntity()?.value - ?: return CompletableDeferred(XFullValueEvaluatorResult.EvaluationError(XDebuggerBundle.message("xdebugger.evaluate.full.value.evaluator.not.available"))) - - val result = CompletableDeferred() - var isObsolete = false - - val callback = object : XFullValueEvaluationCallback, Obsolescent { - override fun isObsolete(): Boolean { - return isObsolete - } - - override fun evaluated(fullValue: String) { - result.complete(XFullValueEvaluatorResult.Evaluated(fullValue)) - } - - override fun evaluated(fullValue: String, font: Font?) { - // TODO[IJPL-160146]: support Font? - result.complete(XFullValueEvaluatorResult.Evaluated(fullValue)) - } - - override fun errorOccurred(errorMessage: @NlsContexts.DialogMessage String) { - result.complete(XFullValueEvaluatorResult.EvaluationError(errorMessage)) - } - } - - result.invokeOnCompletion { - isObsolete = true - } - - xFullValueEvaluator.startEvaluation(callback) - - return result - } - private suspend fun evaluate( evaluatorId: XDebuggerEvaluatorId, evaluateFun: suspend (XDebuggerEvaluator, XEvaluationCallback) -> Unit, diff --git a/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXValueApi.kt b/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXValueApi.kt index 41e7cee3ef15..72c28de276bb 100644 --- a/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXValueApi.kt +++ b/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXValueApi.kt @@ -3,11 +3,14 @@ package com.intellij.platform.debugger.impl.backend import com.intellij.ide.ui.icons.rpcId import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.util.NlsContexts import com.intellij.openapi.util.NlsSafe -import com.intellij.platform.kernel.backend.newValueEntity import com.intellij.platform.util.coroutines.childScope import com.intellij.ui.SimpleTextAttributes +import com.intellij.xdebugger.Obsolescent +import com.intellij.xdebugger.XDebuggerBundle import com.intellij.xdebugger.frame.* +import com.intellij.xdebugger.frame.XFullValueEvaluator.XFullValueEvaluationCallback import com.intellij.xdebugger.frame.presentation.XValuePresentation import com.intellij.xdebugger.frame.presentation.XValuePresentation.XValueTextRenderer import com.intellij.xdebugger.impl.rhizome.XValueEntity @@ -24,6 +27,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.emptyFlow import org.jetbrains.annotations.NonNls +import java.awt.Font import javax.swing.Icon internal class BackendXValueApi : XValueApi { @@ -61,14 +65,17 @@ internal class BackendXValueApi : XValueApi { return } + // TODO[IJPL-160146]: data race with multiple setFullValueEvaluator calls channelCs.launch { - // TODO[IJPL-160146]: dispose full value evaluator - val fullValueEvaluatorEntity = newValueEntity(fullValueEvaluator) + change { + xValueEntity.update { + it[XValueEntity.FullValueEvaluator] = fullValueEvaluator + } + } presentations.trySend( XValuePresentationEvent.SetFullValueEvaluator( XFullValueEvaluatorDto( - XFullValueEvaluatorId(fullValueEvaluatorEntity.id), fullValueEvaluator.linkText, fullValueEvaluator.isEnabled, fullValueEvaluator.isShowValuePopup, @@ -86,7 +93,14 @@ internal class BackendXValueApi : XValueApi { override fun clearFullValueEvaluator() { // TODO[IJPL-160146]: data race with setFullValueEvaluator - presentations.trySend(XValuePresentationEvent.ClearFullValueEvaluator) + channelCs.launch { + change { + xValueEntity.update { + it[XValueEntity.FullValueEvaluator] = null + } + } + presentations.send(XValuePresentationEvent.ClearFullValueEvaluator) + } } } xValue.computePresentation(valueNode, xValuePlace) @@ -177,6 +191,41 @@ internal class BackendXValueApi : XValueApi { } } + override suspend fun evaluateFullValue(xValueId: XValueId): Deferred { + val xFullValueEvaluator = entity(XValueEntity.XValueId, xValueId)?.fullValueEvaluator + ?: return CompletableDeferred(XFullValueEvaluatorResult.EvaluationError(XDebuggerBundle.message("xdebugger.evaluate.full.value.evaluator.not.available"))) + + val result = CompletableDeferred() + var isObsolete = false + + val callback = object : XFullValueEvaluationCallback, Obsolescent { + override fun isObsolete(): Boolean { + return isObsolete + } + + override fun evaluated(fullValue: String) { + result.complete(XFullValueEvaluatorResult.Evaluated(fullValue)) + } + + override fun evaluated(fullValue: String, font: Font?) { + // TODO[IJPL-160146]: support Font? + result.complete(XFullValueEvaluatorResult.Evaluated(fullValue)) + } + + override fun errorOccurred(errorMessage: @NlsContexts.DialogMessage String) { + result.complete(XFullValueEvaluatorResult.EvaluationError(errorMessage)) + } + } + + result.invokeOnCompletion { + isObsolete = true + } + + xFullValueEvaluator.startEvaluation(callback) + + return result + } + private class XValueTextRendererPartsCollector : XValueTextRenderer { private val _parts = mutableListOf() diff --git a/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXFullValueEvaluator.kt b/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXFullValueEvaluator.kt index 555670a479b0..a4b4d312b840 100644 --- a/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXFullValueEvaluator.kt +++ b/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXFullValueEvaluator.kt @@ -4,16 +4,21 @@ package com.intellij.platform.debugger.impl.frontend.evaluate.quick import com.intellij.ide.ui.icons.icon import com.intellij.openapi.application.EDT import com.intellij.xdebugger.frame.XFullValueEvaluator -import com.intellij.xdebugger.impl.rpc.XDebuggerEvaluatorApi import com.intellij.xdebugger.impl.rpc.XFullValueEvaluatorDto import com.intellij.xdebugger.impl.rpc.XFullValueEvaluatorResult +import com.intellij.xdebugger.impl.rpc.XValueApi +import com.intellij.xdebugger.impl.rpc.XValueId import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.jetbrains.annotations.Nls import java.util.function.Supplier -internal class FrontendXFullValueEvaluator(private val xValueCs: CoroutineScope, private val dto: XFullValueEvaluatorDto) : XFullValueEvaluator() { +internal class FrontendXFullValueEvaluator( + private val xValueCs: CoroutineScope, + private val xValueId: XValueId, + private val dto: XFullValueEvaluatorDto, +) : XFullValueEvaluator() { private val linkAttributes = dto.attributes?.let { LinkAttributes(it.tooltipText, it.shortcut?.let { shortcut -> Supplier { shortcut } }, it.linkIcon?.icon()) } @@ -50,7 +55,7 @@ internal class FrontendXFullValueEvaluator(private val xValueCs: CoroutineScope, override fun startEvaluation(callback: XFullValueEvaluationCallback) { callback.childCoroutineScope(parentScope = xValueCs, "XFullValueEvaluationCallback").launch(Dispatchers.EDT) { - val result = XDebuggerEvaluatorApi.getInstance().evaluateFullValue(dto.xFullValueEvaluatorId).await() + val result = XValueApi.getInstance().evaluateFullValue(xValueId).await() when (result) { is XFullValueEvaluatorResult.Evaluated -> { callback.evaluated(result.fullValue) diff --git a/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXValue.kt b/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXValue.kt index 269f4aef84f0..3375242fe2a6 100644 --- a/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXValue.kt +++ b/platform/xdebugger-impl/frontend/src/com/intellij/platform/debugger/impl/frontend/evaluate/quick/FrontendXValue.kt @@ -100,7 +100,7 @@ internal class FrontendXValue( node.setPresentation(presentationEvent.icon?.icon(), FrontendXValuePresentation(presentationEvent), presentationEvent.hasChildren) } is XValuePresentationEvent.SetFullValueEvaluator -> { - node.setFullValueEvaluator(FrontendXFullValueEvaluator(cs, presentationEvent.fullValueEvaluatorDto)) + node.setFullValueEvaluator(FrontendXFullValueEvaluator(cs, xValueDto.id, presentationEvent.fullValueEvaluatorDto)) } XValuePresentationEvent.ClearFullValueEvaluator -> { if (node is XValueNodeEx) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rhizome/XDebuggerEntities.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rhizome/XDebuggerEntities.kt index 450bcea5a69d..e7fb897ad48b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rhizome/XDebuggerEntities.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rhizome/XDebuggerEntities.kt @@ -5,7 +5,9 @@ import com.intellij.platform.kernel.EntityTypeProvider import com.intellij.platform.project.ProjectEntity import com.intellij.xdebugger.XDebugSession import com.intellij.xdebugger.evaluation.XDebuggerEvaluator +import com.intellij.xdebugger.frame.XFullValueEvaluator import com.intellij.xdebugger.frame.XValue +import com.intellij.xdebugger.impl.rhizome.XValueEntity.Companion.XValueId import com.intellij.xdebugger.impl.rpc.XDebugSessionId import com.intellij.xdebugger.impl.rpc.XDebuggerEvaluatorId import com.intellij.xdebugger.impl.rpc.XValueId @@ -111,6 +113,8 @@ data class XValueEntity(override val eid: EID) : Entity { val marker: XValueMarkerDto? by Marker + val fullValueEvaluator: XFullValueEvaluator? by FullValueEvaluator + companion object : EntityType( XValueEntity::class.java.name, "com.intellij.xdebugger.impl.rhizome", @@ -120,6 +124,7 @@ data class XValueEntity(override val eid: EID) : Entity { val XValueAttribute: Required = requiredTransient("xValue") val SessionEntity: Required = requiredRef("sessionEntity", RefFlags.CASCADE_DELETE_BY) val ParentXValue: Optional = optionalRef("parentXValue", RefFlags.CASCADE_DELETE_BY) + val FullValueEvaluator: Optional = optionalTransient("fullValueEvaluator") val Marker: Optional = optionalTransient("marker") } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/XDebuggerEvaluatorApi.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/XDebuggerEvaluatorApi.kt index 45e9a8301102..b142c09cf039 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/XDebuggerEvaluatorApi.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/XDebuggerEvaluatorApi.kt @@ -11,7 +11,6 @@ import com.intellij.ui.SimpleTextAttributes import com.intellij.xdebugger.frame.XDebuggerTreeNodeHyperlink import com.intellij.xdebugger.impl.evaluate.quick.common.ValueHintType import com.intellij.xdebugger.impl.rhizome.XValueMarkerDto -import com.jetbrains.rhizomedb.EID import fleet.rpc.RemoteApi import fleet.rpc.Rpc import fleet.rpc.core.DeferredSerializer @@ -34,8 +33,6 @@ interface XDebuggerEvaluatorApi : RemoteApi { suspend fun evaluateInDocument(evaluatorId: XDebuggerEvaluatorId, documentId: DocumentId, offset: Int, type: ValueHintType): Deferred - suspend fun evaluateFullValue(fullValueEvaluatorId: XFullValueEvaluatorId): Deferred - companion object { @JvmStatic suspend fun getInstance(): XDebuggerEvaluatorApi { @@ -148,7 +145,6 @@ sealed interface XValuePresentationEvent { @ApiStatus.Internal @Serializable data class XFullValueEvaluatorDto( - @JvmField val xFullValueEvaluatorId: XFullValueEvaluatorId, @NlsSafe @JvmField val linkText: String, @JvmField val isEnabled: Boolean, @JvmField val isShowValuePopup: Boolean, @@ -163,10 +159,6 @@ data class XFullValueEvaluatorDto( ) } -@ApiStatus.Internal -@Serializable -data class XFullValueEvaluatorId(val eid: EID) - @ApiStatus.Internal @Serializable sealed interface XFullValueEvaluatorResult { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/XValueApi.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/XValueApi.kt index 8b3855e35a47..3f9a1a6d625b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/XValueApi.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/XValueApi.kt @@ -6,6 +6,7 @@ import com.intellij.xdebugger.frame.XValuePlace import fleet.rpc.RemoteApi import fleet.rpc.Rpc import fleet.rpc.remoteApiDescriptor +import kotlinx.coroutines.Deferred import kotlinx.coroutines.flow.Flow import org.jetbrains.annotations.ApiStatus @@ -18,6 +19,8 @@ interface XValueApi : RemoteApi { suspend fun disposeXValue(xValueId: XValueId) + suspend fun evaluateFullValue(xValueId: XValueId): Deferred + companion object { @JvmStatic suspend fun getInstance(): XValueApi {