@Override
    public void renderValue(@NotNull XValueTextRenderer renderer, @Nullable XValueNodeImpl node) {
      boolean compact = node != null;
      if (myError != null) {
        if (myValue.endsWith(myError)) {
          renderer.renderValue(myValue.substring(0, myValue.length() - myError.length()));
        }
        renderer.renderError(myError);
      } else {
        if (compact && node.getValueContainer() instanceof JavaValue) {
          final JavaValue container = (JavaValue) node.getValueContainer();

          if (container.getDescriptor().isArray()) {
            final ArrayReference value = (ArrayReference) container.getDescriptor().getValue();
            final ArrayType type = (ArrayType) container.getDescriptor().getType();
            if (type != null) {
              final String typeName = type.componentTypeName();
              if (TypeConversionUtil.isPrimitive(typeName)
                  || CommonClassNames.JAVA_LANG_STRING.equals(typeName)) {
                int size = value.length();
                int max =
                    Math.min(size, CommonClassNames.JAVA_LANG_STRING.equals(typeName) ? 5 : 10);
                // TODO [eu]: this is a quick fix for IDEA-136606, need to move this away from
                // EDT!!!
                final List<Value> values = value.getValues(0, max);
                int i = 0;
                final List<String> vals = new ArrayList<String>(max);
                while (i < values.size()) {
                  vals.add(StringUtil.first(values.get(i).toString(), 15, true));
                  i++;
                }
                String more = "";
                if (vals.size() < size) {
                  more = ", + " + (size - vals.size()) + " more";
                }

                renderer.renderValue("{" + StringUtil.join(vals, ", ") + more + "}");
                return;
              }
            }
          }
        }

        String value = myValue;
        if (myValueDescriptor.isString()) {
          renderer.renderStringValue(myValue, "\"\\", XValueNode.MAX_VALUE_LENGTH);
          return;
        } else if (myValueDescriptor.getLastRenderer() instanceof ToStringRenderer
            || myValueDescriptor.getLastRenderer() instanceof ToStringBasedRenderer) {
          value = StringUtil.wrapWithDoubleQuote(truncateToMaxLength(myValue));
        } else if (myValueDescriptor.getLastRenderer() instanceof CompoundReferenceRenderer) {
          value = truncateToMaxLength(myValue);
        }
        renderer.renderValue(value);
      }
    }
 @Override
 public void actionPerformed(final AnActionEvent e) {
   XValueNodeImpl node = getSelectedNode(e.getDataContext());
   if (node != null) {
     String nodeName = node.getName();
     if (nodeName != null) {
       perform(node, nodeName, e);
     }
   }
 }
 @Nullable
 private static NodeInfo createNode(final XDebuggerTreeNode node, boolean selected) {
   if (node instanceof XValueNodeImpl) {
     XValueNodeImpl valueNode = (XValueNodeImpl) node;
     if (valueNode.isComputed()) {
       return new NodeInfo(valueNode.getName(), valueNode.getValue(), selected);
     }
   }
   return null;
 }
 @Override
 public void drop(final DnDEvent aEvent) {
   Object object = aEvent.getAttachedObject();
   if (object instanceof XValueNodeImpl[]) {
     final XValueNodeImpl[] nodes = (XValueNodeImpl[]) object;
     for (XValueNodeImpl node : nodes) {
       String expression = node.getValueContainer().getEvaluationExpression();
       if (expression != null) {
         addWatchExpression(expression, -1, false);
       }
     }
   } else if (object instanceof EventInfo) {
     String text = ((EventInfo) object).getTextForFlavor(DataFlavor.stringFlavor);
     if (text != null) {
       addWatchExpression(text, -1, false);
     }
   }
 }
  public static void editNew(@NotNull XValueNodeImpl parentNode) {
    ValueDescriptorImpl descriptor = ((JavaValue) parentNode.getValueContainer()).getDescriptor();
    EnumerationChildrenRenderer renderer = EnumerationChildrenRenderer.getCurrent(descriptor);
    XDebuggerTreeNode newNode = parentNode.addTemporaryEditorNode();
    DebuggerUIUtil.invokeLater(
        () ->
            new CustomFieldInplaceEditor(newNode, null, renderer) {
              @Override
              public void cancelEditing() {
                super.cancelEditing();
                parentNode.removeTemporaryEditorNode(newNode);
              }

              @Override
              protected List<Pair<String, TextWithImports>> getRendererChildren() {
                if (myRenderer != null) {
                  return myRenderer.getChildren();
                }
                String name = getTypeName(descriptor);
                EnumerationChildrenRenderer enumerationChildrenRenderer =
                    new EnumerationChildrenRenderer();
                enumerationChildrenRenderer.setAppendDefaultChildren(true);

                Renderer lastRenderer = descriptor.getLastRenderer();
                if (lastRenderer instanceof CompoundNodeRenderer
                    && !(((CompoundNodeRenderer) lastRenderer).getChildrenRenderer()
                        instanceof ExpressionChildrenRenderer)) {
                  ((CompoundNodeRenderer) lastRenderer)
                      .setChildrenRenderer(enumerationChildrenRenderer);
                } else {
                  NodeRenderer renderer =
                      NodeRendererSettings.getInstance()
                          .createCompoundTypeRenderer(
                              name, name, null, enumerationChildrenRenderer);
                  renderer.setEnabled(true);
                  NodeRendererSettings.getInstance().getCustomRenderers().addRenderer(renderer);
                  NodeRendererSettings.getInstance().fireRenderersChanged();
                }
                return enumerationChildrenRenderer.getChildren();
              }
            }.show());
  }
 public void reBuild(final XValueNodeImpl node) {
   DebuggerManagerThreadImpl.assertIsManagerThread();
   myCurrentChildrenStart = 0;
   node.getTree()
       .getLaterInvocator()
       .offer(
           new Runnable() {
             @Override
             public void run() {
               node.clearChildren();
               computePresentation(node, XValuePlace.TREE);
             }
           });
 }
 @Nullable
 public static XValue getSelectedValue(@NotNull DataContext dataContext) {
   XValueNodeImpl node = getSelectedNode(dataContext);
   return node != null ? node.getValueContainer() : null;
 }
 protected boolean isEnabled(final @NotNull XValueNodeImpl node, @NotNull AnActionEvent e) {
   return node.getName() != null;
 }
  @Override
  public Collection<LineExtensionInfo> getLineExtensions(
      @NotNull Project project, @NotNull VirtualFile file, int lineNumber) {
    if (!Registry.is("ide.debugger.inline")) {
      return null;
    }

    final Map<Pair<VirtualFile, Integer>, Set<XValueNodeImpl>> map =
        project.getUserData(XVariablesView.DEBUG_VARIABLES);
    final Map<VirtualFile, Long> timestamps =
        project.getUserData(XVariablesView.DEBUG_VARIABLES_TIMESTAMPS);
    final Document doc = FileDocumentManager.getInstance().getDocument(file);

    if (map == null || timestamps == null || doc == null) {
      return null;
    }

    Map<Variable, VariableValue> oldValues = project.getUserData(CACHE);
    if (oldValues == null) {
      oldValues = new HashMap<Variable, VariableValue>();
      project.putUserData(CACHE, oldValues);
    }
    final Long timestamp = timestamps.get(file);
    if (timestamp == null || timestamp < doc.getModificationStamp()) {
      return null;
    }
    Set<XValueNodeImpl> values = map.get(Pair.create(file, lineNumber));
    if (values != null && !values.isEmpty()) {
      ArrayList<LineExtensionInfo> result = new ArrayList<LineExtensionInfo>();
      for (XValueNodeImpl value : values) {
        SimpleColoredText text = new SimpleColoredText();
        XValueTextRendererImpl renderer = new XValueTextRendererImpl(text);
        final XValuePresentation presentation = value.getValuePresentation();
        if (presentation == null) continue;
        try {
          if (presentation instanceof XValueCompactPresentation) {
            ((XValueCompactPresentation) presentation).renderValue(renderer, value);
          } else {
            presentation.renderValue(renderer);
          }
        } catch (Exception e) {
          continue;
        }
        final Color color = getForeground();
        final String name = value.getName();
        result.add(new LineExtensionInfo("  " + name + ": ", color, null, null, Font.PLAIN));

        Variable var = new Variable(name, lineNumber);
        VariableValue variableValue = oldValues.get(var);
        if (variableValue == null) {
          variableValue = new VariableValue(text.toString(), null, value.hashCode());
          oldValues.put(var, variableValue);
        }
        if (variableValue.valueNodeHashCode != value.hashCode()) {
          variableValue.old = variableValue.actual;
          variableValue.actual = text.toString();
          variableValue.valueNodeHashCode = value.hashCode();
        }

        if (!variableValue.isChanged()) {
          for (String s : text.getTexts()) {
            result.add(new LineExtensionInfo(s, color, null, null, Font.PLAIN));
          }
        } else {
          variableValue.produceChangedParts(result);
        }
      }
      return result;
    }

    return null;
  }