IDEA-250429 Simple arrays renderer master
authorEgor Ushakov <egor.ushakov@jetbrains.com>
Thu, 24 Sep 2020 08:42:19 +0000 (11:42 +0300)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Thu, 24 Sep 2020 08:45:30 +0000 (08:45 +0000)
GitOrigin-RevId: 51020582ee841efb31319222e3a5ecd50c9c9e57

java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java
java/debugger/openapi/resources/messages/JavaDebuggerBundle.properties
platform/util/resources/misc/registry.properties

index 99e29286ba707226325a5dddd63e70db6498e2e3..ff77fb39421b70aff26f25919554de9ead48cb9d 100644 (file)
@@ -6,6 +6,7 @@ import com.intellij.debugger.DebuggerManagerEx;
 import com.intellij.debugger.JavaDebuggerBundle;
 import com.intellij.debugger.actions.ArrayAction;
 import com.intellij.debugger.engine.ContextUtil;
 import com.intellij.debugger.JavaDebuggerBundle;
 import com.intellij.debugger.actions.ArrayAction;
 import com.intellij.debugger.engine.ContextUtil;
+import com.intellij.debugger.engine.DebugProcessImpl;
 import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
 import com.intellij.debugger.engine.JavaValue;
 import com.intellij.debugger.engine.evaluation.EvaluateException;
 import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
 import com.intellij.debugger.engine.JavaValue;
 import com.intellij.debugger.engine.evaluation.EvaluateException;
@@ -29,11 +30,11 @@ import com.intellij.openapi.roots.LanguageLevelProjectExtension;
 import com.intellij.openapi.util.DefaultJDOMExternalizer;
 import com.intellij.openapi.util.InvalidDataException;
 import com.intellij.openapi.util.WriteExternalException;
 import com.intellij.openapi.util.DefaultJDOMExternalizer;
 import com.intellij.openapi.util.InvalidDataException;
 import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.pom.java.LanguageLevel;
 import com.intellij.pom.java.LanguageLevel;
-import com.intellij.psi.JavaPsiFacade;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiElementFactory;
-import com.intellij.psi.PsiExpression;
+import com.intellij.psi.*;
+import com.intellij.psi.util.TypeConversionUtil;
 import com.intellij.ui.SimpleTextAttributes;
 import com.intellij.util.IncorrectOperationException;
 import com.intellij.xdebugger.XExpression;
 import com.intellij.ui.SimpleTextAttributes;
 import com.intellij.util.IncorrectOperationException;
 import com.intellij.xdebugger.XExpression;
@@ -43,6 +44,7 @@ import com.intellij.xdebugger.frame.XValueChildrenList;
 import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
 import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
 import com.sun.jdi.*;
 import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
 import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
 import com.sun.jdi.*;
+import one.util.streamex.StreamEx;
 import org.jdom.Element;
 import org.jetbrains.annotations.NonNls;
 
 import org.jdom.Element;
 import org.jetbrains.annotations.NonNls;
 
@@ -91,8 +93,60 @@ public class ArrayRenderer extends NodeRendererImpl{
   }
 
   @Override
   }
 
   @Override
-  public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener) throws EvaluateException {
-    return ClassRenderer.calcLabel(descriptor, evaluationContext);
+  public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener listener)
+    throws EvaluateException {
+    if (!Registry.is("debugger.renderers.arrays") ||
+        OnDemandRenderer.isOnDemandForced((DebugProcessImpl)evaluationContext.getDebugProcess())) {
+      return ClassRenderer.calcLabel(descriptor, evaluationContext);
+    }
+
+    Value value = descriptor.getValue();
+    if (value == null) {
+      return "null";
+    }
+    else if (value instanceof ArrayReference) {
+      ArrayReference arrValue = (ArrayReference)value;
+      String componentTypeName = ((ArrayType)arrValue.type()).componentTypeName();
+      boolean isString = CommonClassNames.JAVA_LANG_STRING.equals(componentTypeName);
+      if (TypeConversionUtil.isPrimitive(componentTypeName) || isString) {
+        CompletableFuture<String> asyncLabel = DebuggerUtilsAsync.length(arrValue)
+          .thenCompose(length -> {
+            if (length > 0) {
+              int shownLength = Math.min(length, isString ? 5 : 10);
+              return DebuggerUtilsAsync.getValues(arrValue, 0, shownLength).thenCompose(values -> {
+                CompletableFuture[] futures = StreamEx.of(values).map(ArrayRenderer::getElementAsString).toArray(CompletableFuture[]::new);
+                return CompletableFuture.allOf(futures).thenApply(__ -> {
+                  StreamEx<Object> strings = StreamEx.of(futures).map(CompletableFuture::join);
+                  int remaining = length - values.size();
+                  if (remaining > 0) {
+                    strings = strings.append(JavaDebuggerBundle.message("message.node.array.elements.more", remaining));
+                  }
+                  return strings.joining(", ", "[", "]");
+                });
+              });
+            }
+            return CompletableFuture.completedFuture("[]");
+          });
+        if (asyncLabel.isDone()) {
+          return asyncLabel.join();
+        }
+        else {
+          asyncLabel.thenAccept(res -> {
+            descriptor.setValueLabel(res);
+            listener.labelChanged();
+          });
+        }
+      }
+      return "";
+    }
+    return JavaDebuggerBundle.message("label.undefined");
+  }
+
+  private static CompletableFuture<String> getElementAsString(Value value) {
+    if (value instanceof StringReference) {
+      return DebuggerUtilsAsync.getStringValue((StringReference)value).thenApply(e -> "\"" + StringUtil.first(e, 15, true) + "\"");
+    }
+    return CompletableFuture.completedFuture(value.toString());
   }
 
   public void setForced(boolean forced) {
   }
 
   public void setForced(boolean forced) {
index b607af5e0ec6e8de53599bb5a500a3e8819619de..b232cf71fad5d3d96d4c2b1ff5cfa34f41f4bd68 100644 (file)
@@ -356,6 +356,7 @@ message.node.debug.info.not.available=Debug info not available
 message.node.local.variables.debug.info.not.available=Variables debug info not available
 message.node.local.variables.not.captured=Local variables are not captured for synthetic, bridge etc. methods
 message.node.local.variables.capture.disabled=Local variables were not captured, you can change it in
 message.node.local.variables.debug.info.not.available=Variables debug info not available
 message.node.local.variables.not.captured=Local variables are not captured for synthetic, bridge etc. methods
 message.node.local.variables.capture.disabled=Local variables were not captured, you can change it in
+message.node.array.elements.more=+{0} more
 message.node.elements.null.hidden=Not showing null elements
 message.node.all.array.elements.null=All elements in range ({0}, {1}) are null
 message.node.all.elements.null=All elements are null
 message.node.elements.null.hidden=Not showing null elements
 message.node.all.array.elements.null=All elements in range ({0}, {1}) are null
 message.node.all.elements.null=All elements are null
index 7304e4fa31092196248b635634020153e74d16b6..6e8aa062fc5f432598efd24d59f7fb69fb5f5c2b 100644 (file)
@@ -419,6 +419,8 @@ debugger.click.disable.breakpoints=false
 debugger.click.disable.breakpoints.description=Single click to disable a breakpoint, middle click to remove
 debugger.renderers.file=true
 debugger.renderers.file.description=Enable file object renderer
 debugger.click.disable.breakpoints.description=Single click to disable a breakpoint, middle click to remove
 debugger.renderers.file=true
 debugger.renderers.file.description=Enable file object renderer
+debugger.renderers.arrays=true
+debugger.renderers.arrays.description=Show first elements for primitive and string arrays  
 debugger.single.smart.step.force=true
 debugger.single.smart.step.force.description=Do force step into on single variant smart step into
 debugger.emulate.method.breakpoints=true
 debugger.single.smart.step.force=true
 debugger.single.smart.step.force.description=Do force step into on single variant smart step into
 debugger.emulate.method.breakpoints=true