[debugger-rd] IJPL-160146: Don't use entities for FullValueEvaluator, instead attach it to XValueEntity

GitOrigin-RevId: 6c239f959b2eceac4a36a2d0a09de530d51d8b08
This commit is contained in:
Nikolay Rykunov
2025-02-05 20:50:33 +00:00
committed by intellij-monorepo-bot
parent 99af4dc6fa
commit 469010a42d
7 changed files with 71 additions and 52 deletions
@@ -61,41 +61,6 @@ internal class BackendXDebuggerEvaluatorApi : XDebuggerEvaluatorApi {
}
}
override suspend fun evaluateFullValue(fullValueEvaluatorId: XFullValueEvaluatorId): Deferred<XFullValueEvaluatorResult> {
val xFullValueEvaluator = fullValueEvaluatorId.eid.findValueEntity<XFullValueEvaluator>()?.value
?: return CompletableDeferred(XFullValueEvaluatorResult.EvaluationError(XDebuggerBundle.message("xdebugger.evaluate.full.value.evaluator.not.available")))
val result = CompletableDeferred<XFullValueEvaluatorResult>()
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,
@@ -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<XFullValueEvaluatorResult> {
val xFullValueEvaluator = entity(XValueEntity.XValueId, xValueId)?.fullValueEvaluator
?: return CompletableDeferred(XFullValueEvaluatorResult.EvaluationError(XDebuggerBundle.message("xdebugger.evaluate.full.value.evaluator.not.available")))
val result = CompletableDeferred<XFullValueEvaluatorResult>()
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<XValueAdvancedPresentationPart>()
@@ -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)
@@ -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) {
@@ -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>(
XValueEntity::class.java.name,
"com.intellij.xdebugger.impl.rhizome",
@@ -120,6 +124,7 @@ data class XValueEntity(override val eid: EID) : Entity {
val XValueAttribute: Required<XValue> = requiredTransient("xValue")
val SessionEntity: Required<XDebugSessionEntity> = requiredRef("sessionEntity", RefFlags.CASCADE_DELETE_BY)
val ParentXValue: Optional<XValueEntity> = optionalRef<XValueEntity>("parentXValue", RefFlags.CASCADE_DELETE_BY)
val FullValueEvaluator: Optional<XFullValueEvaluator> = optionalTransient("fullValueEvaluator")
val Marker: Optional<XValueMarkerDto> = optionalTransient("marker")
}
}
@@ -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<Unit> {
suspend fun evaluateInDocument(evaluatorId: XDebuggerEvaluatorId, documentId: DocumentId, offset: Int, type: ValueHintType): Deferred<XEvaluationResult>
suspend fun evaluateFullValue(fullValueEvaluatorId: XFullValueEvaluatorId): Deferred<XFullValueEvaluatorResult>
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 {
@@ -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<Unit> {
suspend fun disposeXValue(xValueId: XValueId)
suspend fun evaluateFullValue(xValueId: XValueId): Deferred<XFullValueEvaluatorResult>
companion object {
@JvmStatic
suspend fun getInstance(): XValueApi {