mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
[debugger] IDEA-349254 Initial support for collections
Done: - datagrid view (pagination, sorting, filtering) - support for all inheritors of java.util.List - the first element of the collection specifies the columns (if other elements don't have a field, the cell is empty) To be done: - tests - support more types - variables view on click (may result in producing nested sub-views) - maybe include a variable name in the title GitOrigin-RevId: 41ddf8cc16a9aae6aafc671ce1897584d198a6aa
This commit is contained in:
committed by
intellij-monorepo-bot
parent
4dc61efa3b
commit
7d22b2f36b
+37
@@ -0,0 +1,37 @@
|
||||
// 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.debugger.collections.visualizer
|
||||
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import com.intellij.debugger.ui.tree.ValueDescriptor
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.project.Project
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import javax.swing.JComponent
|
||||
|
||||
interface CollectionVisualizer {
|
||||
fun createComponent(
|
||||
project: Project,
|
||||
baseCollectionClass: String,
|
||||
descriptor: ValueDescriptor,
|
||||
evaluationContext: EvaluationContextImpl,
|
||||
scope: CoroutineScope,
|
||||
): JComponent?
|
||||
|
||||
companion object {
|
||||
private val EP_NAME = ExtensionPointName.create<CollectionVisualizer>("com.intellij.debugger.collectionVisualizer")
|
||||
|
||||
fun createComponent(
|
||||
project: Project,
|
||||
baseCollectionClass: String,
|
||||
valueDescriptor: ValueDescriptor,
|
||||
evaluationContext: EvaluationContextImpl,
|
||||
scope: CoroutineScope
|
||||
): JComponent? {
|
||||
for (visualizer in EP_NAME.extensionList) {
|
||||
val component = visualizer.createComponent(project, baseCollectionClass, valueDescriptor, evaluationContext, scope) ?: continue
|
||||
return component
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
// 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.debugger.collections.visualizer
|
||||
|
||||
import com.intellij.debugger.JavaDebuggerBundle
|
||||
import com.intellij.debugger.engine.DebugProcessListener
|
||||
import com.intellij.debugger.engine.FullValueEvaluatorProvider
|
||||
import com.intellij.debugger.engine.SuspendContext
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.FrameWrapper
|
||||
import com.intellij.platform.util.coroutines.childScope
|
||||
import com.intellij.xdebugger.frame.XFullValueEvaluator
|
||||
import com.intellij.xdebugger.impl.ui.CustomComponentEvaluator
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import java.awt.event.MouseEvent
|
||||
import javax.swing.JComponent
|
||||
|
||||
class CollectionVisualizerEvaluator(private val baseCollectionClass: String) : FullValueEvaluatorProvider {
|
||||
override fun getFullValueEvaluator(evaluationContext: EvaluationContextImpl, valueDescriptor: ValueDescriptorImpl): XFullValueEvaluator? {
|
||||
val presenterName = valueDescriptor.type?.name() ?: "<unknown name>"
|
||||
val scope = evaluationContext.managerThread.coroutineScope.childScope("Collection presentation for $presenterName")
|
||||
|
||||
return object : CustomComponentEvaluator("CoVi") {
|
||||
override fun startEvaluation(callback: XFullValueEvaluationCallback) {
|
||||
callback.evaluated("")
|
||||
}
|
||||
|
||||
override fun createComponent(fullValue: String?): JComponent? {
|
||||
return CollectionVisualizer.createComponent(evaluationContext.project, baseCollectionClass, valueDescriptor, evaluationContext, scope)
|
||||
}
|
||||
|
||||
override fun showValuePopup(event: MouseEvent, project: Project, editor: Editor?, component: JComponent, cancelCallback: Runnable?) {
|
||||
val frame = FrameWrapper(
|
||||
project,
|
||||
dimensionKey = "debugger-collection-visualizer",
|
||||
isDialog = false,
|
||||
title = JavaDebuggerBundle.message("debugger.collection.visualizer.title"),
|
||||
component,
|
||||
// don't cancel the whole scope when the window is closed -- otherwise it wouldn't be possible to reopen
|
||||
scope.childScope("Collection presentation for $presenterName (limited to a window)"),
|
||||
)
|
||||
frame.apply {
|
||||
disposeOnResume(evaluationContext, scope)
|
||||
closeOnEsc()
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FrameWrapper.disposeOnResume(
|
||||
evaluationContext: EvaluationContextImpl,
|
||||
scope: CoroutineScope,
|
||||
) {
|
||||
evaluationContext.debugProcess.addDebugProcessListener(object : DebugProcessListener {
|
||||
override fun resumed(suspendContext: SuspendContext?) {
|
||||
close()
|
||||
scope.cancel()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -556,14 +556,22 @@ public final class DebuggerUtilsImpl extends DebuggerUtilsEx {
|
||||
return evaluationContext.getDebugProcess().invokeMethod(evaluationContext, type, method, Collections.emptyList());
|
||||
}
|
||||
|
||||
public static @Nullable Value invokeObjectMethod(@NotNull EvaluationContext evaluationContext,
|
||||
public static @Nullable Value invokeObjectMethod(@NotNull EvaluationContextImpl evaluationContext,
|
||||
@NotNull ObjectReference value,
|
||||
@NotNull String methodName,
|
||||
@Nullable String signature) throws EvaluateException {
|
||||
return invokeObjectMethod(evaluationContext, value, methodName, signature, Collections.emptyList());
|
||||
}
|
||||
|
||||
public static @Nullable Value invokeObjectMethod(@NotNull EvaluationContextImpl evaluationContext,
|
||||
@NotNull ObjectReference value,
|
||||
@NotNull String methodName,
|
||||
@Nullable String signature,
|
||||
@NotNull List<Value> arguments) throws EvaluateException {
|
||||
ReferenceType type = value.referenceType();
|
||||
Method method = findMethodOrLogError(type, methodName, signature);
|
||||
if (method == null) return null;
|
||||
return evaluationContext.getDebugProcess().invokeMethod(evaluationContext, value, method, Collections.emptyList());
|
||||
return evaluationContext.getDebugProcess().invokeMethod(evaluationContext, value, method, arguments);
|
||||
}
|
||||
|
||||
private static @Nullable Method findMethodOrLogError(ReferenceType type, @NotNull String methodName, @Nullable String signature) {
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.intellij.debugger.settings;
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.debugger.DebuggerContext;
|
||||
import com.intellij.debugger.JavaDebuggerBundle;
|
||||
import com.intellij.debugger.collections.visualizer.CollectionVisualizerEvaluator;
|
||||
import com.intellij.debugger.engine.DebugProcess;
|
||||
import com.intellij.debugger.engine.JavaValuePresentation;
|
||||
import com.intellij.debugger.engine.evaluation.*;
|
||||
@@ -574,6 +575,7 @@ public class NodeRendererSettings implements PersistentStateComponent<Element> {
|
||||
createExpressionArrayChildrenRenderer("toArray()", "!isEmpty()", arrayRenderer));
|
||||
setClassName(CommonClassNames.JAVA_UTIL_LIST);
|
||||
setIsApplicableChecker(type -> DebuggerUtilsAsync.instanceOf(type, getClassName()));
|
||||
setFullValueEvaluator(new CollectionVisualizerEvaluator(getClassName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-1
@@ -29,6 +29,7 @@ import com.sun.jdi.ReferenceType;
|
||||
import com.sun.jdi.Type;
|
||||
import com.sun.jdi.Value;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -112,7 +113,8 @@ public class CompoundReferenceRenderer extends NodeRendererImpl implements FullV
|
||||
return null;
|
||||
}
|
||||
|
||||
void setFullValueEvaluator(FullValueEvaluatorProvider fullValueEvaluatorProvider) {
|
||||
@ApiStatus.Internal
|
||||
public void setFullValueEvaluator(FullValueEvaluatorProvider fullValueEvaluatorProvider) {
|
||||
myFullValueEvaluatorProvider = fullValueEvaluatorProvider;
|
||||
}
|
||||
|
||||
|
||||
@@ -267,6 +267,7 @@ user.renderers.configurable.display.name=Java Type Renderers
|
||||
async.stacktraces.configurable.display.name=Async Stack Traces
|
||||
label.user.renderers.configurable.renderer.name=Renderer name:
|
||||
text.user.renderers.configurable.no.renderers=No renderers
|
||||
debugger.collection.visualizer.title=Collection Presentation
|
||||
button.copy=Copy
|
||||
user.renderers.configurable.button.description.copy=Copy selected renderer
|
||||
threads.export.attribute.label.daemon=daemon
|
||||
|
||||
@@ -314,6 +314,8 @@
|
||||
<extensionPoint qualifiedName="com.intellij.debugger.additionalContextProvider"
|
||||
interface="com.intellij.debugger.engine.evaluation.AdditionalContextProvider" dynamic="true"/>
|
||||
|
||||
<extensionPoint qualifiedName="com.intellij.debugger.collectionVisualizer"
|
||||
interface="com.intellij.debugger.collections.visualizer.CollectionVisualizer" dynamic="true"/>
|
||||
|
||||
<extensionPoint qualifiedName="com.intellij.compiler.inspectionValidator"
|
||||
interface="com.intellij.openapi.compiler.util.InspectionValidator"
|
||||
|
||||
Reference in New Issue
Block a user